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.

187 lines
5.4 KiB

1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
  1. package uistate
  2. import (
  3. "git.aiterp.net/lucifer3/server/device"
  4. "git.aiterp.net/lucifer3/server/effects"
  5. "git.aiterp.net/lucifer3/server/events"
  6. "git.aiterp.net/lucifer3/server/internal/color"
  7. "git.aiterp.net/lucifer3/server/internal/gentools"
  8. "git.aiterp.net/lucifer3/server/services/script"
  9. "github.com/google/uuid"
  10. "strings"
  11. )
  12. type Data struct {
  13. Devices map[string]Device `json:"devices"`
  14. Assignments map[uuid.UUID]Assignment `json:"assignments"`
  15. Scripts map[string][]script.Line `json:"scripts"`
  16. Triggers map[uuid.UUID]script.Trigger `json:"triggers"`
  17. }
  18. func (d *Data) WithPatch(patches ...Patch) Data {
  19. newData := d.Copy()
  20. for _, patch := range patches {
  21. if patch.Device != nil {
  22. pd := d.ensureDevice(patch.Device.ID)
  23. gentools.ApplyUpdate(&pd.Name, patch.Device.Name)
  24. gentools.ApplyUpdatePtr(&pd.HWState, patch.Device.HWState)
  25. gentools.ApplyUpdatePtr(&pd.HWMetadata, patch.Device.HWMetadata)
  26. gentools.ApplyUpdatePtr(&pd.DesiredState, patch.Device.DesiredState)
  27. gentools.ApplyUpdatePtr(&pd.Assignment, patch.Device.Assignment)
  28. gentools.ApplyUpdatePtr(&pd.ActiveColorRGB, patch.Device.ActiveColorRGB)
  29. gentools.ApplyUpdatePtr(&pd.DesiredColorRGB, patch.Device.DesiredColorRGB)
  30. if patch.Device.AddAlias != nil {
  31. ptr := device.Pointer{ID: "dummy", Aliases: pd.Aliases}
  32. ptr.AddAlias(*patch.Device.AddAlias)
  33. if strings.HasPrefix(*patch.Device.AddAlias, "lucifer:name:") {
  34. pd.Name = (*patch.Device.AddAlias)[len("lucifer:name:"):]
  35. }
  36. if strings.HasPrefix(*patch.Device.AddAlias, "lucifer:icon:") {
  37. pd.Icon = (*patch.Device.AddAlias)[len("lucifer:icon:"):]
  38. }
  39. pd.Aliases = ptr.Aliases
  40. }
  41. if patch.Device.RemoveAlias != nil {
  42. for i, alias := range pd.Aliases {
  43. if alias == *patch.Device.RemoveAlias {
  44. pd.Aliases = append(pd.Aliases[:i], pd.Aliases[i+1:]...)
  45. }
  46. }
  47. }
  48. if patch.Device.HWMetadata != nil {
  49. hasIconAlias := false
  50. for _, a := range pd.Aliases {
  51. if strings.HasPrefix(a, "lucifer:icon") {
  52. hasIconAlias = true
  53. break
  54. }
  55. }
  56. if !hasIconAlias {
  57. pd.Icon = patch.Device.HWMetadata.Icon
  58. }
  59. }
  60. if patch.Device.ClearAssignment {
  61. pd.Assignment = nil
  62. }
  63. if patch.Device.ClearActiveColorRGB {
  64. pd.ActiveColorRGB = nil
  65. }
  66. if patch.Device.Sensors != nil {
  67. if patch.Device.Sensors.LastMotion != nil {
  68. pd.Sensors.LastMotion = gentools.ShallowCopy(patch.Device.Sensors.LastMotion)
  69. }
  70. if patch.Device.Sensors.Temperature != nil {
  71. pd.Sensors.Temperature = gentools.ShallowCopy(patch.Device.Sensors.Temperature)
  72. }
  73. }
  74. if patch.Device.Delete {
  75. delete(newData.Devices, pd.ID)
  76. } else {
  77. newData.Devices[pd.ID] = pd
  78. }
  79. }
  80. if patch.Assignment != nil {
  81. pa := d.ensureAssignment(patch.Assignment.ID)
  82. gentools.ApplyUpdatePtr(&pa.Effect, patch.Assignment.Effect)
  83. if patch.Assignment.AddDeviceID != nil {
  84. pa.DeviceIDs = append(pa.DeviceIDs[:0:0], pa.DeviceIDs...)
  85. pa.DeviceIDs = append(pa.DeviceIDs, *patch.Assignment.AddDeviceID)
  86. }
  87. if patch.Assignment.RemoveDeviceID != nil {
  88. for i, id := range pa.DeviceIDs {
  89. if id == *patch.Assignment.RemoveDeviceID {
  90. pa.DeviceIDs = append(pa.DeviceIDs[:0:0], pa.DeviceIDs...)
  91. pa.DeviceIDs[i] = ""
  92. break
  93. }
  94. }
  95. }
  96. if patch.Assignment.Variables != nil {
  97. pa.Variables = gentools.CopyMap(patch.Assignment.Variables)
  98. }
  99. if patch.Assignment.Delete {
  100. delete(newData.Assignments, pa.ID)
  101. } else {
  102. newData.Assignments[pa.ID] = pa
  103. }
  104. }
  105. if patch.Script != nil {
  106. if len(patch.Script.Lines) > 0 {
  107. newData.Scripts[patch.Script.Name] = patch.Script.Lines
  108. } else {
  109. delete(newData.Scripts, patch.Script.Name)
  110. }
  111. }
  112. if patch.Trigger != nil {
  113. if !patch.Trigger.Delete {
  114. newData.Triggers[patch.Trigger.ID] = patch.Trigger.Trigger
  115. } else {
  116. delete(newData.Triggers, patch.Trigger.ID)
  117. }
  118. }
  119. }
  120. return newData
  121. }
  122. func (d *Data) Copy() Data {
  123. return Data{
  124. Devices: gentools.CopyMap(d.Devices),
  125. Assignments: gentools.CopyMap(d.Assignments),
  126. Scripts: gentools.CopyMap(d.Scripts),
  127. Triggers: gentools.CopyMap(d.Triggers),
  128. }
  129. }
  130. func (d *Data) ensureDevice(id string) Device {
  131. if device, ok := d.Devices[id]; ok {
  132. return device
  133. } else {
  134. return Device{ID: id}
  135. }
  136. }
  137. func (d *Data) ensureAssignment(id uuid.UUID) Assignment {
  138. if assignment, ok := d.Assignments[id]; ok {
  139. return assignment
  140. } else {
  141. return Assignment{ID: id}
  142. }
  143. }
  144. type Device struct {
  145. ID string `json:"id"`
  146. Name string `json:"name"`
  147. HWMetadata *events.HardwareMetadata `json:"hwMetadata"`
  148. HWState *events.HardwareState `json:"hwState"`
  149. DesiredColorRGB *color.RGB `json:"desiredColorRgb"`
  150. ActiveColorRGB *color.RGB `json:"activeColorRgb"`
  151. DesiredState *device.State `json:"desiredState"`
  152. Aliases []string `json:"aliases"`
  153. Assignment *uuid.UUID `json:"assignment"`
  154. Sensors DeviceSensors `json:"sensors"`
  155. Icon string `json:"icon"`
  156. }
  157. type DeviceSensors struct {
  158. LastMotion *float64 `json:"lastMotion,omitempty"`
  159. Temperature *float64 `json:"temperature,omitempty"`
  160. }
  161. type Assignment struct {
  162. ID uuid.UUID `json:"id"`
  163. DeviceIDs []string `json:"deviceIds"`
  164. Effect *effects.Serializable `json:"effect"`
  165. Variables map[string]float64 `json:"variables"`
  166. }