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.
136 lines
3.1 KiB
136 lines
3.1 KiB
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
|
|
}
|
|
}
|
|
}()
|
|
}
|
|
}
|
|
}
|