fix: fridge/washer coverage gaps from the #19-#27 dump batch
Six new diagnostics dumps, six gaps closed: - refrigerator: bind /diagnosis/vs/0 (reuse dishwasher.DIAGNOSIS -- same shape) into the refrigerator registry; it was never wired up there, tripping the coverage repair on any fridge that reports it (#20, #26). - refrigerator: add PANTRY_ZONE for the Cool Select Zone pantry compartment (/status/pantry/one/vs/0, x.com.samsung.da.mode/supportedOptions) -- same shape as BEVERAGE_ZONE but a distinct resource/field set (#20). - refrigerator: generalize FLEX_ZONE to identify the current mode by list membership in supportedOptions instead of a hardcoded CV_TTYPE_RF9000A_ prefix check. TP1X/Bespoke-class fridges use a CV_FDR_ prefix instead, which the old code didn't recognize -- the select existed but always read as unknown, and writing to it would have appended a duplicate CV_FDR_ flag rather than replacing the existing one (#26, #27; also closes #32). - common: add energy_saved_kwh (x.com.samsung.da.cumulativeSavedPower) and power_energy_kwh (x.com.samsung.da.cumulativeConsumption) to the shared energy meter, plus fridge-only energy_last_month_kwh/energy_this_month_kwh (monthlyConsumption/thismonthlyConsumption) -- all self-gating on field presence (#26). - by_type: add the WV consumer-model prefix (FlexWash twin washers, e.g. WV55M9600AW) to the by-model fallback map. These report no oneUiVersion and previously matched no prefix at all, so they fell all the way through to the unrecognized-device registry with zero capabilities bound (#19). - washer: add a self-gating dry_level select to WASHER_SETTINGS for washer/dryer combo units, which carry a writable dryLevel field directly on /washer/vs/0 with no separate dryer resource or course (#22). The reset-water-filter button and "ice type vs. two named icemakers" requests from #26/#27 are left alone -- no write contract or exclusivity behavior is evidenced in either dump, and both icemakers report On simultaneously on the Bespoke unit, so synthesizing a single-select would be a guess rather than a fix. Adds scrubbed fixtures + goldens for FlexWash, a washer/dryer combo, ARTIK051_REF_17K, and TP2X_REF_20K, plus unit tests for the new/changed capabilities.
This commit is contained in:
22 files changed
+1719
-11
No files matched your search
@@ -1,5 +1,5 @@
|
||||
"""Refrigerator device registry."""
|
||||
from ..capabilities import common, fridge, ignored
|
||||
from ..capabilities import common, dishwasher, fridge, ignored
|
||||
from ._base import DeviceRegistry, _build
|
||||
|
||||
REGISTRY = DeviceRegistry(
|
||||
@@ -17,6 +17,7 @@ REGISTRY = DeviceRegistry(
|
||||
common.ALARMS,
|
||||
common.ENERGY_METER,
|
||||
common.WATER_FILTER,
|
||||
dishwasher.DIAGNOSIS,
|
||||
fridge.ICEMAKER_NIGHTTIME,
|
||||
fridge.FLEX_ZONE,
|
||||
fridge.REFRIGERATION,
|
||||
@@ -26,6 +27,7 @@ REGISTRY = DeviceRegistry(
|
||||
fridge.CABINET_LIGHT_ENHANCED,
|
||||
fridge.SABBATH,
|
||||
fridge.BEVERAGE_ZONE,
|
||||
fridge.PANTRY_ZONE,
|
||||
fridge.FIRMWARE_UPDATE,
|
||||
fridge.DEFROST_DELAY,
|
||||
fridge.DEFROST_DELAY_NATIVE_DUPLICATE,
|
||||
|
||||
@@ -175,6 +175,31 @@ ENERGY_METER = Capability(
|
||||
state_class='total_increasing', unit='kWh', value_fn=wh_to_kwh,
|
||||
exists_fn=lambda rep, resources: (
|
||||
not rep or 'x.com.samsung.da.cumulativePower' in rep)),
|
||||
# cumulativeConsumption is a second, independently-varying running
|
||||
# total alongside cumulativePower -- some fridges (issue #26) report
|
||||
# both. Self-gates off where only cumulativePower is present.
|
||||
SensorDesc(key='power_energy_kwh', field='x.com.samsung.da.cumulativeConsumption',
|
||||
name='Power energy', device_class='energy',
|
||||
state_class='total_increasing', unit='kWh', value_fn=wh_to_kwh,
|
||||
exists_fn=lambda rep, resources: 'x.com.samsung.da.cumulativeConsumption' in rep),
|
||||
# AI Energy Mode's lifetime savings estimate vs. an unoptimized
|
||||
# baseline -- present on some models (e.g. TP1X_REF_21K, issue #21/
|
||||
# #27) and absent on others (issue #20/#26), unlike cumulativePower.
|
||||
SensorDesc(key='energy_saved_kwh', field='x.com.samsung.da.cumulativeSavedPower',
|
||||
name='Energy saved', device_class='energy',
|
||||
state_class='total_increasing', unit='kWh', value_fn=wh_to_kwh,
|
||||
exists_fn=lambda rep, resources: 'x.com.samsung.da.cumulativeSavedPower' in rep),
|
||||
# Monthly billing-cycle totals -- the completed prior month and the
|
||||
# in-progress current month. Not ever-increasing (each resets at
|
||||
# month boundary), so no state_class.
|
||||
SensorDesc(key='energy_last_month_kwh', field='x.com.samsung.da.monthlyConsumption',
|
||||
name='Energy (last month)', device_class='energy',
|
||||
unit='kWh', value_fn=wh_to_kwh,
|
||||
exists_fn=lambda rep, resources: 'x.com.samsung.da.monthlyConsumption' in rep),
|
||||
SensorDesc(key='energy_this_month_kwh', field='x.com.samsung.da.thismonthlyConsumption',
|
||||
name='Energy (this month)', device_class='energy',
|
||||
unit='kWh', value_fn=wh_to_kwh,
|
||||
exists_fn=lambda rep, resources: 'x.com.samsung.da.thismonthlyConsumption' in rep),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -502,17 +502,56 @@ BEVERAGE_ZONE = Capability(
|
||||
),
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Pantry / Cool Select Zone -- a convertible compartment toggled between
|
||||
# wine/deli/drinks temperature presets (issue #20). Same shape as
|
||||
# BEVERAGE_ZONE (a controllable named sub-zone with a mode + supported-modes
|
||||
# list) but a distinct resource/field set -- x.com.samsung.da.mode /
|
||||
# x.com.samsung.da.supportedOptions on /status/pantry/one/vs/0, rather than
|
||||
# roomDesiredMode/roomSupportedModes on /specialzone/one/vs/0. Only a "one"
|
||||
# instance has been seen; not generalized to a pattern cap until a second
|
||||
# instance turns up.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _pantry_write(p, rep, href=None):
|
||||
return ['status', 'pantry', 'one', 'vs', '0'], {'x.com.samsung.da.mode': p}
|
||||
|
||||
|
||||
PANTRY_ZONE = Capability(
|
||||
href='/status/pantry/one/vs/0',
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
SelectDesc(key='pantry_zone_mode', field='x.com.samsung.da.mode',
|
||||
name='Pantry zone mode', icon='mdi:glass-wine',
|
||||
translation_key='pantry_zone_mode',
|
||||
entity_category='config',
|
||||
options_field='x.com.samsung.da.supportedOptions',
|
||||
write_fn=_pantry_write),
|
||||
),
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Flex zone (convertible drawer — /mode/vs/0 on RF9000-class fridges)
|
||||
#
|
||||
# x.com.samsung.da.modes holds multiple orthogonal flags in one list.
|
||||
# The flex zone entry is identified by the CV_TTYPE_RF9000A_ prefix.
|
||||
# x.com.samsung.da.modes holds multiple orthogonal flags in one list; the
|
||||
# flex-zone entry is whichever item is also a member of supportedOptions --
|
||||
# the other flags (WATERFILTER_*, DEFROST_BLOCK_*, the CVN_*_ZONE marker)
|
||||
# never appear there. The prefix on that item varies by fridge family
|
||||
# (CV_TTYPE_RF9000A_ on RF9000-class, CV_FDR_ on Bespoke-class -- issue #27 /
|
||||
# #26, where the old CV_TTYPE_RF9000A_-only match left this entity bound but
|
||||
# stuck on None), so match by list membership instead of a hardcoded prefix.
|
||||
# Write replaces only that item; other flags are preserved.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _flex_zone_current(rep):
|
||||
modes = rep.get('x.com.samsung.da.modes') or []
|
||||
supported = set(rep.get('x.com.samsung.da.supportedOptions') or ())
|
||||
return next((m for m in modes if m in supported), None)
|
||||
|
||||
|
||||
def _flex_zone_write(p, rep, href=None):
|
||||
modes = list(rep.get('x.com.samsung.da.modes') or [])
|
||||
modes = [m for m in modes if not m.startswith('CV_TTYPE_RF9000A_')]
|
||||
supported = set(rep.get('x.com.samsung.da.supportedOptions') or ())
|
||||
modes = [m for m in (rep.get('x.com.samsung.da.modes') or []) if m not in supported]
|
||||
modes.append(p)
|
||||
return ['mode', 'vs', '0'], {'x.com.samsung.da.modes': modes}
|
||||
|
||||
@@ -522,16 +561,13 @@ FLEX_ZONE = Capability(
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
SelectDesc(key='flex_zone_mode',
|
||||
field='x.com.samsung.da.modes',
|
||||
name='Flex zone mode', icon='mdi:thermostat',
|
||||
translation_key='flex_zone_mode',
|
||||
entity_category='config',
|
||||
options_field='x.com.samsung.da.supportedOptions',
|
||||
exists_fn=lambda rep, resources: bool(
|
||||
rep.get('x.com.samsung.da.supportedOptions')),
|
||||
value_fn=lambda modes: next(
|
||||
(m for m in (modes or [])
|
||||
if m.startswith('CV_TTYPE_RF9000A_')), None),
|
||||
rep_fn=_flex_zone_current,
|
||||
write_fn=_flex_zone_write),
|
||||
),
|
||||
)
|
||||
|
||||
@@ -30,13 +30,25 @@
|
||||
"sp_ttype_wine_dessert": "Wine and Dessert"
|
||||
}
|
||||
},
|
||||
"pantry_zone_mode": {
|
||||
"state": {
|
||||
"fdr_wine": "Wine",
|
||||
"fdr_deli": "Deli",
|
||||
"fdr_drinks": "Drinks"
|
||||
}
|
||||
},
|
||||
"flex_zone_mode": {
|
||||
"state": {
|
||||
"cv_ttype_rf9000a_freeze": "Freeze",
|
||||
"cv_ttype_rf9000a_softfreeze": "Soft Freeze",
|
||||
"cv_ttype_rf9000a_meat_fish": "Meat/Fish",
|
||||
"cv_ttype_rf9000a_fruit_veggies": "Fruit & Veggies",
|
||||
"cv_ttype_rf9000a_beverage": "Beverage"
|
||||
"cv_ttype_rf9000a_beverage": "Beverage",
|
||||
"cv_fdr_wine": "Wine",
|
||||
"cv_fdr_deli": "Deli",
|
||||
"cv_fdr_beverage": "Beverage",
|
||||
"cv_fdr_meat": "Meat",
|
||||
"cv_fdr_soft_freezer": "Soft Freezer"
|
||||
}
|
||||
},
|
||||
"dishwasher_cycle": {
|
||||
|
||||
@@ -30,13 +30,25 @@
|
||||
"sp_ttype_wine_dessert": "Wine and Dessert"
|
||||
}
|
||||
},
|
||||
"pantry_zone_mode": {
|
||||
"state": {
|
||||
"fdr_wine": "Wine",
|
||||
"fdr_deli": "Deli",
|
||||
"fdr_drinks": "Drinks"
|
||||
}
|
||||
},
|
||||
"flex_zone_mode": {
|
||||
"state": {
|
||||
"cv_ttype_rf9000a_freeze": "Freeze",
|
||||
"cv_ttype_rf9000a_softfreeze": "Soft Freeze",
|
||||
"cv_ttype_rf9000a_meat_fish": "Meat/Fish",
|
||||
"cv_ttype_rf9000a_fruit_veggies": "Fruit & Veggies",
|
||||
"cv_ttype_rf9000a_beverage": "Beverage"
|
||||
"cv_ttype_rf9000a_beverage": "Beverage",
|
||||
"cv_fdr_wine": "Wine",
|
||||
"cv_fdr_deli": "Deli",
|
||||
"cv_fdr_beverage": "Beverage",
|
||||
"cv_fdr_meat": "Meat",
|
||||
"cv_fdr_soft_freezer": "Soft Freezer"
|
||||
}
|
||||
},
|
||||
"dishwasher_cycle": {
|
||||
|
||||
Reference in new issue
Block a user