|
|
package nanoleaf
import ( "context" "fmt" lucifer3 "git.aiterp.net/lucifer3/server" "git.aiterp.net/lucifer3/server/commands" "git.aiterp.net/lucifer3/server/events" "strings" "time" )
func NewService() lucifer3.ActiveService { return &service{ bridges: make(map[string]*bridge), cancels: make(map[string]context.CancelFunc), } }
type service struct { bridges map[string]*bridge cancels map[string]context.CancelFunc }
func (s *service) Active() bool { return true }
func (s *service) HandleEvent(*lucifer3.EventBus, lucifer3.Event) {}
func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command) { switch command := command.(type) { case commands.SetState: if sub, ok := command.Matches("nanoleaf"); ok && s.bridges[sub] != nil { s.bridges[sub].Update(command.ID, command.State) }
case commands.SetStateBatch: for _, b := range s.bridges { b.UpdateBatch(command) }
case commands.SearchDevices: if sub, ok := command.Matches("nanoleaf"); ok { if s.bridges[sub] != nil { go func(bridge *bridge) { newIDs, err := bridge.Refresh(context.Background()) if err != nil { bus.RunEvent(events.DeviceFailed{ ID: command.ID, Error: fmt.Sprintf("Search failed: %s", err), }) return } if len(newIDs) > 0 { for _, event := range bridge.HardwareEvents() { bus.RunEvent(event) } for _, id := range newIDs { bus.RunEvent(events.DeviceReady{ID: id}) } } }(s.bridges[sub]) } }
case commands.PairDevice: if address, ok := command.Matches("nanoleaf"); ok { go func() { timeout, cancel := context.WithTimeout(context.Background(), time.Second*5) defer cancel()
apiKey, info, err := Discover(timeout, address, true) if err != nil { bus.RunEvent(events.DeviceFailed{ ID: command.ID, Error: fmt.Sprintf("Pairing failed: %s", err), }) return }
bus.RunEvent(events.DeviceAccepted{ ID: command.ID, APIKey: apiKey, Extras: nil, }) bus.RunEvent(events.HardwareMetadata{ ID: command.ID, Icon: "bridge", SerialNumber: info.SerialNumber, FirmwareVersion: strings.Join([]string{ info.FirmwareVersion, info.BootloaderVersion, info.HardwareVersion, }, "; "), }) }() }
case commands.ConnectDevice: if sub, ok := command.Matches("nanoleaf"); ok { if s.bridges[sub] != nil { s.cancels[sub]() }
ctx, cancel := context.WithCancel(context.Background())
s.bridges[sub] = &bridge{ host: sub, apiKey: command.APIKey, panels: make([]*panel, 0, 64), panelIDMap: make(map[uint16]string), } s.cancels[sub] = cancel
go func() { for ctx.Err() == nil { ctx2, cancel2 := context.WithCancel(ctx)
err := s.bridges[sub].Run(ctx2, bus) cancel2() if err != nil { bus.RunEvent(events.DeviceFailed{ ID: command.ID, Error: fmt.Sprintf("Run failed: %s", err), }) }
select { case <-time.After(time.Second * 5): case <-ctx.Done(): return } } }() } } }
|