package internal import ( "encoding/json" "log" "sync" "time" "github.com/cenkalti/backoff/v4" "github.com/jcollie/go-homeassistant" "github.com/jcollie/go-streamdeck" "github.com/pkg/errors" ) // Button . type Button interface { InitializeButton() StateChange(entityID string, state string) ButtonPressed(sd *streamdeck.StreamDeck, x int, y int, timestamp time.Time) ButtonReleased(sd *streamdeck.StreamDeck, x int, y int, timestamp time.Time) } // ButtonInfo . type ButtonInfo struct { X int Y int } var myButtons []Button type eventWatcher struct { sync.Mutex id uint64 } var theEventWatcher eventWatcher // StartWatchingEvents . func StartWatchingEvents(ha *homeassistant.Connection) error { var err error theEventWatcher.Lock() defer theEventWatcher.Unlock() if theEventWatcher.id != 0 { return errors.Errorf("we already seem to be watching events!") } theEventWatcher.id, err = ha.SubscribeToEvents("state_changed", &theEventWatcher) if err != nil { return errors.Wrap(err, "unable to subscribe to state changed events") } log.Printf("subscribe to state changed events command sent") return nil } func (e *eventWatcher) HandleResult(ha *homeassistant.Connection, subscriptionID uint64, success bool, result json.RawMessage) { log.Printf("eventwatcher result: %v %s\n", success, string(result)) } func (e *eventWatcher) HandleEvent(ha *homeassistant.Connection, subscriptionID uint64, origin string, timeFired time.Time, event *homeassistant.Event) { // fmt.Printf("%s %s %s\n", origin, event.Data.NewState.EntityID, event.Data.NewState.State) for _, m := range myButtons { m.StateChange(event.Data.NewState.EntityID, event.Data.NewState.State) } } func (e *eventWatcher) HandleClose(ha *homeassistant.Connection, id uint64) { log.Printf("home assistant closed") time.Sleep(5 * time.Second) e.id = 0 go func() { err := backoff.Retry( func() error { log.Printf("attempting to watch events") return StartWatchingEvents(ha) }, backoff.NewExponentialBackOff(), ) if err != nil { log.Printf("unable to start watching events: %+v", err) } }() } type initializeState struct { id uint64 result chan bool } // InitializeState . func InitializeState(ha *homeassistant.Connection) error { var err error var i initializeState i.result = make(chan bool) i.id, err = ha.GetStates(&i) if err != nil { return errors.Wrap(err, "unable to initialize state") } result := <-i.result if !result { return errors.Errorf("problem intiaizlizing states") } return nil } // HandleResult . func (i *initializeState) HandleResult(ha *homeassistant.Connection, id uint64, success bool, result json.RawMessage) { if !success { i.result <- false close(i.result) return } var states []homeassistant.State err := json.Unmarshal(result, &states) if err != nil { log.Printf("unable to unmarshall states: %+v", err) return } for _, state := range states { for _, m := range myButtons { m.StateChange(state.EntityID, state.State) } } i.result <- true close(i.result) } func (i *initializeState) HandleClose(ha *homeassistant.Connection, id uint64) { log.Printf("home assistant closed") time.Sleep(5 * time.Second) i.id = 0 go func() { err := backoff.Retry( func() error { log.Printf("attempting to initialize state") return InitializeState(ha) }, backoff.NewExponentialBackOff(), ) if err != nil { log.Printf("unable to initalize state: %+v", err) } }() }