Redesign Sud schedule format: separate ramp/hold keys with defaults

Steps now declare a "ramp" or "hold" key instead of a flat "type", and
unspecified fields (including nested stirrer settings) fall back to a
new top-level default.step structure. Stirrer config is now
interval_time/on_ratio, mapping directly onto AStirrer's cycle
time/duty cycle instead of separate on/off durations. Update
components/sud.py, tasks/sud.py, the Sud demo, sude/sud_0010.json, and
the README to match.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CgR9tPaSzFkAwRAUyeaaCD
This commit is contained in:
2026-06-20 07:20:52 +02:00
co-authored by Claude Sonnet 4.6
parent 2dcf644bed
commit 123318ac85
5 changed files with 172 additions and 107 deletions
+18 -18
View File
@@ -19,34 +19,34 @@ class SudTask(ATask):
msg_handler.set_recv_handler(self.recv)
def apply_stirrer(self, step):
speed = step.get('stirrer_speed', 0)
on = step.get('stirrer_time_on', 0)
off = step.get('stirrer_time_off', 0)
cycle = on + off
if cycle > 0:
duty = on / cycle
stirrer_cfg = step.get('ramp', step.get('hold', {})).get('stirrer', {})
speed = stirrer_cfg.get('speed', 0)
interval_time = stirrer_cfg.get('interval_time', 0)
on_ratio = stirrer_cfg.get('on_ratio', 1.0)
if interval_time > 0:
self.stirrer.set_cycle_time(interval_time)
self.stirrer.set_duty_cycle(on_ratio)
else:
cycle = 1.0
duty = 1.0 if speed > 0 else 0.0
self.stirrer.set_cycle_time(cycle)
self.stirrer.set_duty_cycle(duty)
self.stirrer.set_cycle_time(1.0)
self.stirrer.set_duty_cycle(1.0 if speed > 0 else 0.0)
self.stirrer.set_speed(speed)
def on_step_changed(self, step):
ramp = step.get('ramp') if step else None
hold = step.get('hold') if step else None
if step is not None:
if step['type'] == 'heat':
self.tc.set_theta_soll(step['temp'])
self.tc.set_heatrate_soll(step['rate'])
if ramp is not None:
self.tc.set_theta_soll(ramp['temp'])
self.tc.set_heatrate_soll(ramp['rate'])
self.apply_stirrer(step)
asyncio.create_task(self.send({'Step': {
'Index': self.sud.index,
'Type': step['type'] if step else None,
'Type': 'ramp' if ramp is not None else 'hold' if hold is not None else None,
'Descr': step.get('descr') if step else None,
'Temp': step.get('temp') if step else None,
'Rate': step.get('rate') if step else None,
'Duration': step.get('duration') if step else None,
'Temp': ramp.get('temp') if ramp else None,
'Rate': ramp.get('rate') if ramp else None,
'Duration': hold.get('duration') if hold else None,
'WaitForUser': step.get('user_wait_for_continue', False) if step else None,
}}))