mirror of
https://github.com/Xevion/go-ha.git
synced 2025-12-06 01:15:10 -06:00
Don't exit the app on connection failures, expose the error in the API
This commit is contained in:
13
app.go
13
app.go
@@ -15,6 +15,9 @@ import (
|
|||||||
ws "saml.dev/gome-assistant/internal/websocket"
|
ws "saml.dev/gome-assistant/internal/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// Returned by NewApp() if authentication fails
|
||||||
|
var ErrInvalidToken = ws.ErrInvalidToken
|
||||||
|
|
||||||
type App struct {
|
type App struct {
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
ctxCancel context.CancelFunc
|
ctxCancel context.CancelFunc
|
||||||
@@ -77,7 +80,7 @@ type NewAppRequest struct {
|
|||||||
NewApp establishes the websocket connection and returns an object
|
NewApp establishes the websocket connection and returns an object
|
||||||
you can use to register schedules and listeners.
|
you can use to register schedules and listeners.
|
||||||
*/
|
*/
|
||||||
func NewApp(request NewAppRequest) *App {
|
func NewApp(request NewAppRequest) (*App, error) {
|
||||||
if request.IpAddress == "" || request.HAAuthToken == "" || request.HomeZoneEntityId == "" {
|
if request.IpAddress == "" || request.HAAuthToken == "" || request.HomeZoneEntityId == "" {
|
||||||
log.Fatalln("IpAddress, HAAuthToken, and HomeZoneEntityId are all required arguments in NewAppRequest.")
|
log.Fatalln("IpAddress, HAAuthToken, and HomeZoneEntityId are all required arguments in NewAppRequest.")
|
||||||
}
|
}
|
||||||
@@ -85,7 +88,11 @@ func NewApp(request NewAppRequest) *App {
|
|||||||
if port == "" {
|
if port == "" {
|
||||||
port = "8123"
|
port = "8123"
|
||||||
}
|
}
|
||||||
conn, ctx, ctxCancel := ws.SetupConnection(request.IpAddress, port, request.HAAuthToken)
|
conn, ctx, ctxCancel, err := ws.SetupConnection(request.IpAddress, port, request.HAAuthToken)
|
||||||
|
|
||||||
|
if conn == nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
httpClient := http.NewHttpClient(request.IpAddress, port, request.HAAuthToken)
|
httpClient := http.NewHttpClient(request.IpAddress, port, request.HAAuthToken)
|
||||||
|
|
||||||
@@ -105,7 +112,7 @@ func NewApp(request NewAppRequest) *App {
|
|||||||
intervals: pq.New(),
|
intervals: pq.New(),
|
||||||
entityListeners: map[string][]*EntityListener{},
|
entityListeners: map[string][]*EntityListener{},
|
||||||
eventListeners: map[string][]*EventListener{},
|
eventListeners: map[string][]*EventListener{},
|
||||||
}
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (a *App) Cleanup() {
|
func (a *App) Cleanup() {
|
||||||
|
|||||||
@@ -10,11 +10,16 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
app := ga.NewApp(ga.NewAppRequest{
|
app, err := ga.NewApp(ga.NewAppRequest{
|
||||||
IpAddress: "192.168.86.67", // Replace with your Home Assistant IP Address
|
IpAddress: "192.168.86.67", // Replace with your Home Assistant IP Address
|
||||||
HAAuthToken: os.Getenv("HA_AUTH_TOKEN"),
|
HAAuthToken: os.Getenv("HA_AUTH_TOKEN"),
|
||||||
HomeZoneEntityId: "zone.home",
|
HomeZoneEntityId: "zone.home",
|
||||||
})
|
})
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("Error connecting to HASS:", err)
|
||||||
|
}
|
||||||
|
|
||||||
defer app.Cleanup()
|
defer app.Cleanup()
|
||||||
|
|
||||||
pantryDoor := ga.
|
pantryDoor := ga.
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ import (
|
|||||||
i "saml.dev/gome-assistant/internal"
|
i "saml.dev/gome-assistant/internal"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
var (
|
||||||
|
ErrInvalidToken = errors.New("invalid authentication token")
|
||||||
|
)
|
||||||
|
|
||||||
type AuthMessage struct {
|
type AuthMessage struct {
|
||||||
MsgType string `json:"type"`
|
MsgType string `json:"type"`
|
||||||
AccessToken string `json:"access_token"`
|
AccessToken string `json:"access_token"`
|
||||||
@@ -47,7 +51,7 @@ func ReadMessage(conn *websocket.Conn, ctx context.Context) ([]byte, error) {
|
|||||||
return msg, nil
|
return msg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SetupConnection(ip, port, authToken string) (*websocket.Conn, context.Context, context.CancelFunc) {
|
func SetupConnection(ip, port, authToken string) (*websocket.Conn, context.Context, context.CancelFunc, error) {
|
||||||
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*3)
|
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||||
|
|
||||||
// Init websocket connection
|
// Init websocket connection
|
||||||
@@ -55,31 +59,35 @@ func SetupConnection(ip, port, authToken string) (*websocket.Conn, context.Conte
|
|||||||
conn, _, err := dialer.DialContext(ctx, fmt.Sprintf("ws://%s:%s/api/websocket", ip, port), nil)
|
conn, _, err := dialer.DialContext(ctx, fmt.Sprintf("ws://%s:%s/api/websocket", ip, port), nil)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxCancel()
|
ctxCancel()
|
||||||
log.Fatalf("ERROR: Failed to connect to websocket at ws://%s:%s/api/websocket. Check IP address and port\n", ip, port)
|
log.Printf("ERROR: Failed to connect to websocket at ws://%s:%s/api/websocket. Check IP address and port\n", ip, port)
|
||||||
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Read auth_required message
|
// Read auth_required message
|
||||||
_, err = ReadMessage(conn, ctx)
|
_, err = ReadMessage(conn, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxCancel()
|
ctxCancel()
|
||||||
log.Fatalf("Unknown error creating websocket client\n")
|
log.Printf("Unknown error creating websocket client\n")
|
||||||
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Send auth message
|
// Send auth message
|
||||||
err = SendAuthMessage(conn, ctx, authToken)
|
err = SendAuthMessage(conn, ctx, authToken)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxCancel()
|
ctxCancel()
|
||||||
log.Fatalf("Unknown error creating websocket client\n")
|
log.Printf("Unknown error creating websocket client\n")
|
||||||
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Verify auth message was successful
|
// Verify auth message was successful
|
||||||
err = VerifyAuthResponse(conn, ctx)
|
err = VerifyAuthResponse(conn, ctx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
ctxCancel()
|
ctxCancel()
|
||||||
log.Fatalf("ERROR: Auth token is invalid. Please double check it or create a new token in your Home Assistant profile\n")
|
log.Printf("ERROR: Auth token is invalid. Please double check it or create a new token in your Home Assistant profile\n")
|
||||||
|
return nil, nil, nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return conn, ctx, ctxCancel
|
return conn, ctx, ctxCancel, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func SendAuthMessage(conn *websocket.Conn, ctx context.Context, token string) error {
|
func SendAuthMessage(conn *websocket.Conn, ctx context.Context, token string) error {
|
||||||
@@ -105,7 +113,7 @@ func VerifyAuthResponse(conn *websocket.Conn, ctx context.Context) error {
|
|||||||
json.Unmarshal(msg, &authResp)
|
json.Unmarshal(msg, &authResp)
|
||||||
// log.Println(authResp.MsgType)
|
// log.Println(authResp.MsgType)
|
||||||
if authResp.MsgType != "auth_ok" {
|
if authResp.MsgType != "auth_ok" {
|
||||||
return errors.New("invalid auth token")
|
return ErrInvalidToken
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
|
|||||||
Reference in New Issue
Block a user