Track and display energy consumption per Sud step
Each StepPlate on the Progress tab now shows a step's energy use in Wh - live and growing while it's the active step, frozen at its final total once finished, blank before it's ever been reached. Integrated server-side from the heater's own live effective power (pot.get_power(), already fed from heater.power_eff - see server/ brewpi.py's wiring), since actual energy used can't be predicted from the forecast like the timing/temperature fields are, only measured as it happens. Banked into energy_by_step on every genuine step transition (on_step_changed(), keyed off the same index-change check used for the ramp->hold phase switch), including the final transition to DONE; reset on every fresh Load. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_019qvu5giu7gvRCyEWzf2Vpx
This commit is contained in:
+36
-2
@@ -301,7 +301,9 @@ class StepPlate(QtWidgets.QFrame):
|
||||
self.label_masses = QtWidgets.QLabel()
|
||||
self.label_rate = QtWidgets.QLabel()
|
||||
self.label_stirrer = QtWidgets.QLabel()
|
||||
for label in (self.label_target, self.label_actual, self.label_masses, self.label_rate, self.label_stirrer):
|
||||
self.label_energy = QtWidgets.QLabel()
|
||||
for label in (self.label_target, self.label_actual, self.label_masses, self.label_rate,
|
||||
self.label_stirrer, self.label_energy):
|
||||
label.setStyleSheet("color: #555;")
|
||||
|
||||
# A grid, not a single row - the Progress tab shares its pane's
|
||||
@@ -315,13 +317,15 @@ class StepPlate(QtWidgets.QFrame):
|
||||
layout.addWidget(self.label_remaining, 0, 2)
|
||||
layout.addWidget(self.label_target, 1, 0, 1, 2)
|
||||
layout.addWidget(self.label_actual, 1, 2)
|
||||
layout.addWidget(self.label_masses, 2, 0, 1, 3)
|
||||
layout.addWidget(self.label_masses, 2, 0, 1, 2)
|
||||
layout.addWidget(self.label_energy, 2, 2)
|
||||
layout.addWidget(self.label_rate, 3, 0, 1, 2)
|
||||
layout.addWidget(self.label_stirrer, 3, 2)
|
||||
|
||||
self.set_step(step, resolved_temp)
|
||||
self.set_actual_temp(None)
|
||||
self.set_live_stirrer(None)
|
||||
self.set_energy(None)
|
||||
|
||||
def set_step(self, step, resolved_temp):
|
||||
"""Applies this step's static, schedule-config fields - called once,
|
||||
@@ -345,6 +349,13 @@ class StepPlate(QtWidgets.QFrame):
|
||||
def set_actual_temp(self, temp):
|
||||
self.label_actual.setText("Actual {}".format("{:.1f} °C".format(temp) if temp is not None else "—"))
|
||||
|
||||
def set_energy(self, wh):
|
||||
"""wh is this step's energy consumption so far (Wh) - live and
|
||||
still growing while this is the active step, frozen at its final
|
||||
total once finished, or None before this step has ever been
|
||||
reached (see Window._update_step_plates())."""
|
||||
self.label_energy.setText("Energy {}".format("{:.0f} Wh".format(wh) if wh is not None else "—"))
|
||||
|
||||
def set_live_stirrer(self, speed):
|
||||
"""speed is the live rpm while this step is the active one, or None
|
||||
to fall back to its configured (hold-phase) speed for a step
|
||||
@@ -470,6 +481,16 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
# on_stirrer_changed()) so the Progress tab's active-step plate can
|
||||
# show it.
|
||||
self.stirrer_speed_ist = 0.0
|
||||
# Energy consumption (Wh), straight from the latest 'Energy'
|
||||
# message (see tasks/sud.py's SudTask._on_energy_changed()) -
|
||||
# sud_energy_by_step covers every *finished* step (absolute index
|
||||
# -> Wh), sud_energy_current is the running total for whichever
|
||||
# step is presently active. Unlike the timing/temperature fields
|
||||
# above, there's no forecast equivalent to preview before a run
|
||||
# starts - energy actually used can only be measured, not
|
||||
# predicted - so both stay empty/zero until one actually does.
|
||||
self.sud_energy_by_step = {}
|
||||
self.sud_energy_current = 0.0
|
||||
self.msg_pot = self.msg_dispatch.msgio_get('Pot')
|
||||
self.msg_sensor = self.msg_dispatch.msgio_get('Sensor')
|
||||
self.msg_heater = self.msg_dispatch.msgio_get('Heater')
|
||||
@@ -1097,6 +1118,10 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
self._update_step_plates()
|
||||
elif "Forecast" in key:
|
||||
self.on_sud_forecast_received(msg['Forecast'])
|
||||
elif "Energy" in key:
|
||||
self.sud_energy_by_step = dict(msg['Energy']['StepEnergy'])
|
||||
self.sud_energy_current = msg['Energy']['Current']
|
||||
self._update_step_plates()
|
||||
elif "Error" in key:
|
||||
# The server clears this back to None right after sending
|
||||
# it (see tasks/sud.py's recv()) so it doesn't linger in
|
||||
@@ -1203,6 +1228,8 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
self.sud_forecast_finished = False
|
||||
self.sud_forecast_final_t = None
|
||||
self.step_actual_frozen = {}
|
||||
self.sud_energy_by_step = {}
|
||||
self.sud_energy_current = 0.0
|
||||
self._rebuild_step_plates()
|
||||
self.update_sud_actions()
|
||||
self.update_status_step_label()
|
||||
@@ -1280,6 +1307,13 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
||||
plate.set_actual_temp(None)
|
||||
plate.set_live_stirrer(None)
|
||||
|
||||
if self.sud_step_index is not None and i == self.sud_step_index:
|
||||
plate.set_energy(self.sud_energy_current)
|
||||
elif i in self.sud_energy_by_step:
|
||||
plate.set_energy(self.sud_energy_by_step[i])
|
||||
else:
|
||||
plate.set_energy(None)
|
||||
|
||||
def closeEvent(self, event):
|
||||
print("Exitting gracefully!")
|
||||
self.user_config.set('ambient_temperature', self.doubleSpinBox_ambient.value())
|
||||
|
||||
Reference in New Issue
Block a user