diff --git a/app.go b/app.go index b63373c..464be37 100644 --- a/app.go +++ b/app.go @@ -6,10 +6,11 @@ import ( "os" "time" + "github.com/gorilla/websocket" + "github.com/saml-dev/gome-assistant/internal" "github.com/saml-dev/gome-assistant/internal/http" pq "github.com/saml-dev/gome-assistant/internal/priorityqueue" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) type app struct { @@ -21,8 +22,9 @@ type app struct { service *Service state *State - schedules pq.PriorityQueue - entityListeners []entityListener + schedules pq.PriorityQueue + entityListeners map[string][]entityListener + entityListenerIds map[int64]entityListenerCallback } /* @@ -30,8 +32,8 @@ NewApp establishes the websocket connection and returns an object you can use to register schedules and listeners. */ func NewApp(connString string) app { - token := os.Getenv("AUTH_TOKEN") - conn, ctx, ctxCancel := ws.SetupConnection(connString) + token := os.Getenv("HA_AUTH_TOKEN") + conn, ctx, ctxCancel := ws.SetupConnection(connString, token) httpClient := http.NewHttpClient(connString, token) @@ -39,14 +41,15 @@ func NewApp(connString string) app { state := NewState(httpClient) return app{ - conn: conn, - ctx: ctx, - ctxCancel: ctxCancel, - httpClient: httpClient, - service: service, - state: state, - schedules: pq.New(), - entityListeners: []entityListener{}, + conn: conn, + ctx: ctx, + ctxCancel: ctxCancel, + httpClient: httpClient, + service: service, + state: state, + schedules: pq.New(), + entityListeners: map[string][]entityListener{}, + entityListenerIds: map[int64]entityListenerCallback{}, } } @@ -83,11 +86,48 @@ func (a *app) RegisterSchedule(s schedule) { a.schedules.Insert(s, float64(startTime.Unix())) // TODO: this blows up because schedule can't be used as key for map in prio queue lib. Just copy/paste and tweak as needed } -func (a *app) Start() { +func (a *app) RegisterEntityListener(el entityListener) { + for _, entity := range el.entityIds { + id := internal.GetId() + subscribeTriggerMsg := subscribeMsg{ + Id: id, + Type: "subscribe_trigger", + Trigger: subscribeMsgTrigger{ + Platform: "state", + EntityId: entity, + }, + } + if el.fromState != "" { + subscribeTriggerMsg.Trigger.From = el.fromState + } + if el.toState != "" { + subscribeTriggerMsg.Trigger.To = el.toState + } + log.Default().Println(subscribeTriggerMsg) + ws.WriteMessage(subscribeTriggerMsg, a.conn, a.ctx) + msg, _ := ws.ReadMessage(a.conn, a.ctx) + log.Default().Println(string(msg)) + a.entityListenerIds[id] = el.callback + } +} + +func (a *app) Start() { // schedules - if a.schedules.Len() != 0 { - go RunSchedules(a) + go RunSchedules(a) + + // entity listeners + elChan := make(chan ws.ChanMsg) + go ws.ListenWebsocket(a.conn, a.ctx, elChan) + + log.Default().Println(a.entityListenerIds) + var msg ws.ChanMsg + for { + msg = <-elChan + log.Default().Println(string(msg.Raw)) + if callback, ok := a.entityListenerIds[msg.Id]; ok { + log.Default().Println(msg, callback) + } } // NOTE:should the prio queue and websocket listener both write to a channel or something? diff --git a/cmd/main/testing.go b/cmd/main/testing.go index be9a762..8486e4d 100644 --- a/cmd/main/testing.go +++ b/cmd/main/testing.go @@ -16,13 +16,15 @@ func main() { app.RegisterSchedule(s) app.RegisterSchedule(s2) app.RegisterSchedule(s3) - app.Start() simpleListener := ga.EntityListenerBuilder(). - EntityIds("light.lights"). + EntityIds("light.entryway_lamp"). Call(listenerCB). - OnlyBetween(ga.TimeOfDay(22, 00), ga.TimeOfDay(07, 00)) - log.Println(simpleListener) + // OnlyBetween(ga.TimeOfDay(22, 00), ga.TimeOfDay(07, 00)). + Build() + app.RegisterEntityListener(simpleListener) + + app.Start() log.Println(s) log.Println(s2) @@ -32,17 +34,18 @@ func lightsOut(service *ga.Service, state *ga.State) { // service.InputDatetime.Set("input_datetime.garage_last_triggered_ts", time.Now()) // service.HomeAssistant.Toggle("group.living_room_lamps", map[string]any{"brightness_pct": 100}) // service.Light.Toggle("light.entryway_lamp", map[string]any{"brightness_pct": 100}) - // service.Switch.Toggle("switch.espurna_sunroom_lamp") - log.Default().Println("A") + service.HomeAssistant.Toggle("light.el_gato_key_lights") + // service.HomeAssistant.Toggle("light.entryway_lamp") + // log.Default().Println("A") } func cool(service *ga.Service, state *ga.State) { // service.Light.TurnOn("light.entryway_lamp") - log.Default().Println("B") + // log.Default().Println("B") } func c(service *ga.Service, state *ga.State) { - log.Default().Println("C") + // log.Default().Println("C") } -func listenerCB(service *ga.Service, data *ga.Data) {} +func listenerCB(service *ga.Service, data *ga.EntityData) {} diff --git a/entitylistener.go b/entitylistener.go index fab9ea3..2428461 100644 --- a/entitylistener.go +++ b/entitylistener.go @@ -15,24 +15,49 @@ type entityListener struct { err error } -type entityListenerCallback func(*Service, *Data) +type entityListenerCallback func(*Service, *EntityData) -type Data struct{} - -func (b elBuilder3) OnlyBetween(start time.Duration, end time.Duration) elBuilder3 { - b.entityListener.betweenStart = start - b.entityListener.betweenEnd = end - return b +// TODO: use this to flatten json sent from HA for trigger event +type EntityData struct { + TriggerEntityId string + FromState string + FromAttributes map[string]any + ToState string + ToAttributes map[string]any + LastChanged time.Time } -func (b elBuilder3) FromState(s string) elBuilder3 { - b.entityListener.fromState = s - return b +type triggerMsg struct { + Id int64 `json:"id"` + Type string `json:"type"` + Event struct { + Variables struct { + Trigger struct { + EntityId string `json:"entity_id"` + FromState triggerMsgState `json:"from_state"` + ToState triggerMsgState `json:"to_state"` + } + } `json:"variables"` + } `json:"event"` } -func (b elBuilder3) ToState(s string) elBuilder3 { - b.entityListener.toState = s - return b +type triggerMsgState struct { + State string `json:"state"` + Attributes map[string]any `json:"attributes"` + LastChanged string `json:"last_changed"` +} + +type subscribeMsg struct { + Id int64 `json:"id"` + Type string `json:"type"` + Trigger subscribeMsgTrigger `json:"trigger"` +} + +type subscribeMsgTrigger struct { + Platform string `json:"platform"` + EntityId string `json:"entity_id"` + From string `json:"from"` + To string `json:"to"` } /* Builders */ @@ -68,3 +93,23 @@ func (b elBuilder2) Call(callback entityListenerCallback) elBuilder3 { type elBuilder3 struct { entityListener } + +func (b elBuilder3) OnlyBetween(start time.Duration, end time.Duration) elBuilder3 { + b.entityListener.betweenStart = start + b.entityListener.betweenEnd = end + return b +} + +func (b elBuilder3) FromState(s string) elBuilder3 { + b.entityListener.fromState = s + return b +} + +func (b elBuilder3) ToState(s string) elBuilder3 { + b.entityListener.toState = s + return b +} + +func (b elBuilder3) Build() entityListener { + return b.entityListener +} diff --git a/go.mod b/go.mod index b875865..a20c756 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,4 @@ module github.com/saml-dev/gome-assistant go 1.19 -require nhooyr.io/websocket v1.8.7 - -require github.com/klauspost/compress v1.10.3 // indirect +require github.com/gorilla/websocket v1.5.0 diff --git a/go.sum b/go.sum index f36a934..e5a03d4 100644 --- a/go.sum +++ b/go.sum @@ -1,60 +1,2 @@ -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= -github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= -github.com/gin-gonic/gin v1.6.3 h1:ahKqKTFpO5KTPHxWZjEdPScmYaGtLo8Y4DMHoEsnp14= -github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M= -github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4= -github.com/go-playground/locales v0.13.0 h1:HyWk6mgj5qFqCT5fjGBuRArbVDfE4hi8+e8ceBS/t7Q= -github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8= -github.com/go-playground/universal-translator v0.17.0 h1:icxd5fm+REJzpZx7ZfpaD876Lmtgy7VtROAbHHXk8no= -github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA= -github.com/go-playground/validator/v10 v10.2.0 h1:KgJ0snyC2R9VXYN2rneOtQcw5aHQB1Vv0sFl1UcHBOY= -github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee h1:s+21KNqlpePfkah2I+gwHF8xmJWRjooY+5248k6m4A0= -github.com/gobwas/httphead v0.0.0-20180130184737-2c6c146eadee/go.mod h1:L0fX3K22YWvt/FAX9NnzrNzcI4wNYi9Yku4O0LKYflo= -github.com/gobwas/pool v0.2.0 h1:QEmUOlnSjWtnpRGHF3SauEiOsy82Cup83Vf2LcMlnc8= -github.com/gobwas/pool v0.2.0/go.mod h1:q8bcK0KcYlCgd9e7WYLm9LpyS+YeLd8JVDW6WezmKEw= -github.com/gobwas/ws v1.0.2 h1:CoAavW/wd/kulfZmSIBt6p24n4j7tHgNVCjsfHVNUbo= -github.com/gobwas/ws v1.0.2/go.mod h1:szmBTxLgaFppYjEmNtny/v3w89xOydFnnZMcgRRu/EM= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.3.5 h1:F768QJ1E9tib+q5Sc8MkdJi1RxLTbRcTf8LJV56aRls= -github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk= -github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= -github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= -github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= -github.com/gorilla/websocket v1.4.1 h1:q7AeDBpnBk8AogcD4DSag/Ukw/KV+YhzLj2bP5HvKCM= -github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= -github.com/json-iterator/go v1.1.9 h1:9yzud/Ht36ygwatGx56VwCZtlI/2AD15T1X2sjSuGns= -github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= -github.com/klauspost/compress v1.10.3 h1:OP96hzwJVBIHYU52pVTI6CczrxPvrGfgqF9N5eTO0Q8= -github.com/klauspost/compress v1.10.3/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs= -github.com/leodido/go-urn v1.2.0 h1:hpXL4XnriNwQ/ABnpepYM/1vCLWNDfUNts8dX3xTG6Y= -github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII= -github.com/mattn/go-isatty v0.0.12 h1:wuysRhFDzyxgEmMf5xjvJ2M9dZoWAXNNr5LSBS7uHXY= -github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= -github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= -github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42 h1:vEOn+mP2zCOVzKckCZy6YsCtDblrpj/w7B9nxGNELpg= -golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4= -golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -nhooyr.io/websocket v1.8.7 h1:usjR2uOr/zjjkVMy0lW+PPohFok7PCow5sDjLgX4P4g= -nhooyr.io/websocket v1.8.7/go.mod h1:B70DZP8IakI65RVQ51MsWP/8jndNma26DVA/nFSCgW0= +github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc= +github.com/gorilla/websocket v1.5.0/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE= diff --git a/internal/internal.go b/internal/internal.go new file mode 100644 index 0000000..32e5ad2 --- /dev/null +++ b/internal/internal.go @@ -0,0 +1,8 @@ +package internal + +var id int64 = 0 + +func GetId() int64 { + id += 1 + return id +} diff --git a/internal/services/homeassistant.go b/internal/services/homeassistant.go index 7449cb6..a27f26c 100644 --- a/internal/services/homeassistant.go +++ b/internal/services/homeassistant.go @@ -3,8 +3,8 @@ package services import ( "context" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) type HomeAssistant struct { @@ -36,6 +36,16 @@ func (ha *HomeAssistant) Toggle(entityId string, serviceData ...map[string]any) } ws.WriteMessage(req, ha.conn, ha.ctx) + // msg, _ := ws.ReadMessage(ha.conn, ha.ctx) + // log.Default().Println(string(msg)) + // msg, _ = ws.ReadMessage(ha.conn, ha.ctx) + // log.Default().Println(string(msg)) + // msg, _ = ws.ReadMessage(ha.conn, ha.ctx) + // log.Default().Println(string(msg)) + // msg, _ = ws.ReadMessage(ha.conn, ha.ctx) + // log.Default().Println(string(msg)) + // msg, _ = ws.ReadMessage(ha.conn, ha.ctx) + // log.Default().Println(string(msg)) } func (ha *HomeAssistant) TurnOff(entityId string) { diff --git a/internal/services/input_boolean.go b/internal/services/input_boolean.go index 0582fbe..9b1c64d 100644 --- a/internal/services/input_boolean.go +++ b/internal/services/input_boolean.go @@ -3,8 +3,8 @@ package services import ( "context" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) /* Structs */ diff --git a/internal/services/input_button.go b/internal/services/input_button.go index f7624d4..8b0783c 100644 --- a/internal/services/input_button.go +++ b/internal/services/input_button.go @@ -3,8 +3,8 @@ package services import ( "context" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) /* Structs */ diff --git a/internal/services/input_datetime.go b/internal/services/input_datetime.go index 5967629..7134532 100644 --- a/internal/services/input_datetime.go +++ b/internal/services/input_datetime.go @@ -5,8 +5,8 @@ import ( "fmt" "time" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) /* Structs */ diff --git a/internal/services/input_number.go b/internal/services/input_number.go index d89b11e..fa87bb6 100644 --- a/internal/services/input_number.go +++ b/internal/services/input_number.go @@ -3,8 +3,8 @@ package services import ( "context" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) /* Structs */ diff --git a/internal/services/input_text.go b/internal/services/input_text.go index 0cdec0a..5ec00b8 100644 --- a/internal/services/input_text.go +++ b/internal/services/input_text.go @@ -3,8 +3,8 @@ package services import ( "context" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) /* Structs */ diff --git a/internal/services/light.go b/internal/services/light.go index ab59241..e9e4845 100644 --- a/internal/services/light.go +++ b/internal/services/light.go @@ -3,8 +3,8 @@ package services import ( "context" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) /* Structs */ diff --git a/internal/services/lock.go b/internal/services/lock.go index 62fe874..4f8143b 100644 --- a/internal/services/lock.go +++ b/internal/services/lock.go @@ -3,8 +3,8 @@ package services import ( "context" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) /* Structs */ diff --git a/internal/services/services.go b/internal/services/services.go index b639f7e..d5da2fc 100644 --- a/internal/services/services.go +++ b/internal/services/services.go @@ -3,8 +3,10 @@ package services import ( "context" "fmt" + "log" - "nhooyr.io/websocket" + "github.com/gorilla/websocket" + "github.com/saml-dev/gome-assistant/internal" ) func BuildService[ @@ -32,9 +34,9 @@ type BaseServiceRequest struct { } `json:"target,omitempty"` } -var id int64 = 1 - func NewBaseServiceRequest(entityId string) BaseServiceRequest { + id := internal.GetId() + log.Default().Println("service id", id) bsr := BaseServiceRequest{ Id: fmt.Sprint(id), RequestType: "call_service", diff --git a/internal/services/switch.go b/internal/services/switch.go index 78dfb46..3f64403 100644 --- a/internal/services/switch.go +++ b/internal/services/switch.go @@ -3,8 +3,8 @@ package services import ( "context" + "github.com/gorilla/websocket" ws "github.com/saml-dev/gome-assistant/internal/websocket" - "nhooyr.io/websocket" ) /* Structs */ diff --git a/internal/websocket/reader.go b/internal/websocket/reader.go index 06e0173..3d87604 100644 --- a/internal/websocket/reader.go +++ b/internal/websocket/reader.go @@ -2,15 +2,35 @@ package websocket import ( "context" + "encoding/json" - "nhooyr.io/websocket" + "github.com/gorilla/websocket" ) type BaseMessage struct { - MsgType string `json:"type"` - Other any + Type string `json:"type"` + Id int64 `json:"id"` } -func ReadWebsocket(ws *websocket.Conn, ctx context.Context) { - +type ChanMsg struct { + Id int64 + Type string + Raw []byte +} + +func ListenWebsocket(conn *websocket.Conn, ctx context.Context, c chan ChanMsg) { + for { + // log.Default().Println("reading message") + bytes, _ := ReadMessage(conn, ctx) + base := BaseMessage{} + json.Unmarshal(bytes, &base) + + chanMsg := ChanMsg{ + Type: base.Type, + Id: base.Id, + Raw: bytes, + } + + c <- chanMsg + } } diff --git a/internal/websocket/websocket.go b/internal/websocket/websocket.go index 1e4d16d..ba0fdb7 100644 --- a/internal/websocket/websocket.go +++ b/internal/websocket/websocket.go @@ -10,10 +10,9 @@ import ( "errors" "fmt" "log" - "os" "time" - "nhooyr.io/websocket" + "github.com/gorilla/websocket" ) type AuthMessage struct { @@ -28,7 +27,7 @@ func WriteMessage[T any](msg T, conn *websocket.Conn, ctx context.Context) error return err } - err = conn.Write(ctx, websocket.MessageText, msgJson) + err = conn.WriteMessage(websocket.TextMessage, msgJson) if err != nil { return err } @@ -36,19 +35,20 @@ func WriteMessage[T any](msg T, conn *websocket.Conn, ctx context.Context) error return nil } -func ReadMessage(conn *websocket.Conn, ctx context.Context) (string, error) { - _, msg, err := conn.Read(ctx) +func ReadMessage(conn *websocket.Conn, ctx context.Context) ([]byte, error) { + _, msg, err := conn.ReadMessage() if err != nil { - return "", err + return []byte{}, err } - return string(msg), nil + return msg, nil } -func SetupConnection(connString string) (*websocket.Conn, context.Context, context.CancelFunc) { +func SetupConnection(connString string, authToken string) (*websocket.Conn, context.Context, context.CancelFunc) { ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*3) // Init websocket connection - conn, _, err := websocket.Dial(ctx, fmt.Sprintf("ws://%s/api/websocket", connString), nil) + dialer := websocket.DefaultDialer + conn, _, err := dialer.DialContext(ctx, fmt.Sprintf("ws://%s/api/websocket", connString), nil) if err != nil { ctxCancel() log.Fatalf("ERROR: Failed to connect to websocket at ws://%s/api/websocket. Check IP address and port\n", connString) @@ -62,13 +62,13 @@ func SetupConnection(connString string) (*websocket.Conn, context.Context, conte } // Send auth message - err = SendAuthMessage(conn, ctx) + err = SendAuthMessage(conn, ctx, authToken) if err != nil { ctxCancel() log.Fatalln("Unknown error creating websocket client") } - // Verify auth message + // Verify auth message was successful err = VerifyAuthResponse(conn, ctx) if err != nil { ctxCancel() @@ -78,8 +78,7 @@ func SetupConnection(connString string) (*websocket.Conn, context.Context, conte return conn, ctx, ctxCancel } -func SendAuthMessage(conn *websocket.Conn, ctx context.Context) error { - token := os.Getenv("AUTH_TOKEN") +func SendAuthMessage(conn *websocket.Conn, ctx context.Context, token string) error { err := WriteMessage(AuthMessage{MsgType: "auth", AccessToken: token}, conn, ctx) if err != nil { return err @@ -93,7 +92,7 @@ type authResponse struct { } func VerifyAuthResponse(conn *websocket.Conn, ctx context.Context) error { - _, msg, err := conn.Read(ctx) + msg, err := ReadMessage(conn, ctx) if err != nil { return err } diff --git a/schedule.go b/schedule.go index 2a620ad..c11f139 100644 --- a/schedule.go +++ b/schedule.go @@ -213,6 +213,10 @@ func convertTimeOfDayToActualOffset(t timeOfDay) time.Duration { // app.Start() functions func RunSchedules(a *app) { + if a.schedules.Len() == 0 { + return + } + for { sched := popSchedule(a) // log.Default().Println(sched.realStartTime) diff --git a/service.go b/service.go index 339ab1e..a5f08fb 100644 --- a/service.go +++ b/service.go @@ -3,9 +3,9 @@ package gomeassistant import ( "context" + "github.com/gorilla/websocket" "github.com/saml-dev/gome-assistant/internal/http" "github.com/saml-dev/gome-assistant/internal/services" - "nhooyr.io/websocket" ) type Service struct {