From e0bd3acc264ab9b5bd5e883ec05200db2950853e Mon Sep 17 00:00:00 2001 From: Jens Ahrensfeld Date: Mon, 22 Jun 2026 18:03:48 +0200 Subject: [PATCH] Remove TracerTask Its brewpi.mat output had no consumer - the GUI never subscribed to the 'Tracer' channel, and SudLogTask's run-scoped JSON logs now cover the same sensor/heater/tc data for actual analysis. Drop the task, its DT_TASK_TRACER interval, and the wiring in server/brewpi.py. Co-Authored-By: Claude Sonnet 4.6 Claude-Session: https://claude.ai/code/session_01DkkuG48uHFCGKe6dPSERFk --- server/brewpi.py | 6 +---- tasks/__init__.py | 1 - tasks/sud_log.py | 7 ++--- tasks/tracer.py | 68 ----------------------------------------------- 4 files changed, 5 insertions(+), 77 deletions(-) delete mode 100644 tasks/tracer.py diff --git a/server/brewpi.py b/server/brewpi.py index cc92616..180a1a1 100755 --- a/server/brewpi.py +++ b/server/brewpi.py @@ -13,7 +13,7 @@ from components.plant import Pot from components.actor import HeaterFactory, StirrerFactory from components.sud import Sud from components.sud_forecast import SudForecastEstimator -from tasks import TaskManager, TempSensorTask, HeaterTask, PotTask, TcTask, StirrerTask, TracerTask, SudTask, SudLogTask +from tasks import TaskManager, TempSensorTask, HeaterTask, PotTask, TcTask, StirrerTask, SudTask, SudLogTask import argparse as ap @@ -67,7 +67,6 @@ if __name__ == '__main__': DT = config['Controller']['dt'] DT_TASK = 1.0 / config['Controller']['sim_warp_factor'] - DT_TASK_TRACER = DT_TASK / DT theta_amb = config['ambient_temperature'] plant_sim = "sim" in config['Controller']['plant_name'] @@ -111,9 +110,6 @@ if __name__ == '__main__': # tasks/sud_log.py. taskmgr.add(SudLogTask(sud, tc, heater, heater_task, sud_task, DT_TASK)) - # Tracer - taskmgr.add(TracerTask(sensor, heater, tc, DT_TASK_TRACER, dispatcher.msgio_get("Tracer"))) - # Assign data flow # Assign tc control value to heater tc.set_on_changed("y", heater_task.actor) diff --git a/tasks/__init__.py b/tasks/__init__.py index 0179870..9f9e644 100644 --- a/tasks/__init__.py +++ b/tasks/__init__.py @@ -4,6 +4,5 @@ from tasks.heater import * from tasks.stirrer import * from tasks.pot import * from tasks.tempctrl import * -from tasks.tracer import * from tasks.sud import * from tasks.sud_log import * diff --git a/tasks/sud_log.py b/tasks/sud_log.py index 212003f..cf24c89 100644 --- a/tasks/sud_log.py +++ b/tasks/sud_log.py @@ -21,9 +21,10 @@ class SudLogTask(ATask): power_eff - see client/brewpi_gui.py's PlotCanvas.sample()), plus the forecast curve it's compared against (tasks/sud.py's SudTask. forecast_t/forecast_theta), for the whole duration of a Sud run - - for later offline analysis. One pair of JSON files per run, not the - ever-growing, continuously-rewritten .mat tasks/tracer.py's - TracerTask already produces independently of any Sud run. + for later offline analysis. One pair of JSON files per run, scoped + to that run alone - unlike a continuously-rewritten trace file that + keeps growing independently of whether a Sud run is even in + progress. A fresh, uniquely-named pair of logs starts the moment a run actually starts (Sud.state leaves IDLE/DONE) and is written out diff --git a/tasks/tracer.py b/tasks/tracer.py deleted file mode 100644 index daf58d6..0000000 --- a/tasks/tracer.py +++ /dev/null @@ -1,68 +0,0 @@ -import time -import asyncio -from tasks import ATask -from ws.message import MsgIo -from components import ATemperatureSensor -from components import AHeater -from components import APid - -import numpy as np -import scipy.io -import os - - -class TracerTask(ATask): - def __init__(self, sensor: ATemperatureSensor, heater: AHeater, temp_ctrl: APid, interval, msg_handler: MsgIo, path= './logs'): - ATask.__init__(self, interval) - if not os.path.exists(path): - os.makedirs(path) - - self.msg_handler = msg_handler - msg_handler.set_recv_handler(self.recv) - - self.sensor = sensor - self.heater = heater - self.temp_ctrl = temp_ctrl - self.path = path - - async def recv(self, data): - pass - - async def send(self, data): - await self.msg_handler.send(data) - - async def on_process(self): - print("{}: Started with interval {} s".format(self.msg_handler.get_key(), self.interval)) - - timestamp = 0 - _timestamp = np.empty(0) - _sensor_temp = np.empty(0) - _heater_power = np.empty(0) - _tc_temp_ist = np.empty(0) - _tc_dtemp_ist = np.empty(0) - _tc_temp_soll = np.empty(0) - _tc_dtemp_soll = np.empty(0) - _tc_dtemp_commanded = np.empty(0) - - name = 'brewpi' - filename = os.path.join(self.path, '') + name + ".mat" - filename_full = os.path.join(self.path, '') + name + "." + time.strftime("%Y%m%d%H%M%S", time.localtime()) + ".mat" - - while True: - _timestamp = np.append(_timestamp, timestamp) - _sensor_temp = np.append(_sensor_temp, self.sensor.temperature()) - _heater_power = np.append(_heater_power, self.heater.get_power()) - _tc_temp_ist = np.append(_tc_temp_ist, self.temp_ctrl.theta_ist) - _tc_dtemp_ist = np.append(_tc_dtemp_ist, max(-1, self.temp_ctrl.heatrate_ist)) - _tc_temp_soll = np.append(_tc_temp_soll, self.temp_ctrl.theta_soll_set) - _tc_dtemp_soll = np.append(_tc_dtemp_soll, self.temp_ctrl.heatrate_soll_set) - _tc_dtemp_commanded = np.append(_tc_dtemp_commanded, self.temp_ctrl.heatrate_soll) - - data = {'time': _timestamp, 'sensor_temp': _sensor_temp, 'heater_power': _heater_power, 'tc_temp_ist': _tc_temp_ist, 'tc_dtemp_ist': _tc_dtemp_ist, 'tc_temp_soll': _tc_temp_soll, 'tc_dtemp_soll': _tc_dtemp_soll, 'tc_dtemp_commanded': _tc_dtemp_commanded} - - scipy.io.savemat(filename, data) - scipy.io.savemat(filename_full, data) - timestamp += 1 - await asyncio.sleep(self.interval) - -