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.
120 lines
2.5 KiB
120 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:
|
|
if _, ok := command.Matches("tradfri"); ok {
|
|
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
|
|
}
|