Skip to content

Commit 025e711

Browse files
authored
Merge pull request #11 from saml-dev/feat--enabled/disabled
Feat--enabled/disabled
2 parents eb26a44 + 3cb9680 commit 025e711

File tree

6 files changed

+241
-19
lines changed

6 files changed

+241
-19
lines changed

listeners.go renamed to checkers.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,38 @@ func checkExceptionRanges(eList []timeRange) conditionCheck {
8686
return cc
8787
}
8888

89+
func checkEnabledEntity(s *State, eid, expectedState string, runOnNetworkError bool) conditionCheck {
90+
cc := conditionCheck{fail: false}
91+
if eid == "" || expectedState == "" {
92+
return cc
93+
}
94+
95+
matches, err := s.Equals(eid, expectedState)
96+
if err != nil {
97+
cc.fail = !runOnNetworkError
98+
return cc
99+
}
100+
101+
cc.fail = !matches
102+
return cc
103+
}
104+
105+
func checkDisabledEntity(s *State, eid, expectedState string, runOnNetworkError bool) conditionCheck {
106+
cc := conditionCheck{fail: false}
107+
if eid == "" || expectedState == "" {
108+
return cc
109+
}
110+
111+
matches, err := s.Equals(eid, expectedState)
112+
if err != nil {
113+
cc.fail = !runOnNetworkError
114+
return cc
115+
}
116+
117+
cc.fail = matches
118+
return cc
119+
}
120+
89121
func checkAllowlistDates(eList []time.Time) conditionCheck {
90122
if len(eList) == 0 {
91123
return conditionCheck{fail: false}

entitylistener.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gomeassistant
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"time"
67

78
"github.com/golang-module/carbon"
@@ -27,6 +28,13 @@ type EntityListener struct {
2728

2829
runOnStartup bool
2930
runOnStartupCompleted bool
31+
32+
enabledEntity string
33+
enabledEntityState string
34+
enabledEntityRunOnError bool
35+
disabledEntity string
36+
disabledEntityState string
37+
disabledEntityRunOnError bool
3038
}
3139

3240
type EntityListenerCallback func(*Service, *State, EntityData)
@@ -148,6 +156,40 @@ func (b elBuilder3) RunOnStartup() elBuilder3 {
148156
return b
149157
}
150158

159+
/*
160+
Enable this listener only when the current state of {entityId} matches {state}.
161+
If there is a network error while retrieving state, the listener runs if {runOnNetworkError} is true.
162+
*/
163+
func (b elBuilder3) EnabledWhen(entityId, state string, runOnNetworkError bool) elBuilder3 {
164+
if entityId == "" {
165+
panic(fmt.Sprintf("entityId is empty in EnabledWhen entityId='%s' state='%s'", entityId, state))
166+
}
167+
if b.entityListener.disabledEntity != "" {
168+
panic(fmt.Sprintf("You can't use EnabledWhen and DisabledWhen together. Error occurred while setting EnabledWhen on an entity listener with params entityId=%s state=%s runOnNetworkError=%t", entityId, state, runOnNetworkError))
169+
}
170+
b.entityListener.enabledEntity = entityId
171+
b.entityListener.enabledEntityState = state
172+
b.entityListener.enabledEntityRunOnError = runOnNetworkError
173+
return b
174+
}
175+
176+
/*
177+
Disable this listener when the current state of {entityId} matches {state}.
178+
If there is a network error while retrieving state, the listener runs if {runOnNetworkError} is true.
179+
*/
180+
func (b elBuilder3) DisabledWhen(entityId, state string, runOnNetworkError bool) elBuilder3 {
181+
if entityId == "" {
182+
panic(fmt.Sprintf("entityId is empty in EnabledWhen entityId='%s' state='%s'", entityId, state))
183+
}
184+
if b.entityListener.enabledEntity != "" {
185+
panic(fmt.Sprintf("You can't use EnabledWhen and DisabledWhen together. Error occurred while setting DisabledWhen on an entity listener with params entityId=%s state=%s runOnNetworkError=%t", entityId, state, runOnNetworkError))
186+
}
187+
b.entityListener.disabledEntity = entityId
188+
b.entityListener.disabledEntityState = state
189+
b.entityListener.disabledEntityRunOnError = runOnNetworkError
190+
return b
191+
}
192+
151193
func (b elBuilder3) Build() EntityListener {
152194
return b.entityListener
153195
}
@@ -195,6 +237,12 @@ func callEntityListeners(app *App, msgBytes []byte) {
195237
if c := checkExceptionRanges(l.exceptionRanges); c.fail {
196238
continue
197239
}
240+
if c := checkEnabledEntity(app.state, l.enabledEntity, l.enabledEntityState, l.enabledEntityRunOnError); c.fail {
241+
continue
242+
}
243+
if c := checkDisabledEntity(app.state, l.disabledEntity, l.disabledEntityState, l.disabledEntityRunOnError); c.fail {
244+
continue
245+
}
198246

199247
entityData := EntityData{
200248
TriggerEntityId: eid,

eventListener.go

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package gomeassistant
22

33
import (
44
"encoding/json"
5+
"fmt"
56
"time"
67

78
"github.com/golang-module/carbon"
@@ -19,6 +20,13 @@ type EventListener struct {
1920

2021
exceptionDates []time.Time
2122
exceptionRanges []timeRange
23+
24+
enabledEntity string
25+
enabledEntityState string
26+
enabledEntityRunOnError bool
27+
disabledEntity string
28+
disabledEntityState string
29+
disabledEntityRunOnError bool
2230
}
2331

2432
type EventListenerCallback func(*Service, *State, EventData)
@@ -90,6 +98,40 @@ func (b eventListenerBuilder3) ExceptionRange(start, end time.Time) eventListene
9098
return b
9199
}
92100

101+
/*
102+
Enable this listener only when the current state of {entityId} matches {state}.
103+
If there is a network error while retrieving state, the listener runs if {runOnNetworkError} is true.
104+
*/
105+
func (b eventListenerBuilder3) EnabledWhen(entityId, state string, runOnNetworkError bool) eventListenerBuilder3 {
106+
if entityId == "" {
107+
panic(fmt.Sprintf("entityId is empty in eventListener EnabledWhen entityId='%s' state='%s' runOnNetworkError='%t'", entityId, state, runOnNetworkError))
108+
}
109+
if b.eventListener.disabledEntity != "" {
110+
panic(fmt.Sprintf("You can't use EnabledWhen and DisabledWhen together. Error occurred while setting EnabledWhen entityId=%s state=%s runOnNetworkError=%t", entityId, state, runOnNetworkError))
111+
}
112+
b.eventListener.enabledEntity = entityId
113+
b.eventListener.enabledEntityState = state
114+
b.eventListener.enabledEntityRunOnError = runOnNetworkError
115+
return b
116+
}
117+
118+
/*
119+
Disable this listener when the current state of {entityId} matches {state}.
120+
If there is a network error while retrieving state, the listener runs if {runOnNetworkError} is true.
121+
*/
122+
func (b eventListenerBuilder3) DisabledWhen(entityId, state string, runOnNetworkError bool) eventListenerBuilder3 {
123+
if entityId == "" {
124+
panic(fmt.Sprintf("entityId is empty in eventListener EnabledWhen entityId='%s' state='%s' runOnNetworkError='%t'", entityId, state, runOnNetworkError))
125+
}
126+
if b.eventListener.enabledEntity != "" {
127+
panic(fmt.Sprintf("You can't use EnabledWhen and DisabledWhen together. Error occurred while setting DisabledWhen entityId=%s state=%s runOnNetworkError=%t", entityId, state, runOnNetworkError))
128+
}
129+
b.eventListener.disabledEntity = entityId
130+
b.eventListener.disabledEntityState = state
131+
b.eventListener.disabledEntityRunOnError = runOnNetworkError
132+
return b
133+
}
134+
93135
func (b eventListenerBuilder3) Build() EventListener {
94136
return b.eventListener
95137
}
@@ -124,6 +166,12 @@ func callEventListeners(app *App, msg ws.ChanMsg) {
124166
if c := checkExceptionRanges(l.exceptionRanges); c.fail {
125167
continue
126168
}
169+
if c := checkEnabledEntity(app.state, l.enabledEntity, l.enabledEntityState, l.enabledEntityRunOnError); c.fail {
170+
continue
171+
}
172+
if c := checkDisabledEntity(app.state, l.disabledEntity, l.disabledEntityState, l.disabledEntityRunOnError); c.fail {
173+
continue
174+
}
127175

128176
eventData := EventData{
129177
Type: baseEventMsg.Event.EventType,

interval.go

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,13 @@ type Interval struct {
1818

1919
exceptionDates []time.Time
2020
exceptionRanges []timeRange
21+
22+
enabledEntity string
23+
enabledEntityState string
24+
enabledEntityRunOnError bool
25+
disabledEntity string
26+
disabledEntityState string
27+
disabledEntityRunOnError bool
2128
}
2229

2330
func (i Interval) Hash() string {
@@ -69,38 +76,72 @@ func formatStartOrEndString(s TimeString, isStart bool) string {
6976
}
7077
}
7178

72-
func (sb intervalBuilder) Call(callback IntervalCallback) intervalBuilderCall {
73-
sb.interval.callback = callback
74-
return intervalBuilderCall(sb)
79+
func (ib intervalBuilder) Call(callback IntervalCallback) intervalBuilderCall {
80+
ib.interval.callback = callback
81+
return intervalBuilderCall(ib)
7582
}
7683

7784
// Takes a DurationString ("2h", "5m", etc) to set the frequency of the interval.
78-
func (sb intervalBuilderCall) Every(s DurationString) intervalBuilderEnd {
85+
func (ib intervalBuilderCall) Every(s DurationString) intervalBuilderEnd {
7986
d := internal.ParseDuration(string(s))
80-
sb.interval.frequency = d
81-
return intervalBuilderEnd(sb)
87+
ib.interval.frequency = d
88+
return intervalBuilderEnd(ib)
8289
}
8390

8491
// Takes a TimeString ("HH:MM") when this interval will start running for the day.
85-
func (sb intervalBuilderEnd) StartingAt(s TimeString) intervalBuilderEnd {
86-
sb.interval.startTime = s
87-
return sb
92+
func (ib intervalBuilderEnd) StartingAt(s TimeString) intervalBuilderEnd {
93+
ib.interval.startTime = s
94+
return ib
8895
}
8996

9097
// Takes a TimeString ("HH:MM") when this interval will stop running for the day.
91-
func (sb intervalBuilderEnd) EndingAt(s TimeString) intervalBuilderEnd {
92-
sb.interval.endTime = s
93-
return sb
98+
func (ib intervalBuilderEnd) EndingAt(s TimeString) intervalBuilderEnd {
99+
ib.interval.endTime = s
100+
return ib
94101
}
95102

96-
func (sb intervalBuilderEnd) ExceptionDates(t time.Time, tl ...time.Time) intervalBuilderEnd {
97-
sb.interval.exceptionDates = append(tl, t)
98-
return sb
103+
func (ib intervalBuilderEnd) ExceptionDates(t time.Time, tl ...time.Time) intervalBuilderEnd {
104+
ib.interval.exceptionDates = append(tl, t)
105+
return ib
99106
}
100107

101-
func (sb intervalBuilderEnd) ExceptionRange(start, end time.Time) intervalBuilderEnd {
102-
sb.interval.exceptionRanges = append(sb.interval.exceptionRanges, timeRange{start, end})
103-
return sb
108+
func (ib intervalBuilderEnd) ExceptionRange(start, end time.Time) intervalBuilderEnd {
109+
ib.interval.exceptionRanges = append(ib.interval.exceptionRanges, timeRange{start, end})
110+
return ib
111+
}
112+
113+
/*
114+
Enable this interval only when the current state of {entityId} matches {state}.
115+
If there is a network error while retrieving state, the interval runs if {runOnNetworkError} is true.
116+
*/
117+
func (ib intervalBuilderEnd) EnabledWhen(entityId, state string, runOnNetworkError bool) intervalBuilderEnd {
118+
if entityId == "" {
119+
panic(fmt.Sprintf("entityId is empty in EnabledWhen entityId='%s' state='%s'", entityId, state))
120+
}
121+
if ib.interval.disabledEntity != "" {
122+
panic(fmt.Sprintf("You can't use EnabledWhen and DisabledWhen together. Error occurred while setting EnabledWhen on an entity listener with params entityId=%s state=%s runOnNetworkError=%t", entityId, state, runOnNetworkError))
123+
}
124+
ib.interval.enabledEntity = entityId
125+
ib.interval.enabledEntityState = state
126+
ib.interval.enabledEntityRunOnError = runOnNetworkError
127+
return ib
128+
}
129+
130+
/*
131+
Disable this interval when the current state of {entityId} matches {state}.
132+
If there is a network error while retrieving state, the interval runs if {runOnNetworkError} is true.
133+
*/
134+
func (ib intervalBuilderEnd) DisabledWhen(entityId, state string, runOnNetworkError bool) intervalBuilderEnd {
135+
if entityId == "" {
136+
panic(fmt.Sprintf("entityId is empty in EnabledWhen entityId='%s' state='%s'", entityId, state))
137+
}
138+
if ib.interval.enabledEntity != "" {
139+
panic(fmt.Sprintf("You can't use EnabledWhen and DisabledWhen together. Error occurred while setting DisabledWhen on an entity listener with params entityId=%s state=%s runOnNetworkError=%t", entityId, state, runOnNetworkError))
140+
}
141+
ib.interval.disabledEntity = entityId
142+
ib.interval.disabledEntityState = state
143+
ib.interval.disabledEntityRunOnError = runOnNetworkError
144+
return ib
104145
}
105146

106147
func (sb intervalBuilderEnd) Build() Interval {
@@ -143,6 +184,12 @@ func (i Interval) maybeRunCallback(a *App) {
143184
if c := checkExceptionRanges(i.exceptionRanges); c.fail {
144185
return
145186
}
187+
if c := checkEnabledEntity(a.state, i.enabledEntity, i.enabledEntityState, i.enabledEntityRunOnError); c.fail {
188+
return
189+
}
190+
if c := checkDisabledEntity(a.state, i.disabledEntity, i.disabledEntityState, i.disabledEntityRunOnError); c.fail {
191+
return
192+
}
146193
go i.callback(a.service, a.state)
147194
}
148195

schedule.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,13 @@ type DailySchedule struct {
2626

2727
exceptionDates []time.Time
2828
allowlistDates []time.Time
29+
30+
enabledEntity string
31+
enabledEntityState string
32+
enabledEntityRunOnError bool
33+
disabledEntity string
34+
disabledEntityState string
35+
disabledEntityRunOnError bool
2936
}
3037

3138
func (s DailySchedule) Hash() string {
@@ -110,6 +117,40 @@ func (sb scheduleBuilderEnd) OnlyOnDates(t time.Time, tl ...time.Time) scheduleB
110117
return sb
111118
}
112119

120+
/*
121+
Enable this schedule only when the current state of {entityId} matches {state}.
122+
If there is a network error while retrieving state, the schedule runs if {runOnNetworkError} is true.
123+
*/
124+
func (sb scheduleBuilderEnd) EnabledWhen(entityId, state string, runOnNetworkError bool) scheduleBuilderEnd {
125+
if entityId == "" {
126+
panic(fmt.Sprintf("entityId is empty in EnabledWhen entityId='%s' state='%s'", entityId, state))
127+
}
128+
if sb.schedule.disabledEntity != "" {
129+
panic(fmt.Sprintf("You can't use EnabledWhen and DisabledWhen together. Error occurred while setting EnabledWhen on a schedule with params entityId=%s state=%s runOnNetworkError=%t", entityId, state, runOnNetworkError))
130+
}
131+
sb.schedule.enabledEntity = entityId
132+
sb.schedule.enabledEntityState = state
133+
sb.schedule.enabledEntityRunOnError = runOnNetworkError
134+
return sb
135+
}
136+
137+
/*
138+
Disable this schedule when the current state of {entityId} matches {state}.
139+
If there is a network error while retrieving state, the schedule runs if {runOnNetworkError} is true.
140+
*/
141+
func (sb scheduleBuilderEnd) DisabledWhen(entityId, state string, runOnNetworkError bool) scheduleBuilderEnd {
142+
if entityId == "" {
143+
panic(fmt.Sprintf("entityId is empty in EnabledWhen entityId='%s' state='%s'", entityId, state))
144+
}
145+
if sb.schedule.enabledEntity != "" {
146+
panic(fmt.Sprintf("You can't use EnabledWhen and DisabledWhen together. Error occurred while setting DisabledWhen on a schedule with params entityId=%s state=%s runOnNetworkError=%t", entityId, state, runOnNetworkError))
147+
}
148+
sb.schedule.disabledEntity = entityId
149+
sb.schedule.disabledEntityState = state
150+
sb.schedule.disabledEntityRunOnError = runOnNetworkError
151+
return sb
152+
}
153+
113154
func (sb scheduleBuilderEnd) Build() DailySchedule {
114155
return sb.schedule
115156
}
@@ -145,6 +186,12 @@ func (s DailySchedule) maybeRunCallback(a *App) {
145186
if c := checkAllowlistDates(s.allowlistDates); c.fail {
146187
return
147188
}
189+
if c := checkEnabledEntity(a.state, s.enabledEntity, s.enabledEntityState, s.enabledEntityRunOnError); c.fail {
190+
return
191+
}
192+
if c := checkDisabledEntity(a.state, s.disabledEntity, s.disabledEntityState, s.disabledEntityRunOnError); c.fail {
193+
return
194+
}
148195
go s.callback(a.service, a.state)
149196
}
150197

state.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ func newState(c *http.HttpClient, homeZoneEntityId string) (*State, error) {
3636
func (s *State) getLatLong(c *http.HttpClient, homeZoneEntityId string) error {
3737
resp, err := s.Get(homeZoneEntityId)
3838
if err != nil {
39-
return errors.New(fmt.Sprintf("couldn't get latitude/longitude from home assistant entity '%s'. Did you type it correctly? It should be a zone like 'zone.home'.\n", homeZoneEntityId))
39+
return fmt.Errorf("couldn't get latitude/longitude from home assistant entity '%s'. Did you type it correctly? It should be a zone like 'zone.home'", homeZoneEntityId)
4040
}
4141

4242
if resp.Attributes["latitude"] != nil {

0 commit comments

Comments
 (0)