181 lines
4.5 KiB
Go
181 lines
4.5 KiB
Go
package models
|
||
|
||
import (
|
||
"context"
|
||
"strings"
|
||
)
|
||
|
||
type Device struct {
|
||
ID int `json:"id"`
|
||
BridgeID int `json:"bridgeID"`
|
||
InternalID string `json:"internalId"`
|
||
Icon string `json:"icon"`
|
||
Name string `json:"name"`
|
||
Capabilities []DeviceCapability `json:"capabilities"`
|
||
ButtonNames []string `json:"buttonNames"`
|
||
DriverProperties map[string]interface{} `json:"driverProperties"`
|
||
UserProperties map[string]string `json:"userProperties"`
|
||
State DeviceState `json:"state"`
|
||
Tags []string `json:"tags"`
|
||
}
|
||
|
||
type DeviceUpdate struct {
|
||
Icon *string `json:"icon"`
|
||
Name *string `json:"name"`
|
||
UserProperties map[string]*string `json:"userProperties"`
|
||
}
|
||
|
||
// DeviceState contains optional state values that
|
||
// - Power: Whether the device is powered on
|
||
// - Color: Color value, if a color setting can be set on the device
|
||
// - Intensity: e.g. brightness, range 0..=1
|
||
// - Temperature: e.g. for thermostats
|
||
type DeviceState struct {
|
||
Power bool `json:"power"`
|
||
Color ColorValue `json:"color,omitempty"`
|
||
Intensity float64 `json:"intensity,omitempty"`
|
||
Temperature float64 `json:"temperature"`
|
||
}
|
||
|
||
type NewDeviceState struct {
|
||
Power *bool `json:"power"`
|
||
Color *string `json:"color"`
|
||
Intensity *float64 `json:"intensity"`
|
||
Temperature *int `json:"temperature"`
|
||
}
|
||
|
||
type DeviceCapability string
|
||
|
||
type SaveMode int
|
||
|
||
const (
|
||
SMState SaveMode = 1
|
||
SMProperties SaveMode = 2
|
||
SMTags SaveMode = 4
|
||
)
|
||
|
||
type DeviceRepository interface {
|
||
Find(ctx context.Context, id int) (*Device, error)
|
||
FetchByReference(ctx context.Context, kind ReferenceKind, value string) ([]Device, error)
|
||
Save(ctx context.Context, device *Device, mode SaveMode) error
|
||
Delete(ctx context.Context, device *Device) error
|
||
}
|
||
|
||
func DeviceCapabilitiesToStrings(caps []DeviceCapability) []string {
|
||
res := make([]string, 0, len(caps))
|
||
for _, cap := range caps {
|
||
res = append(res, string(cap))
|
||
}
|
||
|
||
return res
|
||
}
|
||
|
||
var (
|
||
DCPower DeviceCapability = "Power"
|
||
DCColorHS DeviceCapability = "ColorHS"
|
||
DCColorHSK DeviceCapability = "ColorHSK"
|
||
DCColorKelvin DeviceCapability = "ColorKelvin"
|
||
DCButtons DeviceCapability = "Buttons"
|
||
DCPresence DeviceCapability = "Presence"
|
||
DCIntensity DeviceCapability = "Intensity"
|
||
DCTemperatureControl DeviceCapability = "TemperatureControl"
|
||
DCTemperatureSensor DeviceCapability = "TemperatureSensor"
|
||
)
|
||
|
||
var Capabilities = []DeviceCapability{
|
||
DCPower,
|
||
DCColorHS,
|
||
DCColorKelvin,
|
||
DCButtons,
|
||
DCPresence,
|
||
DCIntensity,
|
||
DCTemperatureControl,
|
||
DCTemperatureSensor,
|
||
}
|
||
|
||
func (d *Device) ApplyUpdate(update DeviceUpdate) {
|
||
if update.Name != nil {
|
||
d.Name = *update.Name
|
||
}
|
||
if update.Icon != nil {
|
||
d.Icon = *update.Icon
|
||
}
|
||
if d.UserProperties == nil {
|
||
d.UserProperties = make(map[string]string)
|
||
}
|
||
for key, value := range update.UserProperties {
|
||
if value != nil {
|
||
d.UserProperties[key] = *value
|
||
} else {
|
||
delete(d.UserProperties, key)
|
||
}
|
||
}
|
||
}
|
||
|
||
func (d *Device) Validate() error {
|
||
d.Name = strings.Trim(d.Name, " \t\n ")
|
||
if d.Name == "" {
|
||
return ErrInvalidName
|
||
}
|
||
|
||
newCaps := make([]DeviceCapability, 0, len(d.Capabilities))
|
||
for _, currCap := range d.Capabilities {
|
||
for _, validCap := range Capabilities {
|
||
if currCap == validCap {
|
||
newCaps = append(newCaps, currCap)
|
||
break
|
||
}
|
||
}
|
||
}
|
||
d.Capabilities = newCaps
|
||
|
||
return nil
|
||
}
|
||
|
||
func (d *Device) HasTag(tags ...string) bool {
|
||
for _, c := range d.Tags {
|
||
for _, c2 := range tags {
|
||
if c == c2 {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
func (d *Device) HasCapability(capabilities ...DeviceCapability) bool {
|
||
for _, c := range d.Capabilities {
|
||
for _, c2 := range capabilities {
|
||
if c == c2 {
|
||
return true
|
||
}
|
||
}
|
||
}
|
||
|
||
return false
|
||
}
|
||
|
||
func (d *Device) SetState(newState NewDeviceState) error {
|
||
if newState.Power != nil && d.HasCapability(DCPower) {
|
||
d.State.Power = *newState.Power
|
||
}
|
||
|
||
if newState.Color != nil {
|
||
parsed, err := ParseColorValue(*newState.Color)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
if (parsed.IsKelvin() && d.HasCapability(DCColorKelvin, DCColorHSK)) || (parsed.IsHueSat() && d.HasCapability(DCColorHS)) {
|
||
d.State.Color = parsed
|
||
}
|
||
}
|
||
|
||
if newState.Intensity != nil && d.HasCapability(DCIntensity) {
|
||
d.State.Intensity = *newState.Intensity
|
||
}
|
||
|
||
return nil
|
||
}
|