From 698c0195819e30dab66dc663540850c6346369ec Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Thu, 2 Jul 2026 22:03:50 +0200 Subject: [PATCH] refactor: make ATemperatureSensor's temp observable directly on the sensor TempSensorSim/TempSensor_max31865's temperature() now stores its reading on self.temp, so ATemperatureSensor's inherited AttributeChange (previously never triggered by anything) actually fires. TempSensorTask no longer keeps its own shadow copy of the reading - it registers its websocket-push callback on self.sensor directly and just drives the read each tick; server/brewpi.py's TC-feeding registration moved from sensor_task to sensor for the same reason. Priming read happens before registering the callback (not after) since all tasks are built synchronously at module level, before the asyncio event loop starts - registering first would fire on_temp_changed's asyncio.create_task() with no running loop. Co-Authored-By: Claude Sonnet 5 Claude-Session: https://claude.ai/code/session_01GpePKZiEZWbGo9HrfuML6U --- components/sensor/tempSensorSim.py | 3 ++- components/sensor/tempSensor_max31865.py | 3 ++- server/brewpi.py | 2 +- tasks/tempsensor.py | 10 +++++++--- 4 files changed, 12 insertions(+), 6 deletions(-) diff --git a/components/sensor/tempSensorSim.py b/components/sensor/tempSensorSim.py index 06ce32d..07c8fa4 100644 --- a/components/sensor/tempSensorSim.py +++ b/components/sensor/tempSensorSim.py @@ -42,4 +42,5 @@ class TempSensorSim(ATemperatureSensor): innovation = self.stirrer_sigma * np.sqrt(2.0 * alpha) * np.random.normal() self._stirrer_state = (1.0 - alpha) * self._stirrer_state + innovation - return self.temp_set + self.offset + white + self._stirrer_state + self.temp = self.temp_set + self.offset + white + self._stirrer_state + return self.temp diff --git a/components/sensor/tempSensor_max31865.py b/components/sensor/tempSensor_max31865.py index ae64f10..195efa1 100755 --- a/components/sensor/tempSensor_max31865.py +++ b/components/sensor/tempSensor_max31865.py @@ -47,7 +47,8 @@ class TempSensor_max31865(ATemperatureSensor): def temperature(self): digits = self.read_digits() - return self.temp_offset + self.to_temperature(digits) + self.temp = self.temp_offset + self.to_temperature(digits) + return self.temp @staticmethod def to_temperature(digits): diff --git a/server/brewpi.py b/server/brewpi.py index 334f013..013d8d5 100755 --- a/server/brewpi.py +++ b/server/brewpi.py @@ -182,7 +182,7 @@ if __name__ == '__main__': sud_task.set_on_end(lambda: (heater_task.shutdown(), sud_log_task.stop_run())) # Assign temp. sensor readings to tc - sensor_task.set_on_changed("temp", ChangedFloat(tc.set_theta_ist, prec=2).set) + sensor.set_on_changed("temp", ChangedFloat(tc.set_theta_ist, prec=2).set) heater.set_on_changed("power_set", tc.set_model_power) diff --git a/tasks/tempsensor.py b/tasks/tempsensor.py index a023fe4..62c0654 100644 --- a/tasks/tempsensor.py +++ b/tasks/tempsensor.py @@ -12,8 +12,12 @@ class TempSensorTask(ATask): self.msg_handler = msg_handler msg_handler.set_recv_handler(self.recv) self.sensor = sensor_device - self.temp = self.sensor.temperature() - self.set_on_changed("temp", ChangedFloat(self.on_temp_changed, prec=1).set) + # Prime before registering - temperature() sets self.sensor.temp, + # which would otherwise fire on_temp_changed() (and its + # asyncio.create_task()) before the event loop is running, since + # all tasks are built synchronously at module level in brewpi.py. + self.sensor.temperature() + self.sensor.set_on_changed("temp", ChangedFloat(self.on_temp_changed, prec=1).set) def on_temp_changed(self, value): asyncio.create_task(self.send({'Temp': value})) @@ -26,5 +30,5 @@ class TempSensorTask(ATask): async def on_process(self): while True: - self.temp = self.sensor.temperature() + self.sensor.temperature() await asyncio.sleep(self.interval)