refactor: replace exact-href door/temp/icemaker caps with generic pattern caps
Delete dead: DOOR_FRIDGE, DOOR_FREEZER, TEMP_FRIDGE/FREEZER_CURRENT/SETPOINT, ICEMAKER_ONE, ICEMAKER_TWO, ICE2_MODES, temperature bounds constants. Add: TEMP_CURRENT_GENERIC (href_prefix=/temperature/current/), TEMP_SETPOINT_GENERIC (href_prefix=/temperature/desired/, write derives CoAP path from href), ICEMAKER_GENERIC (href_prefix=/icemaker/, match_fn gates on iceMaker.state field). Key derivation strips 'vs' segments alongside digits so icemaker hrefs like /icemaker/one/vs/0 produce icemaker_one_state not icemaker_one_vs_state. write_fn signature extended: adapter now passes href as 3rd positional arg; all existing write_fns updated to accept href=None. Fridge golden: old ice1_*/ice2_*/fridge_*/freezer_* keys replaced by icemaker_one_*/icemaker_two_*/temperature_current_*/temperature_desired_*.
This commit is contained in:
1 parent
9e5a169c82
commit
785154eb83
10 files changed
+116
-189
No files matched your search
@@ -118,7 +118,7 @@ def _make_command_handlers(bound):
|
||||
|
||||
def handler(payload, links, _fn=fn, _href=href):
|
||||
rep = (links or {}).get(_href) or {}
|
||||
return _fn(payload, rep)
|
||||
return _fn(payload, rep, _href)
|
||||
|
||||
out[f"cmd/{_key(b)}"] = handler
|
||||
return out
|
||||
|
||||
@@ -11,13 +11,7 @@ REGISTRY = DeviceRegistry(
|
||||
common.ALARMS,
|
||||
common.ENERGY_METER,
|
||||
common.WATER_FILTER,
|
||||
fridge.TEMP_FRIDGE_CURRENT,
|
||||
fridge.TEMP_FREEZER_CURRENT,
|
||||
fridge.TEMP_FRIDGE_SETPOINT,
|
||||
fridge.TEMP_FREEZER_SETPOINT,
|
||||
fridge.DOORS_STATUS,
|
||||
fridge.ICEMAKER_ONE,
|
||||
fridge.ICEMAKER_TWO,
|
||||
fridge.ICEMAKER_STATUS,
|
||||
fridge.REFRIGERATION,
|
||||
fridge.AUTOFILL,
|
||||
@@ -26,5 +20,10 @@ REGISTRY = DeviceRegistry(
|
||||
fridge.BEVERAGE_ZONE,
|
||||
fridge.FIRMWARE_UPDATE,
|
||||
]),
|
||||
pattern_capabilities=[fridge.DOOR_GENERIC],
|
||||
pattern_capabilities=[
|
||||
fridge.TEMP_CURRENT_GENERIC,
|
||||
fridge.TEMP_SETPOINT_GENERIC,
|
||||
fridge.ICEMAKER_GENERIC,
|
||||
fridge.DOOR_GENERIC,
|
||||
],
|
||||
)
|
||||
@@ -74,7 +74,7 @@ POWER = Capability(
|
||||
SwitchDesc(key='power_switch', field='x.com.samsung.da.power',
|
||||
name='Power',
|
||||
value_fn=lambda v: v == 'On',
|
||||
write_fn=lambda p, rep: (['power', 'vs', '0'], {'x.com.samsung.da.power': 'On' if p == 'On' else 'Off'})),
|
||||
write_fn=lambda p, rep, href=None: (['power', 'vs', '0'], {'x.com.samsung.da.power': 'On' if p == 'On' else 'Off'})),
|
||||
SensorDesc(key='power_state', field='x.com.samsung.da.power',
|
||||
name='Power state'),
|
||||
BinarySensorDesc(key='power_state_binary', field='x.com.samsung.da.power',
|
||||
|
||||
@@ -34,13 +34,13 @@ _COURSE_NAMES = {
|
||||
_COURSE_CODE_BY_NAME = {name: code for code, name in _COURSE_NAMES.items()}
|
||||
|
||||
|
||||
def _wrinkle_write(p, rep):
|
||||
def _wrinkle_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
return ['washer', 'vs', '0'], {'x.com.samsung.da.wrinklePrevent': p}
|
||||
|
||||
|
||||
def _course_write(p, rep):
|
||||
def _course_write(p, rep, href=None):
|
||||
"""Encode a human course name to the Samsung hex-encoded course string."""
|
||||
code = _COURSE_CODE_BY_NAME.get(p)
|
||||
if code is None:
|
||||
|
||||
@@ -3,30 +3,19 @@
|
||||
Resources verified against the dump at local-tools/dumps/10.0.0.254.json.
|
||||
|
||||
Temperature fields in all /temperature/* resources are in Fahrenheit on this
|
||||
model. Setpoints are NumberDesc with direct-write write_fn (no RMW needed
|
||||
because the individual /temperature/desired/* resources take a PUT with just
|
||||
the 'temperature' field, unlike the aggregated /temperatures/vs/0 path).
|
||||
model. Setpoints are NumberDesc with direct-write write_fn — generic caps
|
||||
derive the CoAP PUT path from href at write time.
|
||||
|
||||
Multi-instance note: the two door resources (/door/cooler/0 and
|
||||
/door/freezer/0) and the two ice-maker resources (/icemaker/one/vs/0 and
|
||||
/icemaker/two/vs/0) use named path segments, so they are modelled as separate
|
||||
Capability objects with distinct entity keys rather than a single capability
|
||||
replicated via instance_suffix.
|
||||
/icemaker/two/vs/0) use named path segments, so they are modelled via
|
||||
pattern capabilities that auto-derive distinct entity keys from href segments.
|
||||
"""
|
||||
from ..capability import Capability
|
||||
from ..entities import (
|
||||
BinarySensorDesc, NumberDesc, SelectDesc, SensorDesc, SwitchDesc,
|
||||
)
|
||||
|
||||
# Setpoint bounds (from /temperatures/vs/0 items on 2026-06-27)
|
||||
FREEZER_MIN_F = -8.0
|
||||
FREEZER_MAX_F = 5.0
|
||||
FRIDGE_MIN_F = 34.0
|
||||
FRIDGE_MAX_F = 44.0
|
||||
|
||||
# Whiskey ball ice sizes.
|
||||
ICE2_MODES = ('Off', 'WHISKEY_ICEBALL_3', 'WHISKEY_ICEBALL_6', 'WHISKEY_ICEBALL_9')
|
||||
|
||||
# Beverage zone flex modes.
|
||||
BZONE_MODES = ('SP_TTYPE_BEER_DRINKS', 'SP_TTYPE_WINE_DESSERT')
|
||||
|
||||
@@ -39,70 +28,67 @@ def _int(v):
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Temperatures
|
||||
# Temperature (generic — covers /temperature/current/* and /temperature/desired/*)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _fridge_setpoint_write(p, rep):
|
||||
try:
|
||||
temp = int(round(float(p)))
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
if not (FRIDGE_MIN_F <= temp <= FRIDGE_MAX_F):
|
||||
return None
|
||||
return ['temperature', 'desired', 'cooler', '0'], {'temperature': temp}
|
||||
|
||||
|
||||
def _freezer_setpoint_write(p, rep):
|
||||
try:
|
||||
temp = int(round(float(p)))
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
if not (FREEZER_MIN_F <= temp <= FREEZER_MAX_F):
|
||||
return None
|
||||
return ['temperature', 'desired', 'freezer', '0'], {'temperature': temp}
|
||||
|
||||
|
||||
TEMP_FRIDGE_CURRENT = Capability(
|
||||
href='/temperature/current/cooler/0',
|
||||
TEMP_CURRENT_GENERIC = Capability(
|
||||
href=None,
|
||||
href_prefix='/temperature/current/',
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
SensorDesc(key='fridge_temp_f', field='temperature',
|
||||
name='Fridge temperature', device_class='temperature',
|
||||
state_class='measurement', unit='°F', value_fn=_int),
|
||||
SensorDesc(key='temp_f', field='temperature',
|
||||
name=None, icon='mdi:thermometer'),
|
||||
),
|
||||
)
|
||||
|
||||
TEMP_FREEZER_CURRENT = Capability(
|
||||
href='/temperature/current/freezer/0',
|
||||
TEMP_SETPOINT_GENERIC = Capability(
|
||||
href=None,
|
||||
href_prefix='/temperature/desired/',
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
SensorDesc(key='freezer_temp_f', field='temperature',
|
||||
name='Freezer temperature', device_class='temperature',
|
||||
state_class='measurement', unit='°F', value_fn=_int),
|
||||
NumberDesc(key='temp_f', field='temperature',
|
||||
name=None, native_min=-20.0, native_max=50.0,
|
||||
write_fn=lambda p, rep, href=None: (
|
||||
[s for s in href.strip('/').split('/') if s],
|
||||
{'temperature': int(round(float(p)))}
|
||||
) if href else None),
|
||||
),
|
||||
)
|
||||
|
||||
TEMP_FRIDGE_SETPOINT = Capability(
|
||||
href='/temperature/desired/cooler/0',
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
NumberDesc(key='fridge_setpoint_f', field='temperature',
|
||||
name='Fridge setpoint', device_class='temperature',
|
||||
unit='°F', native_min=FRIDGE_MIN_F, native_max=FRIDGE_MAX_F,
|
||||
step=1.0, icon='mdi:thermometer-chevron-up',
|
||||
value_fn=_int, write_fn=_fridge_setpoint_write),
|
||||
),
|
||||
)
|
||||
# ---------------------------------------------------------------------------
|
||||
# Icemaker (generic — covers /icemaker/one/vs/0, /icemaker/two/vs/0)
|
||||
# /icemaker/status/vs/0 is kept as exact-href cap and binds first.
|
||||
# /icemaker/nighttime/vs/0 is excluded by match_fn (lacks iceMaker.state).
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
TEMP_FREEZER_SETPOINT = Capability(
|
||||
href='/temperature/desired/freezer/0',
|
||||
def _icemaker_write(field):
|
||||
return lambda p, rep, href=None: (
|
||||
[s for s in href.strip('/').split('/') if s],
|
||||
{field: p}
|
||||
) if href else None
|
||||
|
||||
ICEMAKER_GENERIC = Capability(
|
||||
href=None,
|
||||
href_prefix='/icemaker/',
|
||||
match_fn=lambda rep, resources: 'x.com.samsung.da.iceMaker.state' in rep,
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
NumberDesc(key='freezer_setpoint_f', field='temperature',
|
||||
name='Freezer setpoint', device_class='temperature',
|
||||
unit='°F', native_min=FREEZER_MIN_F, native_max=FREEZER_MAX_F,
|
||||
step=1.0, icon='mdi:thermometer-chevron-down',
|
||||
value_fn=_int, write_fn=_freezer_setpoint_write),
|
||||
SensorDesc(key='state', field='x.com.samsung.da.iceMaker.state',
|
||||
name=None, icon='mdi:cube-outline'),
|
||||
BinarySensorDesc(key='on', field='x.com.samsung.da.iceMaker.state',
|
||||
name=None, device_class='running',
|
||||
value_fn=lambda v: v == 'On'),
|
||||
SensorDesc(key='making_status',
|
||||
field='x.com.samsung.da.iceMaker.iceMakingStatus',
|
||||
name=None, icon='mdi:cube-outline'),
|
||||
SwitchDesc(key='enabled', field='x.com.samsung.da.iceMaker.state',
|
||||
name=None, icon='mdi:cube-outline',
|
||||
value_fn=lambda v: v == 'On',
|
||||
write_fn=_icemaker_write('x.com.samsung.da.iceMaker.state')),
|
||||
SelectDesc(key='type', field='x.com.samsung.da.iceType.desired',
|
||||
name=None, icon='mdi:cube-outline',
|
||||
options=(),
|
||||
write_fn=_icemaker_write('x.com.samsung.da.iceType.desired')),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -110,26 +96,6 @@ TEMP_FREEZER_SETPOINT = Capability(
|
||||
# Doors
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
DOOR_FRIDGE = Capability(
|
||||
href='/door/cooler/0',
|
||||
poll_tier='hot',
|
||||
entities=(
|
||||
BinarySensorDesc(key='door_fridge_open', field='openState',
|
||||
name='Fridge door', device_class='door',
|
||||
value_fn=lambda v: v == 'Open'),
|
||||
),
|
||||
)
|
||||
|
||||
DOOR_FREEZER = Capability(
|
||||
href='/door/freezer/0',
|
||||
poll_tier='hot',
|
||||
entities=(
|
||||
BinarySensorDesc(key='door_freezer_open', field='openState',
|
||||
name='Freezer door', device_class='door',
|
||||
value_fn=lambda v: v == 'Open'),
|
||||
),
|
||||
)
|
||||
|
||||
DOORS_STATUS = Capability(
|
||||
href='/doors/vs/0',
|
||||
poll_tier='hot',
|
||||
@@ -148,54 +114,9 @@ DOORS_STATUS = Capability(
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Ice makers
|
||||
# Ice maker status (exact-href — binds before ICEMAKER_GENERIC pattern)
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _ice1_write(p, rep):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
return ['icemaker', 'one', 'vs', '0'], {'x.com.samsung.da.iceMaker.state': p}
|
||||
|
||||
|
||||
def _ice2_type_write(p, rep):
|
||||
if p not in ICE2_MODES:
|
||||
return None
|
||||
return ['icemaker', 'two', 'vs', '0'], {'x.com.samsung.da.iceType.desired': p}
|
||||
|
||||
|
||||
ICEMAKER_ONE = Capability(
|
||||
href='/icemaker/one/vs/0',
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
SensorDesc(key='ice1_state', field='x.com.samsung.da.iceMaker.state',
|
||||
name='Ice maker (cubed) state', icon='mdi:cube'),
|
||||
BinarySensorDesc(key='ice1_on', field='x.com.samsung.da.iceMaker.state',
|
||||
name='Ice maker (cubed) on',
|
||||
device_class='running',
|
||||
value_fn=lambda v: v == 'On'),
|
||||
SensorDesc(key='ice1_making_status',
|
||||
field='x.com.samsung.da.iceMaker.iceMakingStatus',
|
||||
name='Ice maker (cubed) status', icon='mdi:cube'),
|
||||
SwitchDesc(key='ice1', field='x.com.samsung.da.iceMaker.state',
|
||||
name='Ice maker (cubed)', icon='mdi:cube',
|
||||
value_fn=lambda v: v == 'On',
|
||||
write_fn=_ice1_write),
|
||||
),
|
||||
)
|
||||
|
||||
ICEMAKER_TWO = Capability(
|
||||
href='/icemaker/two/vs/0',
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
SensorDesc(key='ice2_making_status',
|
||||
field='x.com.samsung.da.iceMaker.iceMakingStatus',
|
||||
name='Ice maker (whiskey) status', icon='mdi:circle'),
|
||||
SelectDesc(key='ice2_type', field='x.com.samsung.da.iceType.desired',
|
||||
name='Whiskey ball ice type', icon='mdi:circle',
|
||||
options=ICE2_MODES, write_fn=_ice2_type_write),
|
||||
),
|
||||
)
|
||||
|
||||
ICEMAKER_STATUS = Capability(
|
||||
href='/icemaker/status/vs/0',
|
||||
poll_tier='warm',
|
||||
@@ -210,7 +131,7 @@ ICEMAKER_STATUS = Capability(
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _refrigeration_write(field_name):
|
||||
def _write(p, rep):
|
||||
def _write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
return ['refrigeration', 'vs', '0'], {field_name: p}
|
||||
@@ -236,7 +157,7 @@ REFRIGERATION = Capability(
|
||||
# Autofill
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _autofill_write(p, rep):
|
||||
def _autofill_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
return ['autofill', 'vs', '0'], {'x.com.samsung.da.autofill': p}
|
||||
@@ -257,7 +178,7 @@ AUTOFILL = Capability(
|
||||
# Cabinet light
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _cabinet_light_write(p, rep):
|
||||
def _cabinet_light_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
return ['cabinet', 'light', 'total', 'vs', '0'], {
|
||||
@@ -285,7 +206,7 @@ CABINET_LIGHT = Capability(
|
||||
# Sabbath mode
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _sabbath_write(p, rep):
|
||||
def _sabbath_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
return ['sabbath', 'vs', '0'], {'x.com.samsung.da.sabbathMode': p}
|
||||
@@ -306,7 +227,7 @@ SABBATH = Capability(
|
||||
# Beverage zone
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _bzone_write(p, rep):
|
||||
def _bzone_write(p, rep, href=None):
|
||||
if p not in BZONE_MODES:
|
||||
return None
|
||||
return ['specialzone', 'one', 'vs', '0'], {'roomDesiredMode': p}
|
||||
|
||||
@@ -11,19 +11,19 @@ _LED_LEVELS = ('Low', 'High')
|
||||
_SOUND_MODES = ('voice', 'tone', 'mute')
|
||||
|
||||
|
||||
def _led_brightness_write(p, rep):
|
||||
def _led_brightness_write(p, rep, href=None):
|
||||
if p not in _LED_LEVELS:
|
||||
return None
|
||||
return ['doorled', 'light', 'vs', '0'], {'setBrightness': p}
|
||||
|
||||
|
||||
def _led_night_write(p, rep):
|
||||
def _led_night_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
return ['doorled', 'light', 'vs', '0'], {'setNightLight': p}
|
||||
|
||||
|
||||
def _sound_mode_write(p, rep):
|
||||
def _sound_mode_write(p, rep, href=None):
|
||||
if p not in _SOUND_MODES:
|
||||
return None
|
||||
return ['settings', 'sound', 'mode', 'vs', '0'], {'mode': p}
|
||||
|
||||
@@ -119,7 +119,7 @@ def _replace_in_options(options, prefix, new_value):
|
||||
# Write functions
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _oven_setpoint_write(p, rep):
|
||||
def _oven_setpoint_write(p, rep, href=None):
|
||||
"""RMW write to /temperatures/vs/0 items array."""
|
||||
try:
|
||||
temp = float(p)
|
||||
@@ -136,7 +136,7 @@ def _oven_setpoint_write(p, rep):
|
||||
return ['temperatures', 'vs', '0'], {'x.com.samsung.da.items': items}
|
||||
|
||||
|
||||
def _cook_time_write(p, rep):
|
||||
def _cook_time_write(p, rep, href=None):
|
||||
"""Write operationTime + remainingTime (H:MM:SS) from minutes."""
|
||||
try:
|
||||
minutes = int(round(float(p)))
|
||||
@@ -152,19 +152,19 @@ def _cook_time_write(p, rep):
|
||||
}
|
||||
|
||||
|
||||
def _stop_write(p, rep):
|
||||
def _stop_write(p, rep, href=None):
|
||||
return ['operational', 'state', 'vs', '0'], {
|
||||
'x.com.samsung.da.state': 'Ready',
|
||||
}
|
||||
|
||||
|
||||
def _oven_mode_write(p, rep):
|
||||
def _oven_mode_write(p, rep, href=None):
|
||||
if p not in _OVEN_MODES:
|
||||
return None
|
||||
return ['mode', 'vs', '0'], {'x.com.samsung.da.modes': [p]}
|
||||
|
||||
|
||||
def _lamp_write(p, rep):
|
||||
def _lamp_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
opts = list(rep.get('x.com.samsung.da.options') or [])
|
||||
@@ -175,7 +175,7 @@ def _lamp_write(p, rep):
|
||||
}
|
||||
|
||||
|
||||
def _sound_write(p, rep):
|
||||
def _sound_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
opts = list(rep.get('x.com.samsung.da.options') or [])
|
||||
@@ -186,7 +186,7 @@ def _sound_write(p, rep):
|
||||
}
|
||||
|
||||
|
||||
def _fastpreheat_write(p, rep):
|
||||
def _fastpreheat_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
opts = list(rep.get('x.com.samsung.da.options') or [])
|
||||
@@ -197,7 +197,7 @@ def _fastpreheat_write(p, rep):
|
||||
}
|
||||
|
||||
|
||||
def _naturalsteam_write(p, rep):
|
||||
def _naturalsteam_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
opts = list(rep.get('x.com.samsung.da.options') or [])
|
||||
|
||||
@@ -69,7 +69,7 @@ def discover(
|
||||
continue
|
||||
inst = instance_suffix(href)
|
||||
# Auto-derive key prefix from href: strip digits, join non-empty segs with '_'
|
||||
segs = [s for s in href.strip('/').split('/') if s and not s.isdigit()]
|
||||
segs = [s for s in href.strip('/').split('/') if s and not s.isdigit() and s != 'vs']
|
||||
for desc in cap.entities:
|
||||
key_override = '_'.join(segs) + '_' + desc.key
|
||||
out.append(BoundEntity(href=href, capability=cap, desc=desc,
|
||||
|
||||
+30
-22
@@ -13,21 +13,25 @@
|
||||
"filter_status",
|
||||
"filter_usage",
|
||||
"firmware_update",
|
||||
"freezer_setpoint_f",
|
||||
"freezer_temp_f",
|
||||
"fridge_setpoint_f",
|
||||
"fridge_temp_f",
|
||||
"ice1",
|
||||
"ice1_making_status",
|
||||
"ice1_on",
|
||||
"ice1_state",
|
||||
"ice2_making_status",
|
||||
"ice2_type",
|
||||
"ice_maker_enabled",
|
||||
"icemaker_one_enabled",
|
||||
"icemaker_one_making_status",
|
||||
"icemaker_one_on",
|
||||
"icemaker_one_state",
|
||||
"icemaker_one_type",
|
||||
"icemaker_two_enabled",
|
||||
"icemaker_two_making_status",
|
||||
"icemaker_two_on",
|
||||
"icemaker_two_state",
|
||||
"icemaker_two_type",
|
||||
"power_watts",
|
||||
"rapid_freezing",
|
||||
"rapid_fridge",
|
||||
"sabbath_mode"
|
||||
"sabbath_mode",
|
||||
"temperature_current_cooler_temp_f",
|
||||
"temperature_current_freezer_temp_f",
|
||||
"temperature_desired_cooler_temp_f",
|
||||
"temperature_desired_freezer_temp_f"
|
||||
],
|
||||
"discovery_unique_ids": [
|
||||
"samsung_refrigerator_alarm_code",
|
||||
@@ -43,20 +47,24 @@
|
||||
"samsung_refrigerator_filter_status",
|
||||
"samsung_refrigerator_filter_usage",
|
||||
"samsung_refrigerator_firmware_update",
|
||||
"samsung_refrigerator_freezer_setpoint_f",
|
||||
"samsung_refrigerator_freezer_temp_f",
|
||||
"samsung_refrigerator_fridge_setpoint_f",
|
||||
"samsung_refrigerator_fridge_temp_f",
|
||||
"samsung_refrigerator_ice1",
|
||||
"samsung_refrigerator_ice1_making_status",
|
||||
"samsung_refrigerator_ice1_on",
|
||||
"samsung_refrigerator_ice1_state",
|
||||
"samsung_refrigerator_ice2_making_status",
|
||||
"samsung_refrigerator_ice2_type",
|
||||
"samsung_refrigerator_ice_maker_enabled",
|
||||
"samsung_refrigerator_icemaker_one_enabled",
|
||||
"samsung_refrigerator_icemaker_one_making_status",
|
||||
"samsung_refrigerator_icemaker_one_on",
|
||||
"samsung_refrigerator_icemaker_one_state",
|
||||
"samsung_refrigerator_icemaker_one_type",
|
||||
"samsung_refrigerator_icemaker_two_enabled",
|
||||
"samsung_refrigerator_icemaker_two_making_status",
|
||||
"samsung_refrigerator_icemaker_two_on",
|
||||
"samsung_refrigerator_icemaker_two_state",
|
||||
"samsung_refrigerator_icemaker_two_type",
|
||||
"samsung_refrigerator_power_watts",
|
||||
"samsung_refrigerator_rapid_freezing",
|
||||
"samsung_refrigerator_rapid_fridge",
|
||||
"samsung_refrigerator_sabbath_mode"
|
||||
"samsung_refrigerator_sabbath_mode",
|
||||
"samsung_refrigerator_temperature_current_cooler_temp_f",
|
||||
"samsung_refrigerator_temperature_current_freezer_temp_f",
|
||||
"samsung_refrigerator_temperature_desired_cooler_temp_f",
|
||||
"samsung_refrigerator_temperature_desired_freezer_temp_f"
|
||||
]
|
||||
}
|
||||
@@ -25,12 +25,11 @@ def test_two_iceMakers_get_distinct_keys():
|
||||
resources = _load_resources('10.0.0.254')
|
||||
reg = refrigerator.REGISTRY
|
||||
bound = discover(resources, reg.capabilities, reg.pattern_capabilities)
|
||||
ice_keys = sorted(f"{b.desc.key}{b.instance}" for b in bound
|
||||
if b.desc.key.startswith('ice'))
|
||||
# ice1_* and ice2_* are distinct
|
||||
ice1_keys = [k for k in ice_keys if k.startswith('ice1')]
|
||||
ice2_keys = [k for k in ice_keys if k.startswith('ice2')]
|
||||
assert ice1_keys, "No ice1_* keys found"
|
||||
assert ice2_keys, "No ice2_* keys found"
|
||||
assert set(ice1_keys).isdisjoint(set(ice2_keys)), \
|
||||
f"ice1 and ice2 keys overlap: {ice1_keys} vs {ice2_keys}"
|
||||
ice_keys = sorted(_key(b) for b in bound if _key(b).startswith('icemaker_'))
|
||||
# icemaker_one_* and icemaker_two_* are distinct
|
||||
ice_one_keys = [k for k in ice_keys if k.startswith('icemaker_one_')]
|
||||
ice_two_keys = [k for k in ice_keys if k.startswith('icemaker_two_')]
|
||||
assert ice_one_keys, "No icemaker_one_* keys found"
|
||||
assert ice_two_keys, "No icemaker_two_* keys found"
|
||||
assert set(ice_one_keys).isdisjoint(set(ice_two_keys)), \
|
||||
f"icemaker_one and icemaker_two keys overlap: {ice_one_keys} vs {ice_two_keys}"
|
||||
Reference in new issue
Block a user