|
|
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 }
|