Skip to content

Commit 9d92d81

Browse files
committed
firmware: Dont send MQTT messages if only .since attribute changes
Can happen when pressing openbutton inside/outside for a long time
1 parent ac2fa33 commit 9d92d81

File tree

2 files changed

+53
-1
lines changed

2 files changed

+53
-1
lines changed

firmware/dlockoslo.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,26 @@ def process(self, inport, msg):
298298
self.send('error', 'Unknown port {}'.format(inport))
299299
self.ack(msg)
300300

301+
def is_state_change(current, next):
302+
303+
# avoid modifying inputs
304+
current = copy.deepcopy(current)
305+
next = copy.deepcopy(next)
306+
307+
# ignore changes that are only metadata
308+
current.lock.since = None
309+
next.lock.since = None
310+
current.lock.until = None
311+
next.lock.until = None
312+
current.opener.since = None
313+
next.opener.since = None
314+
current.opener.until = None
315+
next.opener.until = None
316+
317+
state_changed = repr(next.__dict__) != repr(current.__dict__)
318+
return state_changed
319+
320+
301321
class LockParticipant(msgflo.Participant):
302322
def __init__(self, role):
303323
d = copy.deepcopy(participant_definition)
@@ -372,7 +392,7 @@ def recalculate_state(self, mqtt_request=None):
372392
next = next_state(self.state, Inputs(**inputs))
373393
set_outputs(self.state, self.output_files)
374394

375-
state_changed = next.__dict__ != self.state.__dict__
395+
state_changed = is_state_change(self.state, next)
376396
if state_changed:
377397
entry = { 'inputs': inputs, 'state': next.__dict__ }
378398
log.info(entry)

firmware/test_doorsystem.py

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -247,4 +247,36 @@ def test_bolt_present_periodic_update(bolt_present):
247247
assert states.bolt_present_updated > last_updated, 'should update'
248248
assert states.bolt_present_updated == 90.0
249249

250+
def test_state_change_identity():
251+
states = dlockoslo.States()
252+
change = dlockoslo.is_state_change(states, states)
253+
assert change == False
254+
255+
def test_state_change_equivalence():
256+
state1 = dlockoslo.States()
257+
state2 = dlockoslo.States()
258+
change = dlockoslo.is_state_change(state1, state2)
259+
assert change == False
260+
261+
def test_state_change_only_since_until():
262+
state1 = dlockoslo.States()
263+
state2 = dlockoslo.States()
264+
print(id(state1), id(state2))
265+
state2.opener.since = 100
266+
state2.opener.until = 110
267+
state2.opener.since = 100
268+
state2.opener.until = 110
269+
270+
change = dlockoslo.is_state_change(state1, state2)
271+
assert change == False, '.since and .until should be ignored'
272+
273+
def test_state_change_unlocking():
274+
state1 = dlockoslo.States()
275+
state1.lock = dlockoslo.Locked(since=10)
276+
state2 = dlockoslo.States()
277+
state2.lock = dlockoslo.Unlocked(since=20)
278+
279+
change = dlockoslo.is_state_change(state1, state2)
280+
assert change == True, 'unlocking is state change'
281+
250282

0 commit comments

Comments
 (0)