Add a real-time Plot tab to brewpi_gui, mirroring demo_sud figure 1

Embeds a dark-themed matplotlib canvas (3 stacked strip charts: theta
ist/soll, heatrate ist/soll, heater power_set/power_eff) in a new Plot
tab, sampled once per second from the latest websocket-received values.

HeaterTask now also emits a PowerSet message (the pre-discretization
target power) alongside the existing Power (effective) message, since
the GUI had no way to see the set-point side of figure 1's bottom plot
otherwise.
This commit is contained in:
2026-06-20 22:31:07 +02:00
parent bb94e065f4
commit 93b5667a64
5 changed files with 133 additions and 3 deletions
+5
View File
@@ -26,6 +26,9 @@ class HeaterTask(ATask):
def on_changed_power(self, power):
asyncio.create_task(self.send({'Power': power}))
def on_changed_power_set(self, power):
asyncio.create_task(self.send({'PowerSet': power}))
async def recv(self, data):
for pair in data.items():
if 'Power' in pair[0]:
@@ -53,6 +56,7 @@ class HeaterTask(ATask):
await self.send({'Capabilities': {'Power': {'Min': 0, 'Max': self.device.get_power_max()}}})
self.device.set_on_changed('power_eff', ChangedInteger(self.on_changed_power).set)
power_set_changed = ChangedInteger(self.on_changed_power_set).set
pulse_period_s = 10
pulse_period_count = pulse_period_s/self.interval
@@ -61,6 +65,7 @@ class HeaterTask(ATask):
while True:
# Combine power set from different sources
power_soll = max(self.power_soll, self.power_actor)
power_set_changed(power_soll)
# Calculate duty cycle
power_low = self.get_next_smaller_power(power_soll)