Disable manual sliders during sud, track live values continuously
During a running sud, all four manual sliders (temp soll, heat rate, heater power, stirrer speed) are disabled for user input but update their positions continuously from server pushes. They re-enable when the sud stops or is paused, or on disconnect. Browser client also resets initial-sync flags on reconnect so sliders re-sync correctly. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DF16nV2ispNw1C9SbvqbRQ
This commit is contained in:
+23
-11
@@ -722,6 +722,9 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self.sud_state = None
|
self.sud_state = None
|
||||||
self.sud_user_message = None
|
self.sud_user_message = None
|
||||||
self._close_confirm_dialog()
|
self._close_confirm_dialog()
|
||||||
|
for w in (self.Slider_temp_soll, self.doubleSpinBox_heatrate_soll,
|
||||||
|
self.Slider_pwr_soll, self.Slider_speed_soll):
|
||||||
|
w.setEnabled(True)
|
||||||
# ambient_temp (the server's last echoed reading, shown in the
|
# ambient_temp (the server's last echoed reading, shown in the
|
||||||
# status bar) is no longer trustworthy, but the spinbox itself is
|
# status bar) is no longer trustworthy, but the spinbox itself is
|
||||||
# a client-owned setting (see closeEvent()/connect()) - leave it
|
# a client-owned setting (see closeEvent()/connect()) - leave it
|
||||||
@@ -912,16 +915,13 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
if 'Temp' in submsg:
|
if 'Temp' in submsg:
|
||||||
self.plot_temp_soll = submsg['Temp']
|
self.plot_temp_soll = submsg['Temp']
|
||||||
self.lcdNumber_temp_soll.display(f'{submsg["Temp"]:.1f}')
|
self.lcdNumber_temp_soll.display(f'{submsg["Temp"]:.1f}')
|
||||||
if self.slider_temp_soll_initial_update:
|
sud_running = self.sud_state in SUD_RUNNING_STATES
|
||||||
# blockSignals: setValue() here is just syncing the
|
if self.slider_temp_soll_initial_update or sud_running:
|
||||||
# slider's display to the server's current value, not
|
|
||||||
# a user edit - without this it would also fire
|
|
||||||
# valueChanged and echo the value straight back as a
|
|
||||||
# command.
|
|
||||||
self.Slider_temp_soll.blockSignals(True)
|
self.Slider_temp_soll.blockSignals(True)
|
||||||
self.Slider_temp_soll.setValue(int(round(submsg['Temp'])))
|
self.Slider_temp_soll.setValue(int(round(submsg['Temp'])))
|
||||||
self.Slider_temp_soll.blockSignals(False)
|
self.Slider_temp_soll.blockSignals(False)
|
||||||
self.slider_temp_soll_initial_update = False
|
if not sud_running:
|
||||||
|
self.slider_temp_soll_initial_update = False
|
||||||
if 'Rate' in submsg:
|
if 'Rate' in submsg:
|
||||||
subsubmsg = submsg['Rate']
|
subsubmsg = submsg['Rate']
|
||||||
for subkey in subsubmsg:
|
for subkey in subsubmsg:
|
||||||
@@ -929,11 +929,13 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
self.plot_rate_soll = subsubmsg['Current']
|
self.plot_rate_soll = subsubmsg['Current']
|
||||||
self.lcdNumber_heatrate_soll.display(f'{subsubmsg["Current"]:.1f}')
|
self.lcdNumber_heatrate_soll.display(f'{subsubmsg["Current"]:.1f}')
|
||||||
if "Set" in subkey:
|
if "Set" in subkey:
|
||||||
if self.heatrate_soll_initial_update:
|
sud_running = self.sud_state in SUD_RUNNING_STATES
|
||||||
self.heatrate_soll_initial_update = False
|
if self.heatrate_soll_initial_update or sud_running:
|
||||||
self.doubleSpinBox_heatrate_soll.blockSignals(True)
|
self.doubleSpinBox_heatrate_soll.blockSignals(True)
|
||||||
self.doubleSpinBox_heatrate_soll.setValue(subsubmsg['Set'])
|
self.doubleSpinBox_heatrate_soll.setValue(subsubmsg['Set'])
|
||||||
self.doubleSpinBox_heatrate_soll.blockSignals(False)
|
self.doubleSpinBox_heatrate_soll.blockSignals(False)
|
||||||
|
if not sud_running:
|
||||||
|
self.heatrate_soll_initial_update = False
|
||||||
if "Ist" in key:
|
if "Ist" in key:
|
||||||
submsg = msg['Ist']
|
submsg = msg['Ist']
|
||||||
if 'Temp' in submsg:
|
if 'Temp' in submsg:
|
||||||
@@ -949,6 +951,10 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
if "PowerSet" in key:
|
if "PowerSet" in key:
|
||||||
self.plot_power_set = msg['PowerSet']
|
self.plot_power_set = msg['PowerSet']
|
||||||
self.lcdNumber_power_heater.display(msg['PowerSet'])
|
self.lcdNumber_power_heater.display(msg['PowerSet'])
|
||||||
|
if self.sud_state in SUD_RUNNING_STATES:
|
||||||
|
self.Slider_pwr_soll.blockSignals(True)
|
||||||
|
self.Slider_pwr_soll.setValue(int(round(msg['PowerSet'])))
|
||||||
|
self.Slider_pwr_soll.blockSignals(False)
|
||||||
elif "Power" in key:
|
elif "Power" in key:
|
||||||
self.plot_power_eff = msg['Power']
|
self.plot_power_eff = msg['Power']
|
||||||
self.lcdNumber_power_pot.display(msg['Power'])
|
self.lcdNumber_power_pot.display(msg['Power'])
|
||||||
@@ -977,11 +983,13 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
if "Speed" in key:
|
if "Speed" in key:
|
||||||
self.stirrer_speed_ist = msg['Speed']
|
self.stirrer_speed_ist = msg['Speed']
|
||||||
self._update_step_plates()
|
self._update_step_plates()
|
||||||
if self.slider_speed_initial_update:
|
sud_running = self.sud_state in SUD_RUNNING_STATES
|
||||||
|
if self.slider_speed_initial_update or sud_running:
|
||||||
self.Slider_speed_soll.blockSignals(True)
|
self.Slider_speed_soll.blockSignals(True)
|
||||||
self.Slider_speed_soll.setValue(int(round(msg['Speed'])))
|
self.Slider_speed_soll.setValue(int(round(msg['Speed'])))
|
||||||
self.Slider_speed_soll.blockSignals(False)
|
self.Slider_speed_soll.blockSignals(False)
|
||||||
self.slider_speed_initial_update = False
|
if not sud_running:
|
||||||
|
self.slider_speed_initial_update = False
|
||||||
elif "Capabilities" in key:
|
elif "Capabilities" in key:
|
||||||
submsg = msg['Capabilities']
|
submsg = msg['Capabilities']
|
||||||
if "Power" in submsg:
|
if "Power" in submsg:
|
||||||
@@ -1008,6 +1016,10 @@ class Window(QtWidgets.QMainWindow, Ui_MainWindow):
|
|||||||
elif "State" in key:
|
elif "State" in key:
|
||||||
prev_state = self.sud_state
|
prev_state = self.sud_state
|
||||||
self.sud_state = msg['State']
|
self.sud_state = msg['State']
|
||||||
|
running = self.sud_state in SUD_RUNNING_STATES
|
||||||
|
for w in (self.Slider_temp_soll, self.doubleSpinBox_heatrate_soll,
|
||||||
|
self.Slider_pwr_soll, self.Slider_speed_soll):
|
||||||
|
w.setEnabled(not running)
|
||||||
|
|
||||||
if self.sud_state in SUD_RUNNING_STATES and self.sud_elapsed_seconds is None:
|
if self.sud_state in SUD_RUNNING_STATES and self.sud_elapsed_seconds is None:
|
||||||
self.sud_elapsed_seconds = 0.0
|
self.sud_elapsed_seconds = 0.0
|
||||||
|
|||||||
+27
-7
@@ -526,6 +526,10 @@ function onHeaterChanged(msg) {
|
|||||||
heaterPowerSoll = msg.PowerSet;
|
heaterPowerSoll = msg.PowerSet;
|
||||||
document.getElementById('lcd-power-soll').textContent = msg.PowerSet;
|
document.getElementById('lcd-power-soll').textContent = msg.PowerSet;
|
||||||
updateFireVisualization();
|
updateFireVisualization();
|
||||||
|
if (RUNNING_STATES.has(sudState)) {
|
||||||
|
document.getElementById('heater-power').value = msg.PowerSet;
|
||||||
|
document.getElementById('heater-power-readout').textContent = msg.PowerSet;
|
||||||
|
}
|
||||||
} else if (key === 'Power') {
|
} else if (key === 'Power') {
|
||||||
heaterPowerIst = msg.Power;
|
heaterPowerIst = msg.Power;
|
||||||
document.getElementById('lcd-power-ist').textContent = msg.Power;
|
document.getElementById('lcd-power-ist').textContent = msg.Power;
|
||||||
@@ -548,10 +552,11 @@ function onStirrerChanged(msg) {
|
|||||||
for (const key of Object.keys(msg)) {
|
for (const key of Object.keys(msg)) {
|
||||||
if (key === 'Speed') {
|
if (key === 'Speed') {
|
||||||
stirrerSpeedIst = msg.Speed;
|
stirrerSpeedIst = msg.Speed;
|
||||||
if (initialSpeedSync) {
|
const sudRunningSpd = RUNNING_STATES.has(sudState);
|
||||||
|
if (initialSpeedSync || sudRunningSpd) {
|
||||||
document.getElementById('stirrer-speed').value = msg.Speed;
|
document.getElementById('stirrer-speed').value = msg.Speed;
|
||||||
document.getElementById('stirrer-speed-readout').textContent = msg.Speed;
|
document.getElementById('stirrer-speed-readout').textContent = msg.Speed;
|
||||||
initialSpeedSync = false;
|
if (!sudRunningSpd) initialSpeedSync = false;
|
||||||
}
|
}
|
||||||
updateStirrerVisualization();
|
updateStirrerVisualization();
|
||||||
updateStepPlates();
|
updateStepPlates();
|
||||||
@@ -571,9 +576,10 @@ function onTempCtrlChanged(msg) {
|
|||||||
if ('Temp' in soll) {
|
if ('Temp' in soll) {
|
||||||
plotTempSoll = soll.Temp;
|
plotTempSoll = soll.Temp;
|
||||||
document.getElementById('lcd-temp-soll').textContent = soll.Temp.toFixed(1);
|
document.getElementById('lcd-temp-soll').textContent = soll.Temp.toFixed(1);
|
||||||
if (initialTempSollSync) {
|
const sudRunning = RUNNING_STATES.has(sudState);
|
||||||
|
if (initialTempSollSync || sudRunning) {
|
||||||
document.getElementById('temp-soll').value = Math.round(soll.Temp);
|
document.getElementById('temp-soll').value = Math.round(soll.Temp);
|
||||||
initialTempSollSync = false;
|
if (!sudRunning) initialTempSollSync = false;
|
||||||
}
|
}
|
||||||
document.getElementById('temp-soll-readout').textContent = document.getElementById('temp-soll').value;
|
document.getElementById('temp-soll-readout').textContent = document.getElementById('temp-soll').value;
|
||||||
updatePotVisualization();
|
updatePotVisualization();
|
||||||
@@ -583,9 +589,10 @@ function onTempCtrlChanged(msg) {
|
|||||||
if ('Current' in rate) {
|
if ('Current' in rate) {
|
||||||
document.getElementById('lcd-rate-soll').textContent = rate.Current.toFixed(1);
|
document.getElementById('lcd-rate-soll').textContent = rate.Current.toFixed(1);
|
||||||
}
|
}
|
||||||
if ('Set' in rate && initialHeatrateSync) {
|
const sudRunningHr = RUNNING_STATES.has(sudState);
|
||||||
|
if ('Set' in rate && (initialHeatrateSync || sudRunningHr)) {
|
||||||
document.getElementById('heatrate-soll').value = rate.Set;
|
document.getElementById('heatrate-soll').value = rate.Set;
|
||||||
initialHeatrateSync = false;
|
if (!sudRunningHr) initialHeatrateSync = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -635,6 +642,10 @@ function onSudChanged(msg) {
|
|||||||
}
|
}
|
||||||
wasRunning = isRunningNow;
|
wasRunning = isRunningNow;
|
||||||
sudState = newState;
|
sudState = newState;
|
||||||
|
const sliderDisabled = RUNNING_STATES.has(sudState);
|
||||||
|
for (const id of ['temp-soll', 'heatrate-soll', 'heater-power', 'stirrer-speed']) {
|
||||||
|
document.getElementById(id).disabled = sliderDisabled;
|
||||||
|
}
|
||||||
if (newState === WAIT_USER_STATE && prevState !== WAIT_USER_STATE && sudUserMessage) {
|
if (newState === WAIT_USER_STATE && prevState !== WAIT_USER_STATE && sudUserMessage) {
|
||||||
showUserMessage(sudUserMessage);
|
showUserMessage(sudUserMessage);
|
||||||
} else if (prevState === WAIT_USER_STATE && newState !== WAIT_USER_STATE) {
|
} else if (prevState === WAIT_USER_STATE && newState !== WAIT_USER_STATE) {
|
||||||
@@ -740,6 +751,10 @@ function connect() {
|
|||||||
ws = ws_;
|
ws = ws_;
|
||||||
statusEl.textContent = 'Connecting…';
|
statusEl.textContent = 'Connecting…';
|
||||||
ws.onopen = () => {
|
ws.onopen = () => {
|
||||||
|
initialPowerSync = true;
|
||||||
|
initialSpeedSync = true;
|
||||||
|
initialHeatrateSync = true;
|
||||||
|
initialTempSollSync = true;
|
||||||
setConnected(true);
|
setConnected(true);
|
||||||
for (const channel of CHANNELS) {
|
for (const channel of CHANNELS) {
|
||||||
ws.send(JSON.stringify({'+': channel}));
|
ws.send(JSON.stringify({'+': channel}));
|
||||||
@@ -754,7 +769,12 @@ function connect() {
|
|||||||
statusEl.textContent = `Could not connect to ${url}`;
|
statusEl.textContent = `Could not connect to ${url}`;
|
||||||
statusEl.className = 'status-disconnected';
|
statusEl.className = 'status-disconnected';
|
||||||
};
|
};
|
||||||
ws.onclose = () => setConnected(false);
|
ws.onclose = () => {
|
||||||
|
for (const id of ['temp-soll', 'heatrate-soll', 'heater-power', 'stirrer-speed']) {
|
||||||
|
document.getElementById(id).disabled = false;
|
||||||
|
}
|
||||||
|
setConnected(false);
|
||||||
|
};
|
||||||
ws.onmessage = (event) => {
|
ws.onmessage = (event) => {
|
||||||
const msg = JSON.parse(event.data);
|
const msg = JSON.parse(event.data);
|
||||||
for (const channel of Object.keys(msg)) {
|
for (const channel of Object.keys(msg)) {
|
||||||
|
|||||||
Reference in New Issue
Block a user