fix(oven): gate fast_preheat/natural_steam on their own tokens (#183)

Both switches were shipped unconditionally (no exists_fn) as an unverified
guess -- the module docstring already flagged them as "unproven." Every
range/oven fixture in the corpus, including the new issue #183 dump,
reports neither fastpreheat_* nor NaturalSteam_* in /mode/vs/0's options at
all, so both were phantom controls: always read as off, and toggling them
wrote a token the firmware never recognized in the first place. That
matches the reporter's exact complaint ("doesn't appear to do anything").

Also bound two tokens confirmed present on this dump but never modeled at
all: EnergySaving_On (the 120-hour energy-saving standby from the app) and
BurnerOnAlert_Off (cooktop-on alert), following the same single-token
options-merge pattern as the existing lamp/sound/fast_preheat switches.

Child lock, the setpoint mismatch, and the missing cook-start control from
this issue are not code bugs -- see the issue comment for what was verified
and what still needs more information from the reporter.
This commit is contained in:
Marc Billow committed 2026-07-29 13:26:39 +00:00
1 parent 487ac748bd
commit 36240b44e6
12 files changed
+399 -14

No files matched your search

@@ -130,6 +130,21 @@ def _option_value(options, prefix):
return None
def _has_option(prefix):
"""exists_fn for an options-array switch: bind only when the device's own
options[] actually carries a `<prefix>_<value>` token.
fast_preheat/natural_steam were shipped unconditionally (no exists_fn) as
an unverified guess (see module docstring) -- issue #183's dump (model
NE6516A) reports neither `fastpreheat_*` nor `NaturalSteam_*` in its
options[] at all, so both switches were phantom controls: always read as
off, and toggling them wrote a token the firmware never recognized in
the first place, hence "does not appear to do anything."
"""
return lambda rep, resources: _option_value(
rep.get('x.com.samsung.da.options'), prefix) is not None
def _option_write(prefix, new_value):
"""A one-token x.com.samsung.da.options write, mirroring
laundry.option_write. NOT independently confirmed on an oven -- issue
@@ -239,6 +254,26 @@ def _naturalsteam_write(p, rep, href=None):
}
def _energysaving_write(p, rep, href=None):
if p not in ('On', 'Off'):
return None
if not rep.get('x.com.samsung.da.options'):
return None
return ['mode', 'vs', '0'], {
'x.com.samsung.da.options': _option_write('EnergySaving', p),
}
def _burneronalert_write(p, rep, href=None):
if p not in ('On', 'Off'):
return None
if not rep.get('x.com.samsung.da.options'):
return None
return ['mode', 'vs', '0'], {
'x.com.samsung.da.options': _option_write('BurnerOnAlert', p),
}
# ---------------------------------------------------------------------------
# Capabilities
# ---------------------------------------------------------------------------
@@ -385,11 +420,30 @@ OVEN_MODE = Capability(
write_fn=_sound_write),
SwitchDesc(key='fast_preheat', field='x.com.samsung.da.options',
icon='mdi:fire',
exists_fn=_has_option('fastpreheat'),
value_fn=lambda opts: _option_value(opts, 'fastpreheat') == 'On',
write_fn=_fastpreheat_write),
SwitchDesc(key='natural_steam', field='x.com.samsung.da.options',
icon='mdi:kettle-steam',
exists_fn=_has_option('NaturalSteam'),
value_fn=lambda opts: _option_value(opts, 'NaturalSteam') == 'On',
write_fn=_naturalsteam_write),
# 120-hour energy-saving standby (issue #183): confirmed present in
# this unit's options[] (EnergySaving_On) and directly requested --
# unlike fast_preheat/natural_steam above, this token is real on this
# hardware, just previously unbound entirely.
SwitchDesc(key='energy_saving', field='x.com.samsung.da.options',
icon='mdi:leaf', entity_category='config',
exists_fn=_has_option('EnergySaving'),
value_fn=lambda opts: _option_value(opts, 'EnergySaving') == 'On',
write_fn=_energysaving_write),
# Cooktop-on alert (issue #183): also confirmed present
# (BurnerOnAlert_Off) though the reporter noted it mainly matters for
# the SmartThings app's own alerting, not local automation.
SwitchDesc(key='cooktop_on_alert', field='x.com.samsung.da.options',
icon='mdi:alert-circle-outline', entity_category='config',
exists_fn=_has_option('BurnerOnAlert'),
value_fn=lambda opts: _option_value(opts, 'BurnerOnAlert') == 'On',
write_fn=_burneronalert_write),
),
)
@@ -1025,6 +1025,12 @@
"natural_steam": {
"name": "Natural steam"
},
"energy_saving": {
"name": "Energy saving"
},
"cooktop_on_alert": {
"name": "Cooktop-on alert"
},
"power_switch": {
"name": "Power"
},
@@ -1025,6 +1025,12 @@
"natural_steam": {
"name": "Natuurlijke stoom"
},
"energy_saving": {
"name": "Energiebesparing"
},
"cooktop_on_alert": {
"name": "Waarschuwing kookplaat aan"
},
"power_switch": {
"name": "Voeding"
},