ui: show water level and status line before any sud is loaded

Pot config (water_mass, volumen) sent in System message at startup.
app.js stores potConfig and uses it in updatePotVisualization/
updateStatusLine when sudEmpty, showing startup fill level and
"No schedule – N L water" without requiring a sud to be loaded first.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-06-30 19:53:54 +02:00
co-authored by Claude Sonnet 4.6
parent d0a137e39e
commit e7824dc297
4 changed files with 29 additions and 8 deletions
+3 -1
View File
@@ -48,6 +48,8 @@
"mass": 5.96, "mass": 5.96,
"material": "Edelstahl 18/10", "material": "Edelstahl 18/10",
"L": 0.2, "L": 0.2,
"Td": 17 "Td": 17,
"water_mass": 22,
"volumen": 30
} }
} }
+3 -1
View File
@@ -47,6 +47,8 @@
"mass": 5.96, "mass": 5.96,
"material": "Edelstahl 18/10", "material": "Edelstahl 18/10",
"L": 0.2, "L": 0.2,
"Td": 17 "Td": 17,
"water_mass": 22,
"volumen": 30
} }
} }
+2 -1
View File
@@ -164,7 +164,8 @@ if __name__ == '__main__':
msg_system = dispatcher.msgio_get("System") msg_system = dispatcher.msgio_get("System")
async def send_system_info(): async def send_system_info():
await msg_system.send({'AmbientTemp': theta_amb, 'WarpFactor': DT / DT_TASK, 'PlantSim': plant_sim}) await msg_system.send({'AmbientTemp': theta_amb, 'WarpFactor': DT / DT_TASK, 'PlantSim': plant_sim,
'Pot': config.get('Pot', {})})
asyncio.ensure_future(send_system_info()) asyncio.ensure_future(send_system_info())
async def on_system_recv(data): async def on_system_recv(data):
+21 -5
View File
@@ -41,6 +41,10 @@ let heaterMaxPower = 100;
// Only switchable when not running; auto-reset to true on play. // Only switchable when not running; auto-reset to true on play.
let closedLoop = true; let closedLoop = true;
// Pot hardware config from server's Pot section - used for display before
// any sud is loaded (startup water level, status line).
let potConfig = {};
// Sud state - mirrors the sud_* fields on client/brewpi_gui.py's Window. // Sud state - mirrors the sud_* fields on client/brewpi_gui.py's Window.
let sudSchedule = []; let sudSchedule = [];
let sudName = ''; let sudName = '';
@@ -420,7 +424,11 @@ function updatePotVisualization() {
const levelTickEl = document.getElementById('level-tick'); const levelTickEl = document.getElementById('level-tick');
const levelLabelEl = document.getElementById('level-label'); const levelLabelEl = document.getElementById('level-label');
if (sudEmpty || sudVolumen <= 0) { const volumen = sudEmpty ? (potConfig.volumen || 0) : sudVolumen;
const grainMass = sudEmpty ? 0 : currentStepGrainMass();
const waterMass = sudEmpty ? (potConfig.water_mass || 0) : currentStepWaterMass();
if (volumen <= 0) {
waterFillEl.setAttribute('height', '0'); waterFillEl.setAttribute('height', '0');
waterWaveEl.setAttribute('d', ''); waterWaveEl.setAttribute('d', '');
if (waterClipRect) waterClipRect.setAttribute('height', '0'); if (waterClipRect) waterClipRect.setAttribute('height', '0');
@@ -430,9 +438,8 @@ function updatePotVisualization() {
return; return;
} }
const grainMass = currentStepGrainMass(); const utilizedVolume = waterMass + grainMass * 0.7;
const utilizedVolume = currentStepWaterMass() + grainMass * 0.7; const fillFraction = Math.min(1, Math.max(0, utilizedVolume / volumen));
const fillFraction = Math.min(1, Math.max(0, utilizedVolume / sudVolumen));
const waterH = fillFraction * potInnerH; const waterH = fillFraction * potInnerH;
const waterTop = potInnerBottom - waterH; const waterTop = potInnerBottom - waterH;
waterFillEl.setAttribute('y', waterTop.toFixed(1)); waterFillEl.setAttribute('y', waterTop.toFixed(1));
@@ -462,7 +469,8 @@ function updatePotVisualization() {
function updateStatusLine() { function updateStatusLine() {
const el = document.getElementById('sud-status-line'); const el = document.getElementById('sud-status-line');
if (sudSchedule.length === 0) { if (sudSchedule.length === 0) {
el.textContent = ''; const w = potConfig.water_mass || 0;
el.textContent = w > 0 ? `No schedule ${w} L water` : '';
return; return;
} }
let text = ''; let text = '';
@@ -776,6 +784,13 @@ function onSystemChanged(msg) {
if ('PlantSim' in msg) { if ('PlantSim' in msg) {
document.getElementById('pot-reset-row').classList.toggle('hidden', !msg.PlantSim); document.getElementById('pot-reset-row').classList.toggle('hidden', !msg.PlantSim);
} }
if ('Pot' in msg) {
potConfig = msg.Pot;
if (sudEmpty) {
updatePotVisualization();
updateStatusLine();
}
}
} }
const HANDLERS = { const HANDLERS = {
@@ -820,6 +835,7 @@ function connect() {
initialTempSollSync = true; initialTempSollSync = true;
initialPotTempSync = true; initialPotTempSync = true;
closedLoop = true; closedLoop = true;
potConfig = {};
setConnected(true); setConnected(true);
for (const channel of CHANNELS) { for (const channel of CHANNELS) {
ws.send(JSON.stringify({'+': channel})); ws.send(JSON.stringify({'+': channel}));