From cb4220458dbb03413015a50da4f0a16a387424ea Mon Sep 17 00:00:00 2001 From: T Date: Sat, 26 Sep 2026 16:23:07 +0200 Subject: [PATCH] Debug state machine, 24h restart --- ug/button.py | 64 ++++++++++++++++++++++++++++++++++------------------ 1 file changed, 42 insertions(+), 22 deletions(-) diff --git a/ug/button.py b/ug/button.py index 17b7c78..0f2a65d 100644 --- a/ug/button.py +++ b/ug/button.py @@ -124,9 +124,12 @@ class DoorLocal(Door): class FoodoorMQTT: + MESSAGE_TIMEOUT = 24 * 60 * 60 + def __init__(self, areas): self.areas = areas self.message_cbs = [] + self.last_message_at = time.monotonic() self.client = mqtt.Client() self.client.on_connect = self.on_connect @@ -157,6 +160,7 @@ class FoodoorMQTT: self._connect_lock.notify() def on_message(self, client, userdata, msg): + self.last_message_at = time.monotonic() print(f"MQTT-Server Message: {msg.topic} {msg.payload.decode()}") self._data[msg.topic] = msg.payload.decode() for cb in self.message_cbs: @@ -182,10 +186,11 @@ class StateMenu: self.anim = [] self.timeout = None self.next_state = None + self._force_redraw = True self.reset_state() self.mqtt = FoodoorMQTT(["oben", "unten"]) - self.mqtt.message_cbs.append(lambda *_: self.draw()) + self.mqtt.message_cbs.append(lambda *_: self.redraw()) if SIM: self.mqtt.connect("127.0.0.1") else: @@ -211,6 +216,7 @@ class StateMenu: self.anim.clear() self.timeout = None self.next_state = None + self._force_redraw = True def button_pressed(self, btn): if btn not in self.doors: # door sensor @@ -236,7 +242,7 @@ class StateMenu: # self.timeout = time.monotonic() + 10 pass - self.draw() + self.redraw() def set_state(self, state, timeout=None): self.state = state @@ -244,22 +250,14 @@ class StateMenu: if timeout is not None: self.timeout = time.monotonic() + timeout - def draw(self): + def redraw(self): + self._force_redraw = True + + def _draw(self): self.anim.clear() self.strip.brightness = 0.5 # full brightness - if self.state == StateMenu.LOW_POWER: - # self.strip.fill(color.BLACK) - self.strip.brightness = 0.1 - elif self.state == StateMenu.SHOW_STATE: - self.strip_oben.fill(color.GREEN if self.mqtt.is_open("oben") else color.RED) - self.strip_unten.fill(color.GREEN if self.mqtt.is_open("unten") else color.RED) - elif self.state == StateMenu.CHANGE: - self.anim = [ - Chase(self.strip_oben, 0.5, color=color.GREEN, size=1, spacing=11), - Chase(self.strip_unten, 0.5, color=color.RED, size=1, spacing=11), - ] - elif self.state == StateMenu.PROGRESS: + if self.state == StateMenu.PROGRESS or (self.change_target and self.doors[self.change_target].inprogress): if self.change_target == "oben": self.strip_unten.fill(color.GREEN if self.mqtt.is_open("unten") else color.RED) self.anim = [Chase(self.strip_oben, 0.05, size=1, @@ -268,15 +266,34 @@ class StateMenu: self.strip_oben.fill(color.GREEN if self.mqtt.is_open("oben") else color.RED) self.anim = [Chase(self.strip_unten, 0.05, size=1, color=color.GREEN if self.target_state == "open" else color.RED)] + return + + if self.state == StateMenu.LOW_POWER: + self.strip.brightness = 0.1 + if self.state in (StateMenu.LOW_POWER, StateMenu.SHOW_STATE): + self.strip_oben.fill(color.GREEN if self.mqtt.is_open("oben") else color.RED) + self.strip_unten.fill(color.GREEN if self.mqtt.is_open("unten") else color.RED) + return + + if self.state == StateMenu.CHANGE: + self.anim = [ + Chase(self.strip_oben, 0.5, color=color.GREEN, size=1, spacing=11), + Chase(self.strip_unten, 0.5, color=color.RED, size=1, spacing=11), + ] def tick(self): - if self.timeout and self.timeout < time.monotonic() and not (self.change_target and self.doors[self.change_target].inprogress): - if self.next_state is not None: - self.set_state(self.next_state, 10) - self.next_state = None - else: - self.reset_state() - self.draw() + if not (self.change_target and self.doors[self.change_target].inprogress): # Freeze timeout while in progress + if self.timeout and self.timeout < time.monotonic(): + if self.next_state is not None: + self.set_state(self.next_state, 10) + self.next_state = None + self.redraw() + else: + self.reset_state() + + if self._force_redraw: + self._force_redraw = False + self._draw() for a in self.anim: a.animate(show=False) @@ -302,6 +319,9 @@ def main(): try: while True: + if time.monotonic() - menu.mqtt.last_message_at >= menu.mqtt.MESSAGE_TIMEOUT: + raise RuntimeError("No MQTT message received for 24 hours. Cautionary restart.") + if not btn_oben.value: if not btn_locked: menu.button_pressed("oben")