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.

259 lines
6.4 KiB

4 years ago
4 years ago
4 years ago
4 years ago
4 years ago
3 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. 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. DCColorXY DeviceCapability = "ColorXY"
  77. DCButtons DeviceCapability = "Buttons"
  78. DCPresence DeviceCapability = "Presence"
  79. DCIntensity DeviceCapability = "Intensity"
  80. DCTemperatureControl DeviceCapability = "TemperatureControl"
  81. DCTemperatureSensor DeviceCapability = "TemperatureSensor"
  82. )
  83. var Capabilities = []DeviceCapability{
  84. DCPower,
  85. DCColorHS,
  86. DCColorKelvin,
  87. DCButtons,
  88. DCPresence,
  89. DCIntensity,
  90. DCTemperatureControl,
  91. DCTemperatureSensor,
  92. }
  93. func (d *Device) ApplyUpdate(update DeviceUpdate) {
  94. if update.Name != nil {
  95. d.Name = *update.Name
  96. }
  97. if update.Icon != nil {
  98. d.Icon = *update.Icon
  99. }
  100. if d.UserProperties == nil {
  101. d.UserProperties = make(map[string]string)
  102. }
  103. for key, value := range update.UserProperties {
  104. if value != nil {
  105. d.UserProperties[key] = *value
  106. } else {
  107. delete(d.UserProperties, key)
  108. }
  109. }
  110. }
  111. func (d *Device) Validate() error {
  112. d.Name = strings.Trim(d.Name, " \t\n ")
  113. if d.Name == "" {
  114. return ErrInvalidName
  115. }
  116. newCaps := make([]DeviceCapability, 0, len(d.Capabilities))
  117. for _, currCap := range d.Capabilities {
  118. for _, validCap := range Capabilities {
  119. if currCap == validCap {
  120. newCaps = append(newCaps, currCap)
  121. break
  122. }
  123. }
  124. }
  125. d.Capabilities = newCaps
  126. return nil
  127. }
  128. func (d *Device) HasTag(tags ...string) bool {
  129. for _, c := range d.Tags {
  130. for _, c2 := range tags {
  131. if c == c2 {
  132. return true
  133. }
  134. }
  135. }
  136. return false
  137. }
  138. func (d *Device) IsOnlySensor() bool {
  139. return !d.HasCapability(
  140. DCPower,
  141. DCColorHS,
  142. DCColorHSK,
  143. DCColorKelvin,
  144. DCIntensity,
  145. DCTemperatureControl,
  146. )
  147. }
  148. func (d *Device) HasCapability(capabilities ...DeviceCapability) bool {
  149. for _, c := range d.Capabilities {
  150. for _, c2 := range capabilities {
  151. if c == c2 {
  152. return true
  153. }
  154. }
  155. }
  156. return false
  157. }
  158. func (d *Device) SetState(newState NewDeviceState) error {
  159. if newState.Power != nil && d.HasCapability(DCPower) {
  160. d.State.Power = *newState.Power
  161. }
  162. if newState.Color != nil {
  163. parsed, err := ParseColorValue(*newState.Color)
  164. if err != nil {
  165. return err
  166. }
  167. if (parsed.IsKelvin() && d.HasCapability(DCColorKelvin, DCColorHSK)) || (parsed.IsHueSat() && d.HasCapability(DCColorHS)) {
  168. d.State.Color = parsed
  169. }
  170. }
  171. if newState.Intensity != nil && d.HasCapability(DCIntensity) {
  172. d.State.Intensity = *newState.Intensity
  173. }
  174. if newState.Temperature != nil && d.HasCapability(DCTemperatureControl) {
  175. d.State.Temperature = *newState.Temperature
  176. }
  177. return nil
  178. }
  179. func (s *NewDeviceState) RelativeTo(device Device) NewDeviceState {
  180. n := NewDeviceState{}
  181. if s.Intensity != nil {
  182. intensity := device.State.Intensity * *s.Intensity
  183. n.Intensity = &intensity
  184. }
  185. return n
  186. }
  187. func (s *NewDeviceState) Interpolate(other NewDeviceState, fac float64) NewDeviceState {
  188. n := NewDeviceState{}
  189. if s.Power != nil && other.Power != nil {
  190. if fac >= 0.5 {
  191. n.Power = other.Power
  192. } else {
  193. n.Power = s.Power
  194. }
  195. }
  196. if s.Color != nil && other.Color != nil {
  197. sc, err := ParseColorValue(*s.Color)
  198. oc, err2 := ParseColorValue(*other.Color)
  199. if err == nil && err2 == nil {
  200. rc := ColorValue{}
  201. rc.Hue = interpolateFloat(sc.Hue, oc.Hue, fac)
  202. rc.Saturation = interpolateFloat(sc.Saturation, oc.Saturation, fac)
  203. rc.Kelvin = interpolateInt(sc.Kelvin, oc.Kelvin, fac)
  204. rcStr := rc.String()
  205. n.Color = &rcStr
  206. }
  207. }
  208. if s.Intensity != nil && other.Intensity != nil {
  209. n.Intensity = new(float64)
  210. *n.Intensity = interpolateFloat(*s.Intensity, *other.Intensity, fac)
  211. }
  212. return n
  213. }
  214. func interpolateFloat(a, b, fac float64) float64 {
  215. return (a * (1 - fac)) + (b * fac)
  216. }
  217. func interpolateInt(a, b int, fac float64) int {
  218. return int((float64(a) * (1 - fac)) + (float64(b) * fac))
  219. }