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.
145 lines
2.8 KiB
145 lines
2.8 KiB
package mill
|
|
|
|
import (
|
|
"errors"
|
|
lucifer3 "git.aiterp.net/lucifer3/server"
|
|
"git.aiterp.net/lucifer3/server/commands"
|
|
"git.aiterp.net/lucifer3/server/device"
|
|
"git.aiterp.net/lucifer3/server/events"
|
|
"sync"
|
|
)
|
|
|
|
func NewService() lucifer3.ActiveService {
|
|
return &service{
|
|
bridges: make([]Bridge, 0, 8),
|
|
}
|
|
}
|
|
|
|
type service struct {
|
|
mu sync.Mutex
|
|
|
|
bridges []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 cmd := command.(type) {
|
|
case commands.PairDevice:
|
|
// Only mill
|
|
if _, ok := cmd.Matches("mill"); !ok {
|
|
return
|
|
}
|
|
|
|
// Run connection if needed
|
|
err := s.connect(bus, cmd.ID, &cmd.APIKey, nil)
|
|
if err != nil {
|
|
bus.RunEvent(events.DeviceFailed{
|
|
ID: cmd.ID,
|
|
Error: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
|
|
// Connection successful
|
|
bus.RunEvent(events.DeviceAccepted{
|
|
ID: cmd.ID,
|
|
APIKey: cmd.APIKey,
|
|
})
|
|
case commands.ConnectDevice:
|
|
// Connect if necessary
|
|
err := s.connect(bus, cmd.ID, &cmd.APIKey, nil)
|
|
if err != nil {
|
|
bus.RunEvent(events.DeviceFailed{
|
|
ID: cmd.ID,
|
|
Error: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
case commands.SetState:
|
|
err := s.connect(bus, cmd.ID, nil, &cmd.State)
|
|
if err != nil {
|
|
bus.RunEvent(events.DeviceFailed{
|
|
ID: cmd.ID,
|
|
Error: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
case commands.SetStateBatch:
|
|
for id, state := range cmd {
|
|
err := s.connect(bus, id, nil, &state)
|
|
if err != nil {
|
|
bus.RunEvent(events.DeviceFailed{
|
|
ID: id,
|
|
Error: err.Error(),
|
|
})
|
|
return
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (s *service) connect(
|
|
bus *lucifer3.EventBus,
|
|
id string,
|
|
apiKey *string,
|
|
state *device.State,
|
|
) error {
|
|
hasState := state != nil
|
|
if !hasState {
|
|
state = &device.State{}
|
|
}
|
|
|
|
// Check if connection is active
|
|
for _, bridge := range s.bridges {
|
|
// Don't block with dead bridges
|
|
if !bridge.IsStarted() {
|
|
continue
|
|
}
|
|
|
|
// Setting a dummy state to the bridge to check if it's online
|
|
bridge.SetBus(bus)
|
|
if ok := bridge.SetState(id, *state); ok {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
if apiKey == nil {
|
|
return errors.New("not connected to device " + id)
|
|
}
|
|
|
|
// Make a bridge, if not a mill ID, this will return ok false
|
|
bridge, ok := MakeBridge(id, *apiKey)
|
|
if !ok {
|
|
return nil
|
|
}
|
|
|
|
bridge.SetBus(bus)
|
|
|
|
// Start bridge, and throw error if it failed to start
|
|
bridge.Start()
|
|
if !bridge.IsStarted() {
|
|
return errors.New("failed to connect to " + id)
|
|
}
|
|
|
|
// Add bridge to lists
|
|
s.bridges = append(s.bridges, bridge)
|
|
|
|
// Update state, if needed, after first connection
|
|
if hasState {
|
|
if ok := bridge.SetState(id, *state); !ok {
|
|
return errors.New("unable to set state to " + id + " after connecting")
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|