refactor: drop firmware-version display, move Enable toggle to Controller
Firmware version is already printed to the log at connect() time (HendiCtrl/Pololu1376) - remove the live GUI/websocket firmware reporting entirely (Connectable, HeaterHendi/StirrerPololu1376, Heater/StirrerTask, web GUI) as redundant. Also move the Heater panel's Closed-loop checkbox into the Controller panel and rename it "Enable" - the Controller panel now shows a live Enabled (green) / Disabled (gray) status badge next to its heading, matching the Connected/Disconnected badges on the Heater/ Stirrer panels. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01YaPLuRPpyjWcwhMvCvpHCL
This commit is contained in:
@@ -23,13 +23,11 @@ class HeaterHendi(AHeater):
|
||||
def connect(self):
|
||||
ok = self.hendi.connect()
|
||||
self.connected = ok
|
||||
self.firmware_version = self.hendi.sw_ver if ok else None
|
||||
return ok
|
||||
|
||||
def disconnect(self):
|
||||
self.hendi.disconnect()
|
||||
self.connected = False
|
||||
self.firmware_version = None
|
||||
|
||||
def activate(self, enable):
|
||||
if not self.connected:
|
||||
|
||||
@@ -23,13 +23,11 @@ class StirrerPololu1376(AStirrer):
|
||||
def connect(self):
|
||||
ok = self.drv.connect()
|
||||
self.connected = ok
|
||||
self.firmware_version = self.drv.firmware_version if ok else None
|
||||
return ok
|
||||
|
||||
def disconnect(self):
|
||||
self.drv.disconnect()
|
||||
self.connected = False
|
||||
self.firmware_version = None
|
||||
|
||||
@contextmanager
|
||||
def remote_open(self):
|
||||
|
||||
@@ -4,16 +4,15 @@ from utils.value import AttributeChange
|
||||
class Connectable(AttributeChange):
|
||||
"""Observable hardware-connection state shared by AHeater/AStirrer.
|
||||
|
||||
Simulated devices are always connected and report no firmware version;
|
||||
real (serial) devices start disconnected and only flip once connect()
|
||||
actually reaches the hardware.
|
||||
Simulated devices are always connected; real (serial) devices start
|
||||
disconnected and only flip once connect() actually reaches the
|
||||
hardware.
|
||||
"""
|
||||
|
||||
def __init__(self, simulated):
|
||||
AttributeChange.__init__(self)
|
||||
self.simulated = simulated
|
||||
self.connected = simulated
|
||||
self.firmware_version = None
|
||||
|
||||
def connect(self):
|
||||
return self.connected
|
||||
|
||||
@@ -21,7 +21,6 @@ class HeaterTask(ATask):
|
||||
self._on_connected_changed = None
|
||||
device.set_on_changed('power_eff', ChangedInteger(self.on_changed_power).set)
|
||||
device.set_on_changed('connected', self.on_connected_changed)
|
||||
device.set_on_changed('firmware_version', self.on_firmware_version_changed)
|
||||
self.power_set_changed = ChangedInteger(self.on_changed_power_set).set
|
||||
|
||||
def set_on_closed_loop_changed(self, callback):
|
||||
@@ -38,9 +37,6 @@ class HeaterTask(ATask):
|
||||
if self._on_connected_changed:
|
||||
self._on_connected_changed(value)
|
||||
|
||||
def on_firmware_version_changed(self, value):
|
||||
fire_and_forget(self.send({'FirmwareVersion': value}))
|
||||
|
||||
def shutdown(self):
|
||||
"""Called when the brew ends (DONE/IDLE). Switches to open-loop at
|
||||
power 0 and disables TC, mirroring what a Stop press should do."""
|
||||
@@ -125,7 +121,6 @@ class HeaterTask(ATask):
|
||||
# fire and a freshly-subscribed client would never learn it's
|
||||
# connected.
|
||||
await self.send({'Connected': self.device.connected})
|
||||
await self.send({'FirmwareVersion': self.device.firmware_version})
|
||||
|
||||
with self.device.open():
|
||||
while True:
|
||||
|
||||
@@ -16,7 +16,6 @@ class StirrerTask(ATask):
|
||||
stirrer_device.set_on_changed("dutyCycle", self.on_dutycycle_changed)
|
||||
stirrer_device.set_on_changed("cycleTime", self.on_cycletime_changed)
|
||||
stirrer_device.set_on_changed("connected", self.on_connected_changed)
|
||||
stirrer_device.set_on_changed("firmware_version", self.on_firmware_version_changed)
|
||||
|
||||
def on_speed_changed(self, value):
|
||||
asyncio.create_task(self.send({'Speed': value}))
|
||||
@@ -38,9 +37,6 @@ class StirrerTask(ATask):
|
||||
if self._on_connected_changed:
|
||||
self._on_connected_changed(value)
|
||||
|
||||
def on_firmware_version_changed(self, value):
|
||||
fire_and_forget(self.send({'FirmwareVersion': value}))
|
||||
|
||||
async def recv(self, data):
|
||||
for pair in data.items():
|
||||
if pair[0] == 'Connect':
|
||||
@@ -69,7 +65,6 @@ class StirrerTask(ATask):
|
||||
# for why a simulated device's connect() alone doesn't fire the
|
||||
# observer.
|
||||
await self.send({'Connected': self.device.connected})
|
||||
await self.send({'FirmwareVersion': self.device.firmware_version})
|
||||
|
||||
with self.device.open():
|
||||
while True:
|
||||
|
||||
+23
-18
@@ -45,10 +45,8 @@ let closedLoop = true;
|
||||
// are always connected and never expose Connect/Disconnect (see
|
||||
// updateDeviceStatus()).
|
||||
let heaterConnected = false;
|
||||
let heaterFirmware = null;
|
||||
let heaterSimulated = null;
|
||||
let stirrerConnected = false;
|
||||
let stirrerFirmware = null;
|
||||
let stirrerSimulated = null;
|
||||
|
||||
// Pot hardware config from server's Pot section - used for display before
|
||||
@@ -536,15 +534,14 @@ function updateSudActions() {
|
||||
document.getElementById('btn-sud-stop').disabled = !(running || paused);
|
||||
}
|
||||
|
||||
// Shared by onHeaterChanged/onStirrerChanged - updates the status badge,
|
||||
// firmware label, and Connect/Disconnect buttons for one device. Simulated
|
||||
// devices are always connected and have nothing to connect/disconnect, so
|
||||
// their buttons are hidden entirely rather than just disabled.
|
||||
function updateDeviceStatus(prefix, isConnected, firmware, simulated) {
|
||||
// Shared by onHeaterChanged/onStirrerChanged - updates the status badge
|
||||
// and Connect/Disconnect buttons for one device. Simulated devices are
|
||||
// always connected and have nothing to connect/disconnect, so their
|
||||
// buttons are hidden entirely rather than just disabled.
|
||||
function updateDeviceStatus(prefix, isConnected, simulated) {
|
||||
const statusEl = document.getElementById(`${prefix}-status`);
|
||||
statusEl.textContent = isConnected ? 'Connected' : 'Disconnected';
|
||||
statusEl.className = `panel-status ${isConnected ? 'status-connected' : 'status-disconnected'}`;
|
||||
document.getElementById(`${prefix}-firmware`).textContent = firmware ? `F/W ${firmware}` : '';
|
||||
const connectBtn = document.getElementById(`btn-${prefix}-connect`);
|
||||
const disconnectBtn = document.getElementById(`btn-${prefix}-disconnect`);
|
||||
connectBtn.classList.toggle('hidden', !!simulated);
|
||||
@@ -553,6 +550,15 @@ function updateDeviceStatus(prefix, isConnected, firmware, simulated) {
|
||||
disconnectBtn.disabled = !isConnected;
|
||||
}
|
||||
|
||||
// Reflects closedLoop (the Controller panel's Enable toggle) in the
|
||||
// Controller heading's status badge - Enabled/green when the TC is
|
||||
// driving the heater, Disabled/gray in open-loop.
|
||||
function updateClosedLoopStatus() {
|
||||
const statusEl = document.getElementById('closed-loop-status');
|
||||
statusEl.textContent = closedLoop ? 'Enabled' : 'Disabled';
|
||||
statusEl.className = `panel-status ${closedLoop ? 'status-connected' : 'status-disconnected'}`;
|
||||
}
|
||||
|
||||
// Mirrors client/brewpi_gui.py's show_user_message(): the Sud is already
|
||||
// blocked in WAIT_USER server-side - dismissing this dialog (OK or Escape,
|
||||
// both fire the dialog's 'close' event) is what unblocks it.
|
||||
@@ -632,6 +638,7 @@ function onHeaterChanged(msg) {
|
||||
} else if (key === 'ClosedLoop') {
|
||||
closedLoop = msg.ClosedLoop;
|
||||
document.getElementById('closed-loop').checked = closedLoop;
|
||||
updateClosedLoopStatus();
|
||||
updateControlsEnabled();
|
||||
} else if (key === 'Capabilities') {
|
||||
const power = msg.Capabilities.Power;
|
||||
@@ -641,15 +648,12 @@ function onHeaterChanged(msg) {
|
||||
slider.max = power.Max;
|
||||
} else if (key === 'Connected') {
|
||||
heaterConnected = msg.Connected;
|
||||
updateDeviceStatus('heater', heaterConnected, heaterFirmware, heaterSimulated);
|
||||
updateDeviceStatus('heater', heaterConnected, heaterSimulated);
|
||||
updateControlsEnabled();
|
||||
updateSudActions();
|
||||
} else if (key === 'FirmwareVersion') {
|
||||
heaterFirmware = msg.FirmwareVersion;
|
||||
updateDeviceStatus('heater', heaterConnected, heaterFirmware, heaterSimulated);
|
||||
} else if (key === 'Simulated') {
|
||||
heaterSimulated = msg.Simulated;
|
||||
updateDeviceStatus('heater', heaterConnected, heaterFirmware, heaterSimulated);
|
||||
updateDeviceStatus('heater', heaterConnected, heaterSimulated);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -669,15 +673,12 @@ function onStirrerChanged(msg) {
|
||||
slider.max = power.Max;
|
||||
} else if (key === 'Connected') {
|
||||
stirrerConnected = msg.Connected;
|
||||
updateDeviceStatus('stirrer', stirrerConnected, stirrerFirmware, stirrerSimulated);
|
||||
updateDeviceStatus('stirrer', stirrerConnected, stirrerSimulated);
|
||||
updateControlsEnabled();
|
||||
updateSudActions();
|
||||
} else if (key === 'FirmwareVersion') {
|
||||
stirrerFirmware = msg.FirmwareVersion;
|
||||
updateDeviceStatus('stirrer', stirrerConnected, stirrerFirmware, stirrerSimulated);
|
||||
} else if (key === 'Simulated') {
|
||||
stirrerSimulated = msg.Simulated;
|
||||
updateDeviceStatus('stirrer', stirrerConnected, stirrerFirmware, stirrerSimulated);
|
||||
updateDeviceStatus('stirrer', stirrerConnected, stirrerSimulated);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -751,6 +752,7 @@ function onSudChanged(msg) {
|
||||
if (isRunningNow && !wasRunning) {
|
||||
closedLoop = true;
|
||||
document.getElementById('closed-loop').checked = true;
|
||||
updateClosedLoopStatus();
|
||||
sendMsg('Heater', {ClosedLoop: true});
|
||||
// Accept the next Soll push from the server even if it
|
||||
// arrives before sudRunning has gone true at this client
|
||||
@@ -886,6 +888,7 @@ function connect() {
|
||||
initialTempSollSync = true;
|
||||
initialPotTempSync = true;
|
||||
closedLoop = true;
|
||||
updateClosedLoopStatus();
|
||||
potConfig = {};
|
||||
setConnected(true);
|
||||
for (const channel of CHANNELS) {
|
||||
@@ -937,6 +940,8 @@ document.getElementById('btn-connect').addEventListener('click', () => {
|
||||
});
|
||||
|
||||
document.getElementById('closed-loop').addEventListener('change', (e) => {
|
||||
closedLoop = e.target.checked;
|
||||
updateClosedLoopStatus();
|
||||
sendMsg('Heater', {ClosedLoop: e.target.checked});
|
||||
});
|
||||
document.getElementById('btn-heater-connect').addEventListener('click', () => {
|
||||
|
||||
+4
-6
@@ -38,7 +38,10 @@
|
||||
<button id="btn-manual-toggle" title="Collapse manual panel">◀</button>
|
||||
<div id="manual-panels">
|
||||
<div class="panel">
|
||||
<h3>Controller</h3>
|
||||
<h3>Controller <span id="closed-loop-status" class="panel-status status-connected">Enabled</span></h3>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="closed-loop" checked> Enable
|
||||
</label>
|
||||
<label>Temperature [°C]
|
||||
<div class="slider-row">
|
||||
<input type="range" id="temp-soll" min="0" max="100" step="1">
|
||||
@@ -52,13 +55,9 @@
|
||||
<div class="panel">
|
||||
<h3>Heater <span id="heater-status" class="panel-status status-disconnected">Disconnected</span></h3>
|
||||
<div class="device-status-row">
|
||||
<span id="heater-firmware" class="device-firmware"></span>
|
||||
<button id="btn-heater-connect">Connect</button>
|
||||
<button id="btn-heater-disconnect" disabled>Disconnect</button>
|
||||
</div>
|
||||
<label class="checkbox-label">
|
||||
<input type="checkbox" id="closed-loop" checked> Closed-loop
|
||||
</label>
|
||||
<label>Power [W]
|
||||
<div class="slider-row">
|
||||
<input type="range" id="heater-power" min="0" max="100" step="1">
|
||||
@@ -69,7 +68,6 @@
|
||||
<div class="panel">
|
||||
<h3>Stirrer <span id="stirrer-status" class="panel-status status-disconnected">Disconnected</span></h3>
|
||||
<div class="device-status-row">
|
||||
<span id="stirrer-firmware" class="device-firmware"></span>
|
||||
<button id="btn-stirrer-connect">Connect</button>
|
||||
<button id="btn-stirrer-disconnect" disabled>Disconnect</button>
|
||||
</div>
|
||||
|
||||
@@ -350,7 +350,6 @@ header#connection-bar {
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.device-status-row button { padding: 0.15em 0.6em; font-size: 0.9em; }
|
||||
.device-firmware { color: var(--text-muted); }
|
||||
|
||||
/* --- Hidden --- */
|
||||
.hidden { display: none !important; }
|
||||
|
||||
Reference in New Issue
Block a user