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.

221 lines
5.5 KiB

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