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.
 
 
 
 
 
 

118 lines
2.5 KiB

package tradfri
import (
"fmt"
lucifer3 "git.aiterp.net/lucifer3/server"
"git.aiterp.net/lucifer3/server/commands"
"git.aiterp.net/lucifer3/server/events"
"github.com/sirupsen/logrus"
"io"
"strings"
"sync"
)
func NewService() lucifer3.ActiveService {
logrus.StandardLogger().Out = io.Discard
logrus.StandardLogger().ExitFunc = func(i int) {
panic(fmt.Sprintf("tradfri: exit code %d", i))
}
return &service{
bridges: make(map[string]*Bridge, 4),
}
}
type service struct {
mu sync.Mutex
bridges map[string]*Bridge
}
func (s *service) Active() bool {
return true
}
func (s *service) HandleEvent(*lucifer3.EventBus, lucifer3.Event) {
// NOP
}
func (s *service) HandleCommand(bus *lucifer3.EventBus, command lucifer3.Command) {
defer s.mu.Unlock()
s.mu.Lock()
switch command := command.(type) {
case commands.PairDevice:
if sub, ok := command.Matches("tradfri"); ok {
bridge, err := connect(sub, command.APIKey)
if err != nil {
bus.RunEvent(events.DeviceFailed{
ID: command.ID,
Error: err.Error(),
})
return
}
s.bridges[bridge.id] = bridge
bus.RunEvent(events.DeviceAccepted{
ID: bridge.id,
APIKey: bridge.newCredentials,
})
}
case commands.SearchDevices:
bus.RunEvent(events.DeviceFailed{
ID: command.ID,
Error: "Please follow instructions in IKEA app; they will appear here after pairing.",
})
case commands.SetState:
if _, ok := command.Matches("tradfri"); ok {
bridge, ok := s.findBridge(command.ID)
if !ok {
return
}
bridge.writeState(command.ID, command.State, bus)
}
case commands.SetStateBatch:
for id, state := range command {
if strings.HasPrefix(id, "tradfri") {
bridge, ok := s.findBridge(id)
if !ok {
return
}
bridge.writeState(id, state, bus)
}
}
case commands.ConnectDevice:
if sub, ok := command.Matches("tradfri"); ok {
if s.bridges[command.ID] == nil {
bridge, err := connect(sub, command.APIKey)
if err != nil {
bus.RunEvent(events.DeviceFailed{
ID: command.ID,
Error: err.Error(),
})
return
}
s.bridges[command.ID] = bridge
}
bus.RunEvent(events.DeviceConnected{Prefix: s.bridges[command.ID].id})
s.bridges[command.ID].listen(bus)
}
}
}
func (s *service) findBridge(id string) (*Bridge, bool) {
bits := strings.Split(id, ":")
for i := 2; i < len(bits); i++ {
prefix := strings.Join(bits[0:i], ":")
if s.bridges[prefix] != nil {
return s.bridges[prefix], true
}
}
return nil, false
}