joshuar-go-hass-agent/internal/hass/config.go

139 lines
3.2 KiB
Go

// Copyright (c) 2023 Joshua Rich <joshua.rich@gmail.com>
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
package hass
import (
"bytes"
"context"
"encoding/json"
"fmt"
"sync"
"time"
"github.com/perimeterx/marshmallow"
"github.com/rs/zerolog/log"
)
type HassConfig struct {
rawConfigProps map[string]interface{}
hassConfigProps
mu sync.Mutex
}
type hassConfigProps struct {
Entities map[string]map[string]interface{} `json:"entities"`
UnitSystem struct {
Length string `json:"length"`
Mass string `json:"mass"`
Temperature string `json:"temperature"`
Volume string `json:"volume"`
} `json:"unit_system"`
ConfigDir string `json:"config_dir"`
LocationName string `json:"location_name"`
TimeZone string `json:"time_zone"`
Version string `json:"version"`
Components []string `json:"components"`
WhitelistExternalDirs []string `json:"whitelist_external_dirs"`
Elevation int `json:"elevation"`
Latitude float64 `json:"latitude"`
Longitude float64 `json:"longitude"`
}
func NewHassConfig(ctx context.Context) *HassConfig {
c := &HassConfig{}
c.Refresh(ctx)
c.updater(ctx)
return c
}
func (h *HassConfig) Refresh(ctx context.Context) {
APIRequest(ctx, h)
}
func (h *HassConfig) updater(ctx context.Context) {
ticker := time.NewTicker(time.Minute * 1)
go func() {
for {
select {
case <-ctx.Done():
return
case <-ticker.C:
h.Refresh(ctx)
}
}
}()
}
func (h *HassConfig) GetEntityState(entity string) map[string]interface{} {
h.mu.Lock()
defer h.mu.Unlock()
if v, ok := h.hassConfigProps.Entities[entity]; ok {
return v
}
return nil
}
func (h *HassConfig) IsEntityDisabled(entity string) bool {
h.mu.Lock()
defer h.mu.Unlock()
if v, ok := h.hassConfigProps.Entities[entity]; ok {
return v["disabled"].(bool)
} else {
return false
}
}
// HassConfig implements hass.Request so that it can be sent as a request to HA
// to get its data.
func (h *HassConfig) RequestType() RequestType {
return RequestTypeGetConfig
}
func (h *HassConfig) RequestData() *json.RawMessage {
return nil
}
func (h *HassConfig) ResponseHandler(resp bytes.Buffer) {
if resp.Bytes() == nil {
log.Debug().
Msg("No response returned.")
return
}
h.mu.Lock()
result, err := marshmallow.Unmarshal(resp.Bytes(), &h.hassConfigProps)
if err != nil {
log.Debug().Err(err).
Msg("Couldn't unmarshal Hass config.")
return
}
h.rawConfigProps = result
h.mu.Unlock()
log.Debug().Caller().Msg("Updated stored HA config.")
}
// HassConfig implements config.Config
func (c *HassConfig) Get(property string) (interface{}, error) {
c.mu.Lock()
defer c.mu.Unlock()
if value, ok := c.rawConfigProps[property]; ok {
return value, nil
} else {
return nil, fmt.Errorf("config does not have an option %s", property)
}
}
func (c *HassConfig) Set(property string, value interface{}) error {
log.Debug().Caller().Msg("Hass configuration is not settable.")
return nil
}
func (c *HassConfig) Validate() error {
log.Debug().Caller().Msg("Hass configuration has no validation.")
return nil
}