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:
+30
-3
@@ -20,6 +20,31 @@ class SudState(Enum):
|
||||
DONE = 4
|
||||
|
||||
|
||||
def _merge_defaults(default, override):
|
||||
"""Deep-merges override onto default, recursing into nested dicts so
|
||||
values missing from override fall back to default's at every level."""
|
||||
merged = dict(default)
|
||||
for key, value in override.items():
|
||||
if key in merged and isinstance(merged[key], dict) and isinstance(value, dict):
|
||||
merged[key] = _merge_defaults(merged[key], value)
|
||||
else:
|
||||
merged[key] = value
|
||||
return merged
|
||||
|
||||
|
||||
def _build_step(defaults, raw_step):
|
||||
"""Fills in a schedule step with default.step's values. A step is a
|
||||
ramp or a hold depending on which of those keys it specifies; the other
|
||||
is left out rather than synthesized from defaults."""
|
||||
step = {}
|
||||
for key in ('descr', 'user_message', 'user_wait_for_continue'):
|
||||
step[key] = raw_step.get(key, defaults.get(key))
|
||||
for key in ('ramp', 'hold'):
|
||||
if key in raw_step:
|
||||
step[key] = _merge_defaults(defaults.get(key, {}), raw_step[key])
|
||||
return step
|
||||
|
||||
|
||||
class Sud(AttributeChange):
|
||||
def __init__(self, path):
|
||||
AttributeChange.__init__(self)
|
||||
@@ -28,7 +53,9 @@ class Sud(AttributeChange):
|
||||
|
||||
self.name = data.get('Name', '')
|
||||
self.description = data.get('Description', '')
|
||||
self.schedule = data['schedule']
|
||||
|
||||
step_defaults = data.get('default', {}).get('step', {})
|
||||
self.schedule = [_build_step(step_defaults, raw) for raw in data['steps']]
|
||||
|
||||
self.pot_mass = data.get('pot_mass', 0)
|
||||
self.pot_material = data.get('pot_material')
|
||||
@@ -84,10 +111,10 @@ class Sud(AttributeChange):
|
||||
return
|
||||
|
||||
next_step = self.schedule[self.index]
|
||||
if next_step['type'] == 'heat':
|
||||
if 'ramp' in next_step:
|
||||
self.state = SudState.RAMPING
|
||||
else:
|
||||
self.hold_remaining = next_step.get('duration', 0)
|
||||
self.hold_remaining = next_step['hold'].get('duration', 0)
|
||||
self.state = SudState.HOLDING
|
||||
|
||||
self.user_message = next_step.get('user_message')
|
||||
|
||||
Reference in New Issue
Block a user