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.

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