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 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GpePKZiEZWbGo9HrfuML6U
This commit is contained in:
2026-07-02 22:03:50 +02:00
co-authored by Claude Sonnet 5
parent 75a886950c
commit 698c019581
4 changed files with 12 additions and 6 deletions
+2 -1
View File
@@ -42,4 +42,5 @@ class TempSensorSim(ATemperatureSensor):
innovation = self.stirrer_sigma * np.sqrt(2.0 * alpha) * np.random.normal() innovation = self.stirrer_sigma * np.sqrt(2.0 * alpha) * np.random.normal()
self._stirrer_state = (1.0 - alpha) * self._stirrer_state + innovation 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
+2 -1
View File
@@ -47,7 +47,8 @@ class TempSensor_max31865(ATemperatureSensor):
def temperature(self): def temperature(self):
digits = self.read_digits() 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 @staticmethod
def to_temperature(digits): def to_temperature(digits):
+1 -1
View File
@@ -182,7 +182,7 @@ if __name__ == '__main__':
sud_task.set_on_end(lambda: (heater_task.shutdown(), sud_log_task.stop_run())) sud_task.set_on_end(lambda: (heater_task.shutdown(), sud_log_task.stop_run()))
# Assign temp. sensor readings to tc # 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) heater.set_on_changed("power_set", tc.set_model_power)
+7 -3
View File
@@ -12,8 +12,12 @@ class TempSensorTask(ATask):
self.msg_handler = msg_handler self.msg_handler = msg_handler
msg_handler.set_recv_handler(self.recv) msg_handler.set_recv_handler(self.recv)
self.sensor = sensor_device self.sensor = sensor_device
self.temp = self.sensor.temperature() # Prime before registering - temperature() sets self.sensor.temp,
self.set_on_changed("temp", ChangedFloat(self.on_temp_changed, prec=1).set) # 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): def on_temp_changed(self, value):
asyncio.create_task(self.send({'Temp': value})) asyncio.create_task(self.send({'Temp': value}))
@@ -26,5 +30,5 @@ class TempSensorTask(ATask):
async def on_process(self): async def on_process(self):
while True: while True:
self.temp = self.sensor.temperature() self.sensor.temperature()
await asyncio.sleep(self.interval) await asyncio.sleep(self.interval)