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.

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