150 lines
4.7 KiB
Go
150 lines
4.7 KiB
Go
// Copyright 2024 Joshua Rich <joshua.rich@gmail.com>.
|
|
// SPDX-License-Identifier: MIT
|
|
|
|
//revive:disable:unused-receiver
|
|
package sensor
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/joshuar/go-hass-agent/internal/hass/sensor/types"
|
|
"github.com/joshuar/go-hass-agent/internal/validation"
|
|
)
|
|
|
|
const (
|
|
StateUnknown = "Unknown"
|
|
|
|
requestTypeRegisterSensor = "register_sensor"
|
|
requestTypeUpdateSensor = "update_sensor_states"
|
|
requestTypeLocation = "update_location"
|
|
)
|
|
|
|
type Request struct {
|
|
Data any `json:"data"`
|
|
RequestType string `json:"type"`
|
|
}
|
|
|
|
type State struct {
|
|
Value any `json:"state" validate:"required"`
|
|
Attributes map[string]any `json:"attributes,omitempty" validate:"omitempty"`
|
|
Icon string `json:"icon,omitempty" validate:"omitempty,startswith=mdi:"`
|
|
ID string `json:"unique_id" validate:"required"`
|
|
EntityType types.SensorType `json:"type" validate:"omitempty"`
|
|
}
|
|
|
|
func (s *State) Validate() error {
|
|
err := validation.Validate.Struct(s)
|
|
if err != nil {
|
|
return fmt.Errorf("sensor state is invalid: %s", validation.ParseValidationErrors(err))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (s *State) RequestBody() any {
|
|
return &Request{
|
|
RequestType: requestTypeUpdateSensor,
|
|
Data: s,
|
|
}
|
|
}
|
|
|
|
//nolint:wrapcheck
|
|
func (s *State) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(&struct {
|
|
State any `json:"state" validate:"required"`
|
|
Attributes map[string]any `json:"attributes,omitempty" validate:"omitempty"`
|
|
Icon string `json:"icon,omitempty" validate:"omitempty,startswith=mdi:"`
|
|
ID string `json:"unique_id" validate:"required"`
|
|
EntityType string `json:"type" validate:"omitempty"`
|
|
}{
|
|
State: s.Value,
|
|
Attributes: s.Attributes,
|
|
Icon: s.Icon,
|
|
ID: s.ID,
|
|
EntityType: s.EntityType.String(),
|
|
})
|
|
}
|
|
|
|
type Entity struct {
|
|
*State
|
|
Name string `json:"name" validate:"required"`
|
|
Units string `json:"unit_of_measurement,omitempty" validate:"omitempty"`
|
|
DeviceClass types.DeviceClass `json:"device_class,omitempty" validate:"omitempty"`
|
|
StateClass types.StateClass `json:"state_class,omitempty" validate:"omitempty"`
|
|
Category types.Category `json:"entity_category,omitempty" validate:"omitempty"`
|
|
}
|
|
|
|
func (e *Entity) Validate() error {
|
|
err := validation.Validate.Struct(e)
|
|
if err != nil {
|
|
return fmt.Errorf("sensor is invalid: %s", validation.ParseValidationErrors(err))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (e *Entity) RequestBody() any {
|
|
return &Request{
|
|
RequestType: requestTypeRegisterSensor,
|
|
Data: e,
|
|
}
|
|
}
|
|
|
|
//nolint:wrapcheck
|
|
func (e *Entity) MarshalJSON() ([]byte, error) {
|
|
return json.Marshal(&struct {
|
|
State any `json:"state" validate:"required"`
|
|
Attributes map[string]any `json:"attributes,omitempty" validate:"omitempty"`
|
|
Icon string `json:"icon,omitempty" validate:"omitempty,startswith=mdi:"`
|
|
ID string `json:"unique_id" validate:"required"`
|
|
EntityType string `json:"type" validate:"omitempty"`
|
|
Name string `json:"name" validate:"required"`
|
|
Units string `json:"unit_of_measurement,omitempty" validate:"omitempty"`
|
|
DeviceClass string `json:"device_class,omitempty" validate:"omitempty"`
|
|
StateClass string `json:"state_class,omitempty" validate:"omitempty"`
|
|
Category string `json:"entity_category,omitempty" validate:"omitempty"`
|
|
}{
|
|
State: e.Value,
|
|
Attributes: e.Attributes,
|
|
Icon: e.Icon,
|
|
ID: e.ID,
|
|
EntityType: e.EntityType.String(),
|
|
Name: e.Name,
|
|
Units: e.Units,
|
|
DeviceClass: e.DeviceClass.String(),
|
|
StateClass: e.StateClass.String(),
|
|
Category: e.Category.String(),
|
|
})
|
|
}
|
|
|
|
// Location represents the location information that can be sent to HA to
|
|
// update the location of the agent. This is exposed so that device code can
|
|
// create location requests directly, as Home Assistant handles these
|
|
// differently from other sensors.
|
|
type Location struct {
|
|
Gps []float64 `json:"gps" validate:"required"`
|
|
GpsAccuracy int `json:"gps_accuracy,omitempty"`
|
|
Battery int `json:"battery,omitempty"`
|
|
Speed int `json:"speed,omitempty"`
|
|
Altitude int `json:"altitude,omitempty"`
|
|
Course int `json:"course,omitempty"`
|
|
VerticalAccuracy int `json:"vertical_accuracy,omitempty"`
|
|
}
|
|
|
|
func (l *Location) Validate() error {
|
|
err := validation.Validate.Struct(l)
|
|
if err != nil {
|
|
return fmt.Errorf("location is invalid: %s", validation.ParseValidationErrors(err))
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (l *Location) RequestBody() any {
|
|
return &Request{
|
|
RequestType: requestTypeLocation,
|
|
Data: l,
|
|
}
|
|
}
|