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.

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