|
|
package publisher
import ( "git.aiterp.net/lucifer/new-server/models" "time" )
type Scene struct { data *models.Scene group string startTime time.Time endTime time.Time roleMap map[int]int roleList map[int][]models.Device lastStates map[int]models.DeviceState
due bool lastInterval int64 }
// UpdateScene updates the scene data and re-seats all devices.
func (s *Scene) UpdateScene(data models.Scene) { devices := make([]models.Device, 0, 16)
// Collect all devices into the undefined role (-1)
for _, list := range s.roleList { for _, device := range list { devices = append(devices, device) s.roleMap[device.ID] = -1 } } s.roleList = map[int][]models.Device{-1: devices}
// Update data and reset devices.
s.data = &data for _, device := range append(devices[:0:0], devices...) { s.UpsertDevice(device) } }
// UpsertDevice moves the device if necessary and updates its state.
func (s *Scene) UpsertDevice(device models.Device) { if s.data == nil { s.roleMap[device.ID] = -1 s.roleList[-1] = append(s.roleList[-1], device) return }
oldIndex, hasOldIndex := s.roleMap[device.ID] newIndex := s.data.RoleIndex(&device)
s.roleMap[device.ID] = newIndex
if hasOldIndex { for i, device2 := range s.roleList[oldIndex] { if device2.ID == device.ID { s.roleList[oldIndex] = append(s.roleList[oldIndex][:i], s.roleList[oldIndex][i+1:]...) break } } }
s.due = true
s.roleList[newIndex] = append(s.roleList[newIndex], device) if newIndex != -1 { s.data.Roles[newIndex].ApplyOrder(s.roleList[newIndex]) } }
// RemoveDevice finds and remove a device. It's a noop if the device does not exist in this scene.
func (s *Scene) RemoveDevice(device models.Device) { roleIndex, hasRoleIndex := s.roleMap[device.ID] if !hasRoleIndex { return }
for i, device2 := range s.roleList[roleIndex] { if device2.ID == device.ID { s.roleList[roleIndex] = append(s.roleList[roleIndex][:i], s.roleList[roleIndex][i+1:]...) break } }
s.due = true
delete(s.roleMap, device.ID) delete(s.lastStates, device.ID) }
func (s *Scene) Empty() bool { for _, list := range s.roleList { if len(list) > 0 { return false } }
return true }
func (s *Scene) Due() bool { if s.due { return true }
if s.data.IntervalMS > 0 { interval := time.Duration(s.data.IntervalMS) * time.Millisecond return int64(time.Since(s.startTime)/interval) != s.lastInterval }
return false }
func (s *Scene) UnaffectedDevices() []models.Device { return append(s.roleList[-1][:0:0], s.roleList[-1]...) }
func (s *Scene) AllDevices() []models.Device { res := make([]models.Device, 0, 16) for _, list := range s.roleList { res = append(res, list...) }
return res }
// Run runs the scene
func (s *Scene) Run() []models.Device { if s.data == nil { return []models.Device{} }
intervalNumber := int64(0) intervalMax := int64(1) if s.data.IntervalMS > 0 { interval := time.Duration(s.data.IntervalMS) * time.Millisecond intervalNumber = int64(time.Since(s.startTime) / interval)
if !s.endTime.IsZero() { intervalMax = int64(s.endTime.Sub(s.startTime) / interval) } else { intervalMax = intervalNumber + 1 } }
updatedDevices := make([]models.Device, 0, 16) for i, list := range s.roleList { if i == -1 { continue }
role := s.data.Roles[i]
for j, device := range list { newState := role.ApplyEffect(&device, models.SceneRunContext{ Index: j, Length: len(list), IntervalNumber: intervalNumber, IntervalMax: intervalMax, })
err := device.SetState(newState) if err != nil { continue }
s.lastStates[device.ID] = device.State
updatedDevices = append(updatedDevices, device) } }
s.due = false s.lastInterval = intervalNumber
return updatedDevices }
func (s *Scene) LastState(id int) *models.DeviceState { lastState, ok := s.lastStates[id] if !ok { return nil }
return &lastState }
|