You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
4.5 KiB

3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
3 years ago
  1. package models
  2. import (
  3. "context"
  4. "strings"
  5. )
  6. type Device struct {
  7. ID int `json:"id"`
  8. BridgeID int `json:"bridgeID"`
  9. InternalID string `json:"internalId"`
  10. Icon string `json:"icon"`
  11. Name string `json:"name"`
  12. Capabilities []DeviceCapability `json:"capabilities"`
  13. ButtonNames []string `json:"buttonNames"`
  14. DriverProperties map[string]interface{} `json:"driverProperties"`
  15. UserProperties map[string]string `json:"userProperties"`
  16. State DeviceState `json:"state"`
  17. Tags []string `json:"tags"`
  18. }
  19. type DeviceUpdate struct {
  20. Icon *string `json:"icon"`
  21. Name *string `json:"name"`
  22. UserProperties map[string]*string `json:"userProperties"`
  23. }
  24. // DeviceState contains optional state values that
  25. // - Power: Whether the device is powered on
  26. // - Color: Color value, if a color setting can be set on the device
  27. // - Intensity: e.g. brightness, range 0..=1
  28. // - Temperature: e.g. for thermostats
  29. type DeviceState struct {
  30. Power bool `json:"power"`
  31. Color ColorValue `json:"color,omitempty"`
  32. Intensity float64 `json:"intensity,omitempty"`
  33. Temperature float64 `json:"temperature"`
  34. }
  35. type NewDeviceState struct {
  36. Power *bool `json:"power"`
  37. Color *string `json:"color"`
  38. Intensity *float64 `json:"intensity"`
  39. Temperature *int `json:"temperature"`
  40. }
  41. type DeviceCapability string
  42. type SaveMode int
  43. const (
  44. SMState SaveMode = 1
  45. SMProperties SaveMode = 2
  46. SMTags SaveMode = 4
  47. )
  48. type DeviceRepository interface {
  49. Find(ctx context.Context, id int) (*Device, error)
  50. FetchByReference(ctx context.Context, kind ReferenceKind, value string) ([]Device, error)
  51. Save(ctx context.Context, device *Device, mode SaveMode) error
  52. Delete(ctx context.Context, device *Device) error
  53. }
  54. func DeviceCapabilitiesToStrings(caps []DeviceCapability) []string {
  55. res := make([]string, 0, len(caps))
  56. for _, cap := range caps {
  57. res = append(res, string(cap))
  58. }
  59. return res
  60. }
  61. var (
  62. DCPower DeviceCapability = "Power"
  63. DCColorHS DeviceCapability = "ColorHS"
  64. DCColorHSK DeviceCapability = "ColorHSK"
  65. DCColorKelvin DeviceCapability = "ColorKelvin"
  66. DCButtons DeviceCapability = "Buttons"
  67. DCPresence DeviceCapability = "Presence"
  68. DCIntensity DeviceCapability = "Intensity"
  69. DCTemperatureControl DeviceCapability = "TemperatureControl"
  70. DCTemperatureSensor DeviceCapability = "TemperatureSensor"
  71. )
  72. var Capabilities = []DeviceCapability{
  73. DCPower,
  74. DCColorHS,
  75. DCColorKelvin,
  76. DCButtons,
  77. DCPresence,
  78. DCIntensity,
  79. DCTemperatureControl,
  80. DCTemperatureSensor,
  81. }
  82. func (d *Device) ApplyUpdate(update DeviceUpdate) {
  83. if update.Name != nil {
  84. d.Name = *update.Name
  85. }
  86. if update.Icon != nil {
  87. d.Icon = *update.Icon
  88. }
  89. if d.UserProperties == nil {
  90. d.UserProperties = make(map[string]string)
  91. }
  92. for key, value := range update.UserProperties {
  93. if value != nil {
  94. d.UserProperties[key] = *value
  95. } else {
  96. delete(d.UserProperties, key)
  97. }
  98. }
  99. }
  100. func (d *Device) Validate() error {
  101. d.Name = strings.Trim(d.Name, " \t\n ")
  102. if d.Name == "" {
  103. return ErrInvalidName
  104. }
  105. newCaps := make([]DeviceCapability, 0, len(d.Capabilities))
  106. for _, currCap := range d.Capabilities {
  107. for _, validCap := range Capabilities {
  108. if currCap == validCap {
  109. newCaps = append(newCaps, currCap)
  110. break
  111. }
  112. }
  113. }
  114. d.Capabilities = newCaps
  115. return nil
  116. }
  117. func (d *Device) HasTag(tags ...string) bool {
  118. for _, c := range d.Tags {
  119. for _, c2 := range tags {
  120. if c == c2 {
  121. return true
  122. }
  123. }
  124. }
  125. return false
  126. }
  127. func (d *Device) HasCapability(capabilities ...DeviceCapability) bool {
  128. for _, c := range d.Capabilities {
  129. for _, c2 := range capabilities {
  130. if c == c2 {
  131. return true
  132. }
  133. }
  134. }
  135. return false
  136. }
  137. func (d *Device) SetState(newState NewDeviceState) error {
  138. if newState.Power != nil && d.HasCapability(DCPower) {
  139. d.State.Power = *newState.Power
  140. }
  141. if newState.Color != nil {
  142. parsed, err := ParseColorValue(*newState.Color)
  143. if err != nil {
  144. return err
  145. }
  146. if (parsed.IsKelvin() && d.HasCapability(DCColorKelvin, DCColorHSK)) || (parsed.IsHueSat() && d.HasCapability(DCColorHS)) {
  147. d.State.Color = parsed
  148. }
  149. }
  150. if newState.Intensity != nil && d.HasCapability(DCIntensity) {
  151. d.State.Intensity = *newState.Intensity
  152. }
  153. return nil
  154. }