| 
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -5,6 +5,7 @@ import ( | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"git.aiterp.net/lucifer3/server/commands" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"git.aiterp.net/lucifer3/server/device" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"git.aiterp.net/lucifer3/server/events" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"git.aiterp.net/lucifer3/server/internal/color" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"git.aiterp.net/lucifer3/server/internal/gentools" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"github.com/google/uuid" | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						"sync" | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -18,6 +19,9 @@ func NewEffectEnforcer(resolver device.Resolver, sceneMap device.SceneMap) lucif | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							sceneMap: sceneMap, | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							list:     make([]*effectEnforcerRun, 0, 16), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							index:    make(map[string]*effectEnforcerRun, 8), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							supportFlags: make(map[string]device.SupportFlags), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							colorFlags:   make(map[string]device.ColorFlags), | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						return s | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -28,6 +32,9 @@ type effectEnforcer struct { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						resolver device.Resolver | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						sceneMap device.SceneMap | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						supportFlags map[string]device.SupportFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						colorFlags   map[string]device.ColorFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						started uint32 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						list  []*effectEnforcerRun | 
				
			
			
		
	
	
		
			
				
					| 
						
						
						
							
								
							
						
					 | 
				
				 | 
				
					@ -40,6 +47,22 @@ func (s *effectEnforcer) Active() bool { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					func (s *effectEnforcer) HandleEvent(_ *lucifer3.EventBus, event lucifer3.Event) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						switch event := event.(type) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						case events.HardwareState: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							s.mu.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							colorFlags := s.colorFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							supportFlags := s.supportFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							s.mu.Unlock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							colorFlags = gentools.CopyMap(colorFlags) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							supportFlags = gentools.CopyMap(supportFlags) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							colorFlags[event.ID] = event.ColorFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							supportFlags[event.ID] = event.SupportFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							s.mu.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							s.colorFlags = colorFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							s.supportFlags = supportFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							s.mu.Unlock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
						case events.DeviceReady: | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// If the device is managed by the effect enforcer, cause the effect to be
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							// re-ran.
 | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -127,6 +150,9 @@ func (s *effectEnforcer) runLoop(bus *lucifer3.EventBus) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							deleteIDs = deleteIDs[:0] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							s.mu.Lock() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							colorFlags := s.colorFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							supportFlags := s.supportFlags | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							for i, run := range s.list { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								if run.dead { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									deleteIDs = append(deleteIDs, run.id) | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
							
								
							
						
						
					 | 
				
				 | 
				
					@ -173,6 +199,51 @@ func (s *effectEnforcer) runLoop(bus *lucifer3.EventBus) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							if len(batch) > 0 { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								for id, state := range batch { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									sf := supportFlags[id] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									if state.Power != nil && !sf.HasAny(device.SFlagPower) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										state.Power = nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									if state.Temperature != nil && !sf.HasAny(device.SFlagTemperature) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										state.Temperature = nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									if state.Intensity != nil && !sf.HasAny(device.SFlagIntensity) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										state.Intensity = nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									if state.Color != nil && !sf.HasAny(device.SFlagColor) { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										state.Color = nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										cf := colorFlags[id] | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										invalid := (state.Color.K != nil && !cf.HasAll(device.CFlagKelvin)) || | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											(state.Color.XY != nil && !cf.HasAll(device.CFlagXY)) || | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											(state.Color.RGB != nil && !cf.HasAll(device.CFlagRGB)) || | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											(state.Color.HS != nil && !cf.HasAll(device.CFlagHS)) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										if invalid { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											var converted color.Color | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											var ok bool | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											switch { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											case cf.HasAny(device.CFlagXY): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
												converted, ok = state.Color.ToXY() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											case cf.HasAny(device.CFlagRGB): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
												converted, ok = state.Color.ToRGB() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											case cf.HasAny(device.CFlagHS): | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
												converted, ok = state.Color.ToHS() | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											if !ok { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
												state.Color = nil | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											} else { | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
												state.Color = &converted | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
											} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
										} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
									batch[id] = state | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								} | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
					
 | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								bus.RunCommand(batch) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
								batch = make(commands.SetStateBatch, 64) | 
				
			
			
		
	
		
			
				
					 | 
					 | 
				
				 | 
				
							} | 
				
			
			
		
	
	
		
			
				
					| 
						
							
								
							
						
						
						
					 | 
				
				 | 
				
					
  |