- Add volumen field to all sud JSON pot entries (30 L) - Fix parseSudDoc to read from nested doc.pot (was using stale flat keys) - SVG widget shows transparent rectangular pot with stirrer, thermometer with live temperature, and water fill level (water_mass/volumen) when a sud is loaded; no water shown when no sud is loaded Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DGKe8JzTM2Gr1fdx9wYXTi
183 lines
6.4 KiB
HTML
183 lines
6.4 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<title>BrewPi</title>
|
|
<link rel="stylesheet" href="style.css">
|
|
</head>
|
|
<body>
|
|
|
|
<header id="connection-bar">
|
|
<label>Host <input id="host" type="text"></label>
|
|
<button id="btn-connect">Connect</button>
|
|
<span id="conn-status" class="status-disconnected">Disconnected</span>
|
|
<span id="sud-controls">
|
|
<button id="btn-sud-new">New</button>
|
|
<button id="btn-sud-load">Load…</button>
|
|
<input type="file" id="sud-file-input" accept="application/json" class="hidden">
|
|
<button id="btn-sud-save">Save…</button>
|
|
<button id="btn-sud-start" class="transport-btn transport-start" title="Start / Resume">▶</button>
|
|
<button id="btn-sud-pause" class="transport-btn transport-pause" title="Pause">▮▮</button>
|
|
<button id="btn-sud-stop" class="transport-btn transport-stop" title="Stop">■</button>
|
|
</span>
|
|
</header>
|
|
|
|
<div id="lcd-panel">
|
|
<div class="lcd-row lcd-header">
|
|
<div class="lcd-label"></div>
|
|
<div>Ist</div>
|
|
<div>Soll</div>
|
|
</div>
|
|
<div class="lcd-row">
|
|
<div class="lcd-label">Temperature [°C]</div>
|
|
<div class="lcd" id="lcd-temp-ist">--</div>
|
|
<div class="lcd" id="lcd-temp-soll">--</div>
|
|
</div>
|
|
<div class="lcd-row">
|
|
<div class="lcd-label">Heat rate [°C/min]</div>
|
|
<div class="lcd" id="lcd-rate-ist">--</div>
|
|
<div class="lcd" id="lcd-rate-soll">--</div>
|
|
</div>
|
|
<div class="lcd-row">
|
|
<div class="lcd-label">Power [W]</div>
|
|
<div class="lcd" id="lcd-power-ist">--</div>
|
|
<div class="lcd" id="lcd-power-soll">--</div>
|
|
</div>
|
|
</div>
|
|
|
|
<div id="pot-view">
|
|
<svg id="pot-svg" viewBox="0 0 290 205" xmlns="http://www.w3.org/2000/svg">
|
|
<defs>
|
|
<clipPath id="pot-clip">
|
|
<rect x="63" y="30" width="114" height="142"/>
|
|
</clipPath>
|
|
<clipPath id="tube-clip">
|
|
<rect x="215" y="28" width="8" height="146"/>
|
|
</clipPath>
|
|
</defs>
|
|
|
|
<!-- Water fill (behind pot walls) -->
|
|
<rect id="water-fill" x="63" y="172" width="114" height="0"
|
|
fill="#1a4a72" clip-path="url(#pot-clip)"/>
|
|
<path id="water-wave" d=""
|
|
fill="none" stroke="#4a9ed8" stroke-width="2"
|
|
clip-path="url(#pot-clip)"/>
|
|
|
|
<!-- Pot outline (transparent walls) -->
|
|
<line x1="60" y1="28" x2="60" y2="174" stroke="#bbb" stroke-width="4" stroke-linecap="round"/>
|
|
<line x1="180" y1="28" x2="180" y2="174" stroke="#bbb" stroke-width="4" stroke-linecap="round"/>
|
|
<line x1="60" y1="174" x2="180" y2="174" stroke="#bbb" stroke-width="4" stroke-linecap="round"/>
|
|
<line x1="60" y1="28" x2="180" y2="28" stroke="#bbb" stroke-width="4" stroke-linecap="round"/>
|
|
|
|
<!-- Stirrer blades (inside pot) -->
|
|
<rect x="87" y="157" width="31" height="5" fill="#666" rx="1"/>
|
|
<rect x="122" y="157" width="31" height="5" fill="#666" rx="1"/>
|
|
|
|
<!-- Lid -->
|
|
<rect x="56" y="20" width="128" height="10" fill="#444" rx="2"/>
|
|
<rect x="56" y="20" width="128" height="3" fill="#555"/>
|
|
|
|
<!-- Stirrer shaft (over lid) -->
|
|
<rect x="118" y="2" width="4" height="158" fill="#777"/>
|
|
|
|
<!-- Motor housing -->
|
|
<rect x="106" y="2" width="28" height="20" fill="#333" rx="3"/>
|
|
<rect x="110" y="6" width="10" height="8" fill="#4a4a4a" rx="1"/>
|
|
<circle cx="129" cy="11" r="3" fill="#cc2222"/>
|
|
|
|
<!-- Thermometer tube -->
|
|
<rect x="212" y="28" width="14" height="146" rx="7"
|
|
fill="#1e1e1e" stroke="#aaa" stroke-width="1.5"/>
|
|
<!-- Thermometer bulb -->
|
|
<circle cx="219" cy="178" r="13" fill="#1e1e1e" stroke="#aaa" stroke-width="1.5"/>
|
|
<!-- Mercury: bulb always red -->
|
|
<circle cx="219" cy="178" r="10" fill="#e0190a"/>
|
|
<!-- Mercury column (JS sets y and height) -->
|
|
<rect id="thermo-mercury" x="215" y="174" width="8" height="0"
|
|
fill="#e0190a" clip-path="url(#tube-clip)"/>
|
|
|
|
<!-- Scale ticks -->
|
|
<line x1="227" y1="28" x2="236" y2="28" stroke="#9e9e9e" stroke-width="1.5"/>
|
|
<text x="239" y="32" font-size="9" fill="#9e9e9e">100</text>
|
|
<line x1="227" y1="65" x2="232" y2="65" stroke="#9e9e9e" stroke-width="1"/>
|
|
<line x1="227" y1="101" x2="236" y2="101" stroke="#9e9e9e" stroke-width="1.5"/>
|
|
<text x="239" y="105" font-size="9" fill="#9e9e9e">50</text>
|
|
<line x1="227" y1="137" x2="232" y2="137" stroke="#9e9e9e" stroke-width="1"/>
|
|
<line x1="227" y1="174" x2="236" y2="174" stroke="#9e9e9e" stroke-width="1.5"/>
|
|
<text x="239" y="178" font-size="9" fill="#9e9e9e">0 °C</text>
|
|
|
|
<!-- Current temperature label -->
|
|
<text id="thermo-temp-label" x="219" y="201" font-size="10"
|
|
fill="#e0e0e0" text-anchor="middle">--</text>
|
|
</svg>
|
|
</div>
|
|
|
|
<nav id="tabs">
|
|
<button class="tab-btn active" data-tab="manual">Manual</button>
|
|
<button class="tab-btn" data-tab="progress">Progress</button>
|
|
</nav>
|
|
|
|
<main>
|
|
<section id="tab-manual" class="tab-content active">
|
|
<div class="panel">
|
|
<h3>Controller</h3>
|
|
<label><input type="checkbox" id="tc-enabled"> Enabled</label>
|
|
<label>Temperature [°C]
|
|
<input type="range" id="temp-soll" min="0" max="100" step="1" disabled>
|
|
<span id="temp-soll-readout">--</span>
|
|
</label>
|
|
<label>Heat rate [°C/min]
|
|
<input type="number" id="heatrate-soll" min="0" max="3" step="0.1" disabled>
|
|
</label>
|
|
</div>
|
|
<div class="panel">
|
|
<h3>Heater</h3>
|
|
<label><input type="checkbox" id="heater-activate"> Activate</label>
|
|
<label>Power [W]
|
|
<input type="range" id="heater-power" min="0" max="100" step="1">
|
|
<span id="heater-power-readout">--</span>
|
|
</label>
|
|
</div>
|
|
<div class="panel">
|
|
<h3>Stirrer</h3>
|
|
<label><input type="checkbox" id="stirrer-activate"> Activate</label>
|
|
<label>Speed [%]
|
|
<input type="range" id="stirrer-speed" min="0" max="100" step="1">
|
|
<span id="stirrer-speed-readout">--</span>
|
|
</label>
|
|
</div>
|
|
<div class="panel">
|
|
<h3>Environment</h3>
|
|
<label>Ambient [°C]
|
|
<input type="number" id="ambient-temp" step="0.1">
|
|
</label>
|
|
<div id="pot-reset-row" class="hidden">
|
|
<label>Pot [°C]
|
|
<input type="number" id="pot-temp" step="0.1">
|
|
</label>
|
|
<button id="btn-pot-reset">Reset</button>
|
|
</div>
|
|
</div>
|
|
</section>
|
|
|
|
<section id="tab-progress" class="tab-content">
|
|
<div id="step-plates"></div>
|
|
</section>
|
|
</main>
|
|
|
|
<dialog id="sud-message-dialog">
|
|
<p id="sud-message-text"></p>
|
|
<form>
|
|
<button id="sud-message-ok" type="button">OK</button>
|
|
</form>
|
|
</dialog>
|
|
|
|
<footer>
|
|
<div id="sud-status-line"></div>
|
|
<div id="env-status-line"></div>
|
|
</footer>
|
|
|
|
<script src="app.js"></script>
|
|
</body>
|
|
</html>
|