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.

165 lines
4.9 KiB

  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. }
  17. func (d *Data) WithPatch(patches ...Patch) Data {
  18. newData := d.Copy()
  19. for _, patch := range patches {
  20. if patch.Device != nil {
  21. pd := d.ensureDevice(patch.Device.ID)
  22. gentools.ApplyUpdate(&pd.Name, patch.Device.Name)
  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. if pd.Icon == "" {
  49. pd.Icon = patch.Device.HWMetadata.Icon
  50. }
  51. }
  52. if patch.Device.ClearAssignment {
  53. pd.Assignment = nil
  54. }
  55. if patch.Device.ClearActiveColorRGB {
  56. pd.ActiveColorRGB = nil
  57. }
  58. if patch.Device.Sensors != nil {
  59. if patch.Device.Sensors.LastMotion != nil {
  60. pd.Sensors.LastMotion = gentools.ShallowCopy(patch.Device.Sensors.LastMotion)
  61. }
  62. if patch.Device.Sensors.Temperature != nil {
  63. pd.Sensors.Temperature = gentools.ShallowCopy(patch.Device.Sensors.Temperature)
  64. }
  65. }
  66. if patch.Device.Delete {
  67. delete(newData.Devices, pd.ID)
  68. } else {
  69. newData.Devices[pd.ID] = pd
  70. }
  71. }
  72. if patch.Assignment != nil {
  73. pa := d.ensureAssignment(patch.Assignment.ID)
  74. gentools.ApplyUpdatePtr(&pa.Effect, patch.Assignment.Effect)
  75. if patch.Assignment.AddDeviceID != nil {
  76. pa.DeviceIDs = append(pa.DeviceIDs[:0:0], pa.DeviceIDs...)
  77. pa.DeviceIDs = append(pa.DeviceIDs, *patch.Assignment.AddDeviceID)
  78. }
  79. if patch.Assignment.RemoveDeviceID != nil {
  80. for i, id := range pa.DeviceIDs {
  81. if id == *patch.Assignment.RemoveDeviceID {
  82. pa.DeviceIDs = append(pa.DeviceIDs[:0:0], pa.DeviceIDs...)
  83. pa.DeviceIDs[i] = ""
  84. break
  85. }
  86. }
  87. }
  88. if patch.Assignment.Variables != nil {
  89. pa.Variables = gentools.CopyMap(patch.Assignment.Variables)
  90. }
  91. if patch.Assignment.Delete {
  92. delete(newData.Assignments, pa.ID)
  93. } else {
  94. newData.Assignments[pa.ID] = pa
  95. }
  96. }
  97. if patch.Script != nil {
  98. newData.Scripts[patch.Script.Name] = patch.Script.Lines
  99. }
  100. }
  101. return newData
  102. }
  103. func (d *Data) Copy() Data {
  104. return Data{
  105. Devices: gentools.CopyMap(d.Devices),
  106. Assignments: gentools.CopyMap(d.Assignments),
  107. Scripts: gentools.CopyMap(d.Scripts),
  108. }
  109. }
  110. func (d *Data) ensureDevice(id string) Device {
  111. if device, ok := d.Devices[id]; ok {
  112. return device
  113. } else {
  114. return Device{ID: id}
  115. }
  116. }
  117. func (d *Data) ensureAssignment(id uuid.UUID) Assignment {
  118. if assignment, ok := d.Assignments[id]; ok {
  119. return assignment
  120. } else {
  121. return Assignment{ID: id}
  122. }
  123. }
  124. type Device struct {
  125. ID string `json:"id"`
  126. Name string `json:"name"`
  127. HWMetadata *events.HardwareMetadata `json:"hwMetadata"`
  128. HWState *events.HardwareState `json:"hwState"`
  129. DesiredColorRGB *color.RGB `json:"desiredColorRgb"`
  130. ActiveColorRGB *color.RGB `json:"activeColorRgb"`
  131. DesiredState *device.State `json:"desiredState"`
  132. Aliases []string `json:"aliases"`
  133. Assignment *uuid.UUID `json:"assignment"`
  134. Sensors DeviceSensors `json:"sensors"`
  135. Icon string `json:"icon"`
  136. }
  137. type DeviceSensors struct {
  138. LastMotion *float64 `json:"lastMotion,omitempty"`
  139. Temperature *float64 `json:"temperature,omitempty"`
  140. }
  141. type Assignment struct {
  142. ID uuid.UUID `json:"id"`
  143. DeviceIDs []string `json:"deviceIds"`
  144. Effect *effects.Serializable `json:"effect"`
  145. Variables map[string]float64 `json:"variables"`
  146. }