Skip to content

Commit

Permalink
fix: Bug with loop detection
Browse files Browse the repository at this point in the history
Message structure was wrong
  • Loading branch information
dansimau committed Jan 20, 2025
1 parent 1757e67 commit 55cfdf2
Show file tree
Hide file tree
Showing 7 changed files with 62 additions and 58 deletions.
2 changes: 1 addition & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
cover.out
sqlite.db
sqlite.db*
45 changes: 30 additions & 15 deletions automations/sensor_lights_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,8 @@ func TestSensorTurnOnTurnOff(t *testing.T) {

// Trigger motion sensor
slog.Info("Test: Triggering motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand All @@ -60,7 +61,8 @@ func TestSensorTurnOnTurnOff(t *testing.T) {

// Clear motion sensor
slog.Info("Test: Clearing motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand Down Expand Up @@ -117,7 +119,8 @@ func TestSensorTurnOnTurnOffWithDimming(t *testing.T) {

// Trigger motion sensor
slog.Info("Test: Triggering motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand All @@ -136,7 +139,8 @@ func TestSensorTurnOnTurnOffWithDimming(t *testing.T) {

// Clear motion sensor
slog.Info("Test: Clearing motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand Down Expand Up @@ -203,7 +207,8 @@ func TestSensorLightsTurnOnAfterDimming(t *testing.T) {

// Trigger motion sensor
slog.Info("Test: Triggering motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand All @@ -222,7 +227,8 @@ func TestSensorLightsTurnOnAfterDimming(t *testing.T) {

// Clear motion sensor
slog.Info("Test: Clearing motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand Down Expand Up @@ -250,7 +256,8 @@ func TestSensorLightsTurnOnAfterDimming(t *testing.T) {

// Trigger motion sensor again
slog.Info("Test: Triggering motion sensor again")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand Down Expand Up @@ -299,7 +306,8 @@ func TestSensorDoesntOverrideManuallySetBrightness(t *testing.T) {

// Trigger motion sensor
slog.Info("Test: Triggering motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand All @@ -318,7 +326,8 @@ func TestSensorDoesntOverrideManuallySetBrightness(t *testing.T) {

// Light was dimmed manually
slog.Info("Test: Dimming light manually")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testLight.GetID(),
NewState: &homeassistant.State{
Expand All @@ -333,7 +342,8 @@ func TestSensorDoesntOverrideManuallySetBrightness(t *testing.T) {

// Trigger motion sensor
slog.Info("Test: Triggering motion sensor again")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand Down Expand Up @@ -390,7 +400,8 @@ func TestHumanOverride(t *testing.T) {

// Trigger motion sensor
slog.Info("Test: Triggering motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand All @@ -409,7 +420,8 @@ func TestHumanOverride(t *testing.T) {

// Human presses button manually, triggering human override
slog.Info("Test: Light set manually")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testLight.GetID(),
NewState: &homeassistant.State{
Expand All @@ -421,7 +433,8 @@ func TestHumanOverride(t *testing.T) {

// Motion sensor is cleared, but it should be ignored because of human override
slog.Info("Test: Clearing motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand Down Expand Up @@ -454,7 +467,8 @@ func TestHumanOverride(t *testing.T) {

// Trigger motion sensor is triggered and cleared again
slog.Info("Test: Triggering motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand All @@ -471,7 +485,8 @@ func TestHumanOverride(t *testing.T) {
})

slog.Info("Test: Clearing motion sensor")
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: testSensor.GetID(),
NewState: &homeassistant.State{
Expand Down
4 changes: 2 additions & 2 deletions connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,8 @@ func (h *Connection) StateChangeEvent(event hassws.EventMessage) {
})

// Prevent loops by not running automations that originate from hal
if event.Context.UserID == h.config.HomeAssistant.UserID {
slog.Debug("Skipping automation to prevent loop", "EntityID", event.Event.EventData.EntityID)
if event.Event.Context.UserID == h.config.HomeAssistant.UserID {
slog.Debug("Skipping automation from own action", "EntityID", event.Event.EventData.EntityID)

return
}
Expand Down
15 changes: 9 additions & 6 deletions connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"testing"

"github.com/dansimau/hal"
"github.com/dansimau/hal/hassws"
"github.com/dansimau/hal/homeassistant"
"github.com/dansimau/hal/testutil"
"github.com/davecgh/go-spew/spew"
Expand All @@ -22,7 +21,8 @@ func TestConnection(t *testing.T) {
conn.RegisterEntities(entity)

// Send state change event
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: "test.entity",
NewState: &homeassistant.State{State: "on"},
Expand Down Expand Up @@ -57,17 +57,20 @@ func TestLoopProtection(t *testing.T) {
)

// This one should be ignored because it is from the same user
server.SendStateChangeEventWithContext(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: "test.entity",
NewState: &homeassistant.State{State: "off"},
},
}, hassws.EventMessageContext{
UserID: testutil.TestUserID,
Context: homeassistant.EventMessageContext{
UserID: testutil.TestUserID,
},
})

// This one should cause the automation to be triggered
server.SendStateChangeEvent(homeassistant.Event{
server.SendEvent(homeassistant.Event{
EventType: "state_changed",
EventData: homeassistant.EventData{
EntityID: "test.entity",
NewState: &homeassistant.State{State: "on"},
Expand Down
16 changes: 3 additions & 13 deletions hassws/message_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,19 +50,9 @@ type AuthResponse struct {
}

type EventMessage struct {
ID int `json:"id"`
Type MessageType `json:"type"` // "event"
Event homeassistant.Event `json:"event"`
EventType MessageType `json:"event_type"`
TimeFired string `json:"time_fired"`
Origin string `json:"origin"`
Context EventMessageContext `json:"context"`
}

type EventMessageContext struct {
ID string `json:"id"`
ParentID string `json:"parent_id"`
UserID string `json:"user_id"`
ID int `json:"id"`
Type MessageType `json:"type"` // "event"
Event homeassistant.Event `json:"event"`
}

type subscribeEventsRequest struct {
Expand Down
26 changes: 6 additions & 20 deletions hassws/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ func (s *Server) listen() {

// Generate state updates
for _, entityID := range entityIDs {
s.SendStateChangeEvent(homeassistant.Event{
s.SendEvent(homeassistant.Event{
EventData: homeassistant.EventData{
EntityID: entityID,
NewState: &homeassistant.State{
Expand Down Expand Up @@ -265,27 +265,13 @@ func (s *Server) MessagesSent() [][]byte {
return s.messagesSent
}

// SendStateChangeEvent sends a state change event to the server.
func (s *Server) SendStateChangeEvent(event homeassistant.Event) {
// SendEvent sends a state change event to the server.
func (s *Server) SendEvent(event homeassistant.Event) {
for _, id := range s.subscribers {
s.SendMessage(EventMessage{
ID: id,
Type: MessageTypeEvent,
EventType: MessageTypeStateChanged,
Event: event,
})
}
}

// SendStateChangeEventWithContext sends a state change event to the server.
func (s *Server) SendStateChangeEventWithContext(event homeassistant.Event, context EventMessageContext) {
for _, id := range s.subscribers {
s.SendMessage(EventMessage{
ID: id,
Type: MessageTypeEvent,
EventType: MessageTypeStateChanged,
Event: event,
Context: context,
ID: id,
Type: MessageTypeEvent,
Event: event,
})
}
}
12 changes: 11 additions & 1 deletion homeassistant/events.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,17 @@
package homeassistant

type Event struct {
EventData EventData `json:"data"`
EventData EventData `json:"data"`
EventType string `json:"event_type"`
TimeFired string `json:"time_fired"`
Origin string `json:"origin"`
Context EventMessageContext `json:"context"`
}

type EventMessageContext struct {
ID string `json:"id"`
ParentID string `json:"parent_id"`
UserID string `json:"user_id"`
}

type EventData struct {
Expand Down

0 comments on commit 55cfdf2

Please sign in to comment.