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.

225 lines
4.6 KiB

  1. package publisher
  2. import (
  3. "git.aiterp.net/lucifer/new-server/models"
  4. "time"
  5. )
  6. type Scene struct {
  7. data *models.Scene
  8. group string
  9. startTime time.Time
  10. endTime time.Time
  11. roleMap map[int]int
  12. roleList map[int][]models.Device
  13. lastStates map[int]models.DeviceState
  14. sensors []models.SceneSensor
  15. due bool
  16. lastInterval int64
  17. }
  18. func (s *Scene) UpdateSensor(data models.SceneSensor) {
  19. s.due = true
  20. for i, sensor := range s.sensors {
  21. if sensor.ID == data.ID {
  22. s.sensors[i] = data
  23. return
  24. }
  25. }
  26. s.sensors = append(s.sensors, data)
  27. }
  28. // UpdateScene updates the scene data and re-seats all devices.
  29. func (s *Scene) UpdateScene(data models.Scene) {
  30. devices := make([]models.Device, 0, 16)
  31. // Collect all devices into the undefined role (-1)
  32. for _, list := range s.roleList {
  33. for _, device := range list {
  34. devices = append(devices, device)
  35. s.roleMap[device.ID] = -1
  36. }
  37. }
  38. s.roleList = map[int][]models.Device{-1: devices}
  39. // Update data and reset devices.
  40. s.data = &data
  41. for _, device := range append(devices[:0:0], devices...) {
  42. s.UpsertDevice(device)
  43. }
  44. }
  45. // UpsertDevice moves the device if necessary and updates its state.
  46. func (s *Scene) UpsertDevice(device models.Device) {
  47. if s.data == nil {
  48. s.roleMap[device.ID] = -1
  49. s.roleList[-1] = append(s.roleList[-1], device)
  50. return
  51. }
  52. oldIndex, hasOldIndex := s.roleMap[device.ID]
  53. newIndex := s.data.RoleIndex(&device)
  54. s.roleMap[device.ID] = newIndex
  55. if hasOldIndex {
  56. for i, device2 := range s.roleList[oldIndex] {
  57. if device2.ID == device.ID {
  58. s.roleList[oldIndex] = append(s.roleList[oldIndex][:i], s.roleList[oldIndex][i+1:]...)
  59. break
  60. }
  61. }
  62. }
  63. s.due = true
  64. s.roleList[newIndex] = append(s.roleList[newIndex], device)
  65. if newIndex != -1 {
  66. s.data.Roles[newIndex].ApplyOrder(s.roleList[newIndex])
  67. }
  68. }
  69. // RemoveDevice finds and remove a device. It's a noop if the device does not exist in this scene.
  70. func (s *Scene) RemoveDevice(device models.Device) {
  71. roleIndex, hasRoleIndex := s.roleMap[device.ID]
  72. if !hasRoleIndex {
  73. return
  74. }
  75. for i, device2 := range s.roleList[roleIndex] {
  76. if device2.ID == device.ID {
  77. s.roleList[roleIndex] = append(s.roleList[roleIndex][:i], s.roleList[roleIndex][i+1:]...)
  78. break
  79. }
  80. }
  81. s.due = true
  82. delete(s.roleMap, device.ID)
  83. delete(s.lastStates, device.ID)
  84. for i, sensor := range s.sensors {
  85. if sensor.ID == device.ID {
  86. s.sensors = append(s.sensors[:i], s.sensors[i+1:]...)
  87. break
  88. }
  89. }
  90. }
  91. func (s *Scene) Empty() bool {
  92. for _, list := range s.roleList {
  93. if len(list) > 0 {
  94. return false
  95. }
  96. }
  97. return true
  98. }
  99. func (s *Scene) Due() bool {
  100. if s.due {
  101. return true
  102. }
  103. if s.data.IntervalMS > 0 {
  104. interval := time.Duration(s.data.IntervalMS) * time.Millisecond
  105. return int64(time.Since(s.startTime)/interval) != s.lastInterval
  106. }
  107. return false
  108. }
  109. func (s *Scene) UnaffectedDevices() []models.Device {
  110. return append(s.roleList[-1][:0:0], s.roleList[-1]...)
  111. }
  112. func (s *Scene) AllDevices() []models.Device {
  113. res := make([]models.Device, 0, 16)
  114. for _, list := range s.roleList {
  115. res = append(res, list...)
  116. }
  117. return res
  118. }
  119. // Run runs the scene
  120. func (s *Scene) Run() []models.Device {
  121. if s.data == nil {
  122. return []models.Device{}
  123. }
  124. currentTime := time.Now()
  125. intervalNumber := int64(0)
  126. intervalMax := int64(1)
  127. if s.data.IntervalMS > 0 {
  128. interval := time.Duration(s.data.IntervalMS) * time.Millisecond
  129. intervalNumber = int64(time.Since(s.startTime) / interval)
  130. if !s.endTime.IsZero() {
  131. intervalMax = int64(s.endTime.Sub(s.startTime) / interval)
  132. } else {
  133. intervalMax = intervalNumber + 1
  134. }
  135. }
  136. updatedDevices := make([]models.Device, 0, 16)
  137. for i, list := range s.roleList {
  138. if i == -1 {
  139. continue
  140. }
  141. sensorCount := 0
  142. for _, device := range list {
  143. if device.IsOnlySensor() {
  144. sensorCount += 1
  145. }
  146. }
  147. role := s.data.Roles[i]
  148. jSkip := 0
  149. for j, device := range list {
  150. if device.IsOnlySensor() {
  151. updatedDevices = append(updatedDevices, device)
  152. jSkip += 1
  153. continue
  154. }
  155. newState := role.ApplyEffect(&device, models.SceneRunContext{
  156. CurrentTime: currentTime,
  157. Index: j - jSkip,
  158. Length: len(list) - sensorCount,
  159. IntervalNumber: intervalNumber,
  160. IntervalMax: intervalMax,
  161. Sensors: s.sensors,
  162. })
  163. err := device.SetState(newState)
  164. if err != nil {
  165. continue
  166. }
  167. s.lastStates[device.ID] = device.State
  168. updatedDevices = append(updatedDevices, device)
  169. }
  170. }
  171. s.due = false
  172. s.lastInterval = intervalNumber
  173. return updatedDevices
  174. }
  175. func (s *Scene) LastState(id int) *models.DeviceState {
  176. lastState, ok := s.lastStates[id]
  177. if !ok {
  178. return nil
  179. }
  180. return &lastState
  181. }