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.

202 lines
5.8 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.ApplyUpdatePtr(&pd.HWState, patch.Device.HWState)
  24. gentools.ApplyUpdatePtr(&pd.HWMetadata, patch.Device.HWMetadata)
  25. gentools.ApplyUpdatePtr(&pd.DesiredState, patch.Device.DesiredState)
  26. gentools.ApplyUpdatePtr(&pd.Assignment, patch.Device.Assignment)
  27. gentools.ApplyUpdatePtr(&pd.ActiveColorRGB, patch.Device.ActiveColorRGB)
  28. gentools.ApplyUpdatePtr(&pd.DesiredColorRGB, patch.Device.DesiredColorRGB)
  29. if patch.Device.AddAlias != nil {
  30. ptr := device.Pointer{ID: "dummy", Aliases: pd.Aliases}
  31. ptr.AddAlias(*patch.Device.AddAlias)
  32. if strings.HasPrefix(*patch.Device.AddAlias, "lucifer:name:") {
  33. pd.Name = (*patch.Device.AddAlias)[len("lucifer:name:"):]
  34. }
  35. if strings.HasPrefix(*patch.Device.AddAlias, "lucifer:icon:") {
  36. pd.Icon = (*patch.Device.AddAlias)[len("lucifer:icon:"):]
  37. }
  38. pd.Aliases = ptr.Aliases
  39. }
  40. if patch.Device.RemoveAlias != nil {
  41. for i, alias := range pd.Aliases {
  42. if alias == *patch.Device.RemoveAlias {
  43. pd.Aliases = append(pd.Aliases[:i], pd.Aliases[i+1:]...)
  44. }
  45. }
  46. }
  47. if patch.Device.HWMetadata != nil {
  48. hasIconAlias := false
  49. for _, a := range pd.Aliases {
  50. if strings.HasPrefix(a, "lucifer:icon") {
  51. hasIconAlias = true
  52. break
  53. }
  54. }
  55. if !hasIconAlias {
  56. pd.Icon = patch.Device.HWMetadata.Icon
  57. }
  58. }
  59. if patch.Device.HWState != nil {
  60. hasName := false
  61. for _, alias := range pd.Aliases {
  62. if strings.HasPrefix(alias, "lucifer:name:") {
  63. hasName = true
  64. break
  65. }
  66. }
  67. if !hasName {
  68. pd.Aliases = append(pd.Aliases, "lucifer:name:"+patch.Device.HWState.InternalName)
  69. }
  70. if pd.Name == "" {
  71. pd.Name = patch.Device.HWState.InternalName
  72. }
  73. }
  74. if patch.Device.ClearAssignment {
  75. pd.Assignment = nil
  76. }
  77. if patch.Device.ClearActiveColorRGB {
  78. pd.ActiveColorRGB = nil
  79. }
  80. if patch.Device.Sensors != nil {
  81. if patch.Device.Sensors.LastMotion != nil {
  82. pd.Sensors.LastMotion = gentools.ShallowCopy(patch.Device.Sensors.LastMotion)
  83. }
  84. if patch.Device.Sensors.Temperature != nil {
  85. pd.Sensors.Temperature = gentools.ShallowCopy(patch.Device.Sensors.Temperature)
  86. }
  87. }
  88. if patch.Device.Delete {
  89. delete(newData.Devices, pd.ID)
  90. } else {
  91. newData.Devices[pd.ID] = pd
  92. }
  93. }
  94. if patch.Assignment != nil {
  95. pa := d.ensureAssignment(patch.Assignment.ID)
  96. gentools.ApplyUpdatePtr(&pa.Effect, patch.Assignment.Effect)
  97. if patch.Assignment.AddDeviceID != nil {
  98. pa.DeviceIDs = append(pa.DeviceIDs[:0:0], pa.DeviceIDs...)
  99. pa.DeviceIDs = append(pa.DeviceIDs, *patch.Assignment.AddDeviceID)
  100. }
  101. if patch.Assignment.RemoveDeviceID != nil {
  102. for i, id := range pa.DeviceIDs {
  103. if id == *patch.Assignment.RemoveDeviceID {
  104. pa.DeviceIDs = append(pa.DeviceIDs[:0:0], pa.DeviceIDs...)
  105. pa.DeviceIDs[i] = ""
  106. break
  107. }
  108. }
  109. }
  110. if patch.Assignment.Variables != nil {
  111. pa.Variables = gentools.CopyMap(patch.Assignment.Variables)
  112. }
  113. if patch.Assignment.Delete {
  114. delete(newData.Assignments, pa.ID)
  115. } else {
  116. newData.Assignments[pa.ID] = pa
  117. }
  118. }
  119. if patch.Script != nil {
  120. if len(patch.Script.Lines) > 0 {
  121. newData.Scripts[patch.Script.Name] = patch.Script.Lines
  122. } else {
  123. delete(newData.Scripts, patch.Script.Name)
  124. }
  125. }
  126. if patch.Trigger != nil {
  127. if !patch.Trigger.Delete {
  128. newData.Triggers[patch.Trigger.ID] = patch.Trigger.Trigger
  129. } else {
  130. delete(newData.Triggers, patch.Trigger.ID)
  131. }
  132. }
  133. }
  134. return newData
  135. }
  136. func (d *Data) Copy() Data {
  137. return Data{
  138. Devices: gentools.CopyMap(d.Devices),
  139. Assignments: gentools.CopyMap(d.Assignments),
  140. Scripts: gentools.CopyMap(d.Scripts),
  141. Triggers: gentools.CopyMap(d.Triggers),
  142. }
  143. }
  144. func (d *Data) ensureDevice(id string) Device {
  145. if device, ok := d.Devices[id]; ok {
  146. return device
  147. } else {
  148. return Device{ID: id, Aliases: make([]string, 0)}
  149. }
  150. }
  151. func (d *Data) ensureAssignment(id uuid.UUID) Assignment {
  152. if assignment, ok := d.Assignments[id]; ok {
  153. return assignment
  154. } else {
  155. return Assignment{ID: id}
  156. }
  157. }
  158. type Device struct {
  159. ID string `json:"id"`
  160. Name string `json:"name"`
  161. HWMetadata *events.HardwareMetadata `json:"hwMetadata"`
  162. HWState *events.HardwareState `json:"hwState"`
  163. DesiredColorRGB *color.RGB `json:"desiredColorRgb"`
  164. ActiveColorRGB *color.RGB `json:"activeColorRgb"`
  165. DesiredState *device.State `json:"desiredState"`
  166. Aliases []string `json:"aliases"`
  167. Assignment *uuid.UUID `json:"assignment"`
  168. Sensors DeviceSensors `json:"sensors"`
  169. Icon string `json:"icon"`
  170. }
  171. type DeviceSensors struct {
  172. LastMotion *float64 `json:"lastMotion,omitempty"`
  173. Temperature *float64 `json:"temperature,omitempty"`
  174. }
  175. type Assignment struct {
  176. ID uuid.UUID `json:"id"`
  177. DeviceIDs []string `json:"deviceIds"`
  178. Effect *effects.Serializable `json:"effect"`
  179. Variables map[string]float64 `json:"variables"`
  180. }