Nik Afiq 6ea4e84949
All checks were successful
CI / test (push) Successful in 4s
CI / build-ha-gateway (push) Successful in 1m7s
CI / build-discord-bot (push) Successful in 51s
Enhance Discord bot and HA gateway with improved structure and documentation
- Added detailed comments to clarify the purpose of various functions and types in the Discord bot and HA gateway.
- Introduced new methods in the CommandApp for handling light and switch operations, including HandleLightOn, HandleLightOff, HandleLightToggle, and their respective autocomplete functions.
- Updated the HAClient interface to include methods for fetching states and calling services, enhancing the interaction with Home Assistant.
- Improved the structure of entity and light domain models to include additional attributes and clearer documentation.
- Implemented logging enhancements in both the Discord bot and HA gateway to ensure better traceability and context in logs.
- Refactored the configuration loading process to streamline environment variable handling and defaults.
- Stubbed out switch control methods in the gRPC adapter, indicating future implementation plans.
- Enhanced telemetry setup to ensure proper initialization and shutdown procedures for observability.
2026-04-09 06:00:59 +09:00

74 lines
1.8 KiB
Go

package app
import (
"context"
"fmt"
"strings"
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/domain"
"gitea.nik4nao.com/nik/home-services/ha-gateway/internal/core/ports/driven"
)
type EntityApp struct {
ha driven.HAClient
}
// NewEntityApp constructs the entity application service.
func NewEntityApp(ha driven.HAClient) *EntityApp {
return &EntityApp{ha: ha}
}
// GetState loads a single entity state through the HA driven port.
func (a *EntityApp) GetState(ctx context.Context, id domain.EntityID) (*domain.EntityState, error) {
s, err := a.ha.GetState(ctx, string(id))
if err != nil {
return nil, err
}
return haStateToDomain(s), nil
}
// ListStates filters the full Home Assistant state list by explicit IDs and/or domain.
func (a *EntityApp) ListStates(ctx context.Context, ids []domain.EntityID, domainFilter string) ([]*domain.EntityState, error) {
all, err := a.ha.ListStates(ctx)
if err != nil {
return nil, err
}
idSet := make(map[string]struct{}, len(ids))
for _, id := range ids {
idSet[string(id)] = struct{}{}
}
var out []*domain.EntityState
for _, s := range all {
if len(ids) > 0 {
if _, ok := idSet[s.EntityID]; !ok {
continue
}
}
if domainFilter != "" {
if !strings.HasPrefix(s.EntityID, domainFilter+".") {
continue
}
}
out = append(out, haStateToDomain(s))
}
return out, nil
}
// haStateToDomain stringifies raw Home Assistant attributes so the core model
// stays transport-agnostic and easy to serialize over gRPC.
func haStateToDomain(s *driven.HAState) *domain.EntityState {
attrs := make(map[string]string, len(s.Attributes))
for k, v := range s.Attributes {
attrs[k] = fmt.Sprintf("%v", v)
}
return &domain.EntityState{
EntityID: domain.EntityID(s.EntityID),
State: s.State,
Attributes: attrs,
LastChanged: s.LastChanged,
LastUpdated: s.LastUpdated,
}
}