Merge pull request #272 from mbillow/claude/issue-triaging-fuq5sn
Issue triage batch: dehumidifier, AC, dryer, fridge, dishwasher, climate fixes
This commit is contained in:
@@ -399,6 +399,24 @@ no `[%key:...%]` resolution (that's Core build tooling). Every other language
|
||||
must mirror `en.json` key for key — also enforced by
|
||||
`tests/test_translations.py`.
|
||||
|
||||
**Don't write a test that just re-asserts a translation string.** Adding
|
||||
labels is a data change, not a logic change, and `tests/test_translations.py`
|
||||
already holds the invariants that matter for data (every descriptor has a
|
||||
catalog entry, every language mirrors English key-for-key, no unresolved
|
||||
`[%key:...%]`). A test that loads the catalog and asserts
|
||||
`catalog["select"]["foo"]["state"]["16"] == "Cotton"` right after you just
|
||||
wrote that exact line into `en.json` doesn't exercise any code path — it
|
||||
re-states the JSON file in Python, passes by construction, and only ever
|
||||
fails when someone *correctly* edits the label later (a wording fix, a
|
||||
translator's improvement). It's not a regression test, because there's no
|
||||
`select.py`/`adapter.py` logic between "the JSON says X" and "the test reads
|
||||
X" for it to catch drift in. If a code/label mapping is worth locking in,
|
||||
test it through the code that actually consumes it instead — a write
|
||||
contract (`desc.write_fn(...)` returns the right raw code), a read contract
|
||||
(`flatten()` produces the right raw value from a fixture rep), or a routing
|
||||
decision — never a bare literal-string comparison against the catalog you
|
||||
just edited.
|
||||
|
||||
## 8. Coverage discipline: bound or ignored
|
||||
|
||||
Every href in the dump must resolve, or the repair fires. If a resource isn't
|
||||
|
||||
@@ -128,6 +128,23 @@ _HVAC_TO_DEVICE = {v: k for k, v in _DEVICE_TO_HVAC.items()}
|
||||
_AI_COMFORT_MODE = "AIComfort"
|
||||
PRESET_AI_COMFORT = "ai_comfort"
|
||||
|
||||
# Codes that appear in /mode/vs/0's supportedModes but are option/capability
|
||||
# flags rather than selectable thermodynamic operations -- dropped silently
|
||||
# (no _warn_unmapped call) rather than every owner of an affected unit
|
||||
# tripping the issue #93 warning on every start.
|
||||
#
|
||||
# HOMECARE_WIZARD_V2 (issue #235, TP2X_RAC_20K): also appears in
|
||||
# /configuration/vs/0's x.com.samsung.da.airconOptionList alongside
|
||||
# PRODUCT_GLOBAL/AI_3.0/SingleCommand_1 -- clearly a capability flag, not a
|
||||
# mode, on that resource. The unit's own `modes` (current mode) never
|
||||
# reported it as active across the reporter's logs, only ever a real
|
||||
# thermodynamic mode -- consistent with it being echoed into supportedModes
|
||||
# rather than genuinely selectable. Unlike _AI_COMFORT_MODE above, it isn't
|
||||
# modeled as a preset: there's no confirmation it's user-selectable at all,
|
||||
# so silently dropping it (rather than guessing a write contract) is the
|
||||
# 'don't guess' rule applied to a mode code instead of a resource field.
|
||||
_NON_HVAC_OPTION_CODES = frozenset({"HOMECARE_WIZARD_V2"})
|
||||
|
||||
# Fan (wind strength): device codes "0".."4" -> HA standard fan constants where
|
||||
# a clean match exists so they auto-localize; "turbo" is custom (translated).
|
||||
_DEVICE_TO_FAN: dict[str, str] = {
|
||||
@@ -363,7 +380,15 @@ class LocalThingsClimate(LocalThingsEntity, ClimateEntity):
|
||||
def _warn_unmapped(self, href: str, code: str) -> None:
|
||||
"""Log once per (href, code) when a device-reported mode has no
|
||||
entry in the relevant device<->HA map, so a real device gap surfaces
|
||||
in the log instead of silently vanishing (issue #93)."""
|
||||
in the log instead of silently vanishing (issue #93).
|
||||
|
||||
Falls back to `unique_id` when `entity_id` is unset (issue #235):
|
||||
this fires during setup's first discovery pass, before the entity is
|
||||
added to hass, so `entity_id` is always None at that point --
|
||||
indistinguishable across multiple same-type devices in the log.
|
||||
`unique_id` is set eagerly in `__init__` (see entity.py), so it's
|
||||
always available here even though `entity_id` isn't.
|
||||
"""
|
||||
key = (href, code)
|
||||
if key in self._warned_unmapped:
|
||||
return
|
||||
@@ -371,7 +396,7 @@ class LocalThingsClimate(LocalThingsEntity, ClimateEntity):
|
||||
_LOGGER.warning(
|
||||
"%s: device mode %r on %s has no HA mapping and was dropped; "
|
||||
"please file an issue with your diagnostics dump",
|
||||
self.entity_id,
|
||||
self.entity_id or self.unique_id,
|
||||
code,
|
||||
href,
|
||||
)
|
||||
@@ -472,7 +497,11 @@ class LocalThingsClimate(LocalThingsEntity, ClimateEntity):
|
||||
device = _first(self._rep(MODE_HREF).get(_MODES_FIELD))
|
||||
if device == _AI_COMFORT_MODE:
|
||||
return HVACMode.AUTO
|
||||
if device is not None and device not in _DEVICE_TO_HVAC:
|
||||
if (
|
||||
device is not None
|
||||
and device not in _DEVICE_TO_HVAC
|
||||
and device not in _NON_HVAC_OPTION_CODES
|
||||
):
|
||||
self._warn_unmapped(MODE_HREF, device)
|
||||
return _DEVICE_TO_HVAC.get(device, HVACMode.AUTO)
|
||||
|
||||
@@ -480,7 +509,7 @@ class LocalThingsClimate(LocalThingsEntity, ClimateEntity):
|
||||
def hvac_modes(self) -> list[HVACMode]:
|
||||
modes = [HVACMode.OFF]
|
||||
for m in self._supported(MODE_HREF):
|
||||
if m == _AI_COMFORT_MODE:
|
||||
if m == _AI_COMFORT_MODE or m in _NON_HVAC_OPTION_CODES:
|
||||
continue
|
||||
mapped = _DEVICE_TO_HVAC.get(m)
|
||||
if mapped is None:
|
||||
|
||||
@@ -259,6 +259,7 @@ _OIC_TYPE_TO_KEY: dict[str, str] = {
|
||||
"oic.d.refrigerator": "refrigerator",
|
||||
"oic.d.washer": "washer",
|
||||
"x.com.st.d.airqualitysensor": "air_monitor",
|
||||
"x.com.st.d.dehumidifier": "dehumidifier",
|
||||
"x.com.st.d.hood": "range_hood", # AHD-WW-TP1-22-COMMON
|
||||
"x.com.st.d.stickcleaner": "vacuum_station",
|
||||
"x.com.st.d.steamcloset": "air_dresser",
|
||||
|
||||
@@ -33,8 +33,11 @@ REGISTRY = DeviceRegistry(
|
||||
airconditioner.AIR_PURIFY,
|
||||
airconditioner.AUTO_CLEAN,
|
||||
airconditioner.AIR_FILTER,
|
||||
airconditioner.AIR_FILTER_PM1,
|
||||
airconditioner.AIR_QUALITY,
|
||||
airconditioner.DISPLAY_LIGHT,
|
||||
airconditioner.UV_LED,
|
||||
airconditioner.VENTILATION_ALARM,
|
||||
airconditioner.MUTE_ONCE,
|
||||
airconditioner.CURRENT_LIMIT,
|
||||
airconditioner.ANOMALY_LOAD,
|
||||
|
||||
@@ -2,10 +2,13 @@
|
||||
|
||||
Shares the DA_AC_ board family with airconditioner.py (power, air filter,
|
||||
auto-clean, mute-once all use the identical resource shapes), so those three
|
||||
Capability objects are reused directly rather than duplicated.
|
||||
Capability objects are reused directly rather than duplicated. The
|
||||
TP1X_DA_AC_DHM_01001_0000 revision (issues #271/#231) also reports
|
||||
air_purifier.py's screen-on/off resource on the identical href/shape, so
|
||||
that's reused too rather than re-defined.
|
||||
"""
|
||||
|
||||
from ..capabilities import airconditioner, common, dehumidifier, ignored
|
||||
from ..capabilities import air_purifier, airconditioner, common, dehumidifier, ignored
|
||||
from ._base import DeviceRegistry, _build
|
||||
|
||||
REGISTRY = DeviceRegistry(
|
||||
@@ -17,9 +20,11 @@ REGISTRY = DeviceRegistry(
|
||||
*common.POWER,
|
||||
dehumidifier.MODE,
|
||||
dehumidifier.HUMIDITY,
|
||||
dehumidifier.WATERTANK_LIGHTING,
|
||||
airconditioner.AUTO_CLEAN,
|
||||
airconditioner.AIR_FILTER,
|
||||
airconditioner.MUTE_ONCE,
|
||||
air_purifier.DISPLAY,
|
||||
*dehumidifier.COVERAGE,
|
||||
]
|
||||
),
|
||||
|
||||
@@ -28,6 +28,7 @@ REGISTRY = DeviceRegistry(
|
||||
fridge.DEFROST_DELAY_NATIVE_DUPLICATE,
|
||||
fridge.DEFROST_BLOCK_STATUS,
|
||||
fridge.DEFINITE_TEMPERATURE_COOLER,
|
||||
fridge.DEFINITE_TEMPERATURE_FREEZER,
|
||||
fridge.DOORS_FALLBACK,
|
||||
fridge.TEMPERATURES_FALLBACK,
|
||||
fridge.ICEMAKER_STATUS_FALLBACK,
|
||||
|
||||
@@ -909,6 +909,80 @@ AIR_FILTER = Capability(
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _pm1_threshold_write(payload, rep, href=None):
|
||||
"""Same contract as _threshold_write, against this filter's own href --
|
||||
not yet confirmed live (no dump seen advertises
|
||||
supportedFilterDesiredUsage for this href), so the Select this backs
|
||||
stays gated behind that field's presence, same as AIR_FILTER's."""
|
||||
return ["filter", "airdustPM1filter", "vs", "0"], {
|
||||
"x.com.samsung.da.filterDesiredUsage": payload,
|
||||
}
|
||||
|
||||
|
||||
def _has_filter_field(field):
|
||||
return lambda rep, resources: rep.get(field) is not None
|
||||
|
||||
|
||||
# Second, PM1-rated dust filter some TP1X_FAC-class boards report alongside
|
||||
# AIR_FILTER's /filter/airdustfilter/vs/0. TP1X_FAC_TIME_23K (issue #270)
|
||||
# reports only filterCapacity/filterCapacityUnit/filterResetType
|
||||
# ('notresetable') on this href, with no live filterUsage/filterStatus at
|
||||
# all -- but the TP1X_DA-AC-CAC-01001_0000 cassette AC (issue #191) reports
|
||||
# the identical href with full live fields. So this stays a real capability
|
||||
# rather than a blanket ignore, with every entity individually gated on its
|
||||
# own field's presence per the 'don't guess' rule: no entity on a board that
|
||||
# has nothing behind it, real readings on one that does.
|
||||
AIR_FILTER_PM1 = Capability(
|
||||
href="/filter/airdustPM1filter/vs/0",
|
||||
poll_tier="cold",
|
||||
entities=(
|
||||
SensorDesc(
|
||||
key="air_filter_pm1_usage",
|
||||
rep_fn=filter_usage_percent,
|
||||
unit="%",
|
||||
state_class="measurement",
|
||||
icon="mdi:air-filter",
|
||||
entity_category="diagnostic",
|
||||
exists_fn=_has_filter_field("x.com.samsung.da.filterUsage"),
|
||||
),
|
||||
SensorDesc(
|
||||
key="air_filter_pm1_usage_hours",
|
||||
field="x.com.samsung.da.filterUsage",
|
||||
device_class="duration",
|
||||
state_class="total_increasing",
|
||||
unit_fn=_filter_unit,
|
||||
icon="mdi:air-filter",
|
||||
entity_category="diagnostic",
|
||||
value_fn=_int,
|
||||
exists_fn=_has_filter_field("x.com.samsung.da.filterUsage"),
|
||||
),
|
||||
SelectDesc(
|
||||
key="air_filter_pm1_threshold",
|
||||
field="x.com.samsung.da.filterDesiredUsage",
|
||||
options_field="x.com.samsung.da.supportedFilterDesiredUsage",
|
||||
exists_fn=lambda rep, res: bool(
|
||||
rep.get("x.com.samsung.da.supportedFilterDesiredUsage")
|
||||
),
|
||||
icon="mdi:alarm",
|
||||
entity_category="config",
|
||||
write_fn=_pm1_threshold_write,
|
||||
value_fn=lambda v: str(v) if v is not None else None,
|
||||
),
|
||||
SensorDesc(
|
||||
key="air_filter_pm1_status",
|
||||
field="x.com.samsung.da.filterStatus",
|
||||
device_class="enum",
|
||||
options=("normal", "wash", "replace"),
|
||||
translation_key="filter_status",
|
||||
icon="mdi:air-filter",
|
||||
entity_category="diagnostic",
|
||||
value_fn=lambda v: v.lower() if isinstance(v, str) else v,
|
||||
exists_fn=_has_filter_field("x.com.samsung.da.filterStatus"),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
DISPLAY_LIGHT = Capability(
|
||||
href="/light/vs/0",
|
||||
poll_tier="cold",
|
||||
@@ -927,6 +1001,51 @@ DISPLAY_LIGHT = Capability(
|
||||
),
|
||||
)
|
||||
|
||||
# UV-C sterilization LED (issue #270, TP1X_FAC_TIME_23K). Same On/Off
|
||||
# convention as everything else on this board, and (unlike VENTILATION_ALARM
|
||||
# below) a real supportedModes list confirms the value set.
|
||||
UV_LED = Capability(
|
||||
href="/uvled/vs/0",
|
||||
poll_tier="cold",
|
||||
entities=(
|
||||
SwitchDesc(
|
||||
key="uv_led",
|
||||
field="x.com.samsung.da.modes",
|
||||
icon="mdi:lightbulb-fluorescent-tube",
|
||||
entity_category="config",
|
||||
value_fn=lambda v: v == "On",
|
||||
write_fn=lambda p, rep, href=None: (
|
||||
["uvled", "vs", "0"],
|
||||
{"x.com.samsung.da.modes": "On" if p == "On" else "Off"},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# Ventilation-reminder alarm toggle (issue #270). Only a bare `alarm` field
|
||||
# is present -- no supportedModes list to confirm the value set against,
|
||||
# unlike UV_LED above. Modeled as a switch on the strength of the same
|
||||
# On/Off convention used everywhere else in this API; a rejected write is
|
||||
# the worst case for a wrong guess (see the adding-device-support skill),
|
||||
# but this hasn't been round-trip confirmed on real hardware.
|
||||
VENTILATION_ALARM = Capability(
|
||||
href="/ventilation/setting/vs/0",
|
||||
poll_tier="cold",
|
||||
entities=(
|
||||
SwitchDesc(
|
||||
key="ventilation_alarm",
|
||||
field="alarm",
|
||||
icon="mdi:bell-alert",
|
||||
entity_category="config",
|
||||
value_fn=lambda v: v == "On",
|
||||
write_fn=lambda p, rep, href=None: (
|
||||
["ventilation", "setting", "vs", "0"],
|
||||
{"alarm": "On" if p == "On" else "Off"},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# Confirmed against issue #38's dump (TP1X_DA-AC-RAC-01001_0000): a single
|
||||
# boolean field, no vendor prefix, mirroring the On/Off convention used
|
||||
# throughout the rest of this API.
|
||||
|
||||
@@ -9,7 +9,7 @@ entities rather than folded into one card.
|
||||
"""
|
||||
|
||||
from ..capability import Capability
|
||||
from ..entities import NumberDesc, SelectDesc, SensorDesc
|
||||
from ..entities import NumberDesc, SelectDesc, SensorDesc, SwitchDesc
|
||||
from .common import int_or_none
|
||||
|
||||
|
||||
@@ -77,6 +77,60 @@ HUMIDITY = Capability(
|
||||
),
|
||||
)
|
||||
|
||||
# Water-tank ambient light (issues #271/#231, TP1X_DA_AC_DHM_01001_0000):
|
||||
# on/off, color, and brightness are three independent controls on this one
|
||||
# resource. `waterfullAlarmStatus` differs between the two dumps that
|
||||
# reported this href (On vs. Off) so it's a real live flag, not a constant --
|
||||
# but its exact meaning (tank actually full vs. the chime feature merely
|
||||
# enabled) isn't confirmed by either dump alone, and /alarms/vs/0's
|
||||
# alarm_code already surfaces a live WaterTankFull condition when one fires
|
||||
# (see common._active_alarm_codes), so this is exposed read-only as a plain
|
||||
# diagnostic value rather than guessed at as a binary_sensor.
|
||||
WATERTANK_LIGHTING = Capability(
|
||||
href="/watertank/lighting/vs/0",
|
||||
poll_tier="cold",
|
||||
entities=(
|
||||
SwitchDesc(
|
||||
key="watertank_light",
|
||||
field="status",
|
||||
icon="mdi:led-on",
|
||||
entity_category="config",
|
||||
value_fn=lambda v: v == "On",
|
||||
write_fn=lambda p, rep, href=None: (
|
||||
["watertank", "lighting", "vs", "0"],
|
||||
{"status": "On" if p == "On" else "Off"},
|
||||
),
|
||||
),
|
||||
SelectDesc(
|
||||
key="watertank_light_color",
|
||||
field="colorOption",
|
||||
icon="mdi:palette",
|
||||
entity_category="config",
|
||||
options_field="colorSupportedList",
|
||||
write_fn=lambda p, rep, href=None: (
|
||||
["watertank", "lighting", "vs", "0"],
|
||||
{"colorOption": p},
|
||||
),
|
||||
),
|
||||
SelectDesc(
|
||||
key="watertank_light_brightness",
|
||||
field="mode",
|
||||
icon="mdi:brightness-6",
|
||||
entity_category="config",
|
||||
options_field="modeSupportedList",
|
||||
write_fn=lambda p, rep, href=None: (
|
||||
["watertank", "lighting", "vs", "0"],
|
||||
{"mode": p},
|
||||
),
|
||||
),
|
||||
SensorDesc(
|
||||
key="watertank_full_alarm_status",
|
||||
field="waterfullAlarmStatus",
|
||||
entity_category="diagnostic",
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Dehumidifier-scoped coverage: vendor plumbing with no user-actionable state
|
||||
# or no documented write contract, following the same 'don't guess' rule as
|
||||
|
||||
@@ -48,6 +48,18 @@ DISHWASHER_SETTINGS = Capability(
|
||||
# boolean-toggle contract washer's bubble-soak/pre-wash/intensive switches
|
||||
# use). Course display names live in translations under
|
||||
# entity.select.dishwasher_cycle (see laundry.cycle_select).
|
||||
#
|
||||
# '83'/'86' were transposed in that catalog until issue #226: both the
|
||||
# original DW9000F-class fixture this table was built from and the issue
|
||||
# #226 reporter's board report the identical DeviceType_0812 (a real
|
||||
# per-board-generation id also seen on unrelated washer/dryer fixtures, so
|
||||
# this is one shared course table, not a Table_02/Table_03-style generation
|
||||
# split), and the original fixture's own live editCourseList
|
||||
# ('EditCourseList_0E07908683848D808E8F') puts '86' and '83' back to back at
|
||||
# positions 4-5 -- exactly the kind of adjacent pair a manual screenshot
|
||||
# transcription slips on. The reporter's live confirmation (selecting
|
||||
# 'Normal' ran the physical Express 60 program and vice versa) settles
|
||||
# which way: '86' is Express 60, '83' is Normal.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
CYCLE_OPTIONS = Capability(
|
||||
|
||||
@@ -11,7 +11,7 @@ the /course/vs/0 cycle select -- lives in laundry.py.
|
||||
|
||||
from ..capability import Capability
|
||||
from ..entities import SensorDesc, SwitchDesc
|
||||
from .laundry import cycle_select
|
||||
from .laundry import cycle_select, drum_clean_cycles_remaining, drum_clean_last_cleaned
|
||||
|
||||
|
||||
def _wrinkle_write(p, rep, href=None):
|
||||
@@ -41,14 +41,25 @@ DRYER_SETTINGS = Capability(
|
||||
# laundry.cycle_select (options read live from /wm/editcourse/vs/0, written as
|
||||
# an RMW on the options array). Course display names live in translations
|
||||
# under entity.select.dryer_cycle (Table_03, DV5000-class, captured
|
||||
# 2026-05-29). Codes 0x21 and 0x4C appear in the issue #14 DV90BB5245AES1
|
||||
# editCourseList but aren't identified yet -- they render as the raw code
|
||||
# until named. Codes '01' Normal and '06' Time dry were confirmed on a
|
||||
# 2026-05-29). Codes '01' Normal and '06' Time dry were confirmed on a
|
||||
# DVE50A8600V/A3 (also Table_03) by selecting each cycle on the physical
|
||||
# appliance and reading back the raw code from the entity's state (issue
|
||||
# #80). The /st/dryercourse/vs/0 resource re-encodes the same selected
|
||||
# course and is ignored (ignored.py) -- the mirror of how /st/washercourse/vs/0
|
||||
# is ignored for washers.
|
||||
# #80). Codes '51' Eco Cotton, '53' AI Dry+, and '4e' Self Dry were
|
||||
# confirmed the same way on a DV90DG6845LHU5 (issue #244). The
|
||||
# /st/dryercourse/vs/0 resource re-encodes the same selected course and is
|
||||
# ignored (ignored.py) -- the mirror of how /st/washercourse/vs/0 is ignored
|
||||
# for washers.
|
||||
#
|
||||
# Drum Clean+ maintenance tracking (issue #258) reuses washer.py's
|
||||
# DrumCleanProposal_/WashingTimes_/DrumCleanLog_ tokens on this same
|
||||
# options[] array -- see laundry.drum_clean_cycles_remaining/
|
||||
# drum_clean_last_cleaned's docstrings for the field contract, including
|
||||
# the dryer-specific '|'-joined multi-entry DrumCleanLog_ shape. No
|
||||
# separate heat-exchanger-clean tracking was found on either dump #258
|
||||
# supplied (DV90BB7445GES7, DV91T6440LE/SA) -- no HeatExchanger*-prefixed
|
||||
# token, nor any other options[] entry that looks like a second maintenance
|
||||
# counter -- so if the Samsung app surfaces that reminder for these units,
|
||||
# it isn't computed from anything this integration can read locally.
|
||||
DRYER_COURSE = Capability(
|
||||
href="/course/vs/0",
|
||||
entities=(
|
||||
@@ -57,6 +68,22 @@ DRYER_COURSE = Capability(
|
||||
icon="mdi:tumble-dryer",
|
||||
table_href="/st/dryercourse/vs/0",
|
||||
),
|
||||
SensorDesc(
|
||||
key="drum_clean_cycles_remaining",
|
||||
unit="cycles",
|
||||
icon="mdi:tumble-dryer-alert",
|
||||
state_class="measurement",
|
||||
exists_fn=lambda rep, resources: drum_clean_cycles_remaining(rep) is not None,
|
||||
rep_fn=drum_clean_cycles_remaining,
|
||||
),
|
||||
SensorDesc(
|
||||
key="drum_clean_last_cleaned",
|
||||
device_class="timestamp",
|
||||
icon="mdi:calendar-clock",
|
||||
entity_category="diagnostic",
|
||||
exists_fn=lambda rep, resources: drum_clean_last_cleaned(rep) is not None,
|
||||
rep_fn=drum_clean_last_cleaned,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
@@ -163,6 +163,34 @@ DEFINITE_TEMPERATURE_COOLER = Capability(
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def _definite_freezer_write(p, rep, href=None):
|
||||
return (
|
||||
["temperature", "definite", "freezer", "vs", "0"],
|
||||
{"x.com.samsung.da.definite.desired": p},
|
||||
)
|
||||
|
||||
|
||||
# Freezer half of the same discrete-setpoint pattern (issue #229): a
|
||||
# fridge/freezer combo reporting no /temperature/current|desired/freezer
|
||||
# pair, only this bundled vendor resource -- identical shape to
|
||||
# DEFINITE_TEMPERATURE_COOLER above (down to the field names), just negative
|
||||
# supportedList values (e.g. ['-23','-21','-19','-17','-15']).
|
||||
DEFINITE_TEMPERATURE_FREEZER = Capability(
|
||||
href="/temperature/definite/freezer/vs/0",
|
||||
poll_tier="warm",
|
||||
entities=(
|
||||
SelectDesc(
|
||||
key="freezer_temperature_setpoint",
|
||||
field="x.com.samsung.da.definite.desired",
|
||||
icon="mdi:thermometer",
|
||||
entity_category="config",
|
||||
options_field="x.com.samsung.da.definite.supportedList",
|
||||
write_fn=_definite_freezer_write,
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Icemaker nighttime quiet mode
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -20,6 +20,7 @@ Door-LED keys use NO `x.com.samsung.da.` prefix -- `setBrightness` /
|
||||
`setNightLight` -- preserved exactly as they appear in the OCF resource rep.
|
||||
"""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
from datetime import time as dt_time
|
||||
|
||||
from ...catalog import has_entity_translation
|
||||
@@ -234,6 +235,47 @@ def option_value(options, prefix):
|
||||
return None
|
||||
|
||||
|
||||
# Drum Clean+ maintenance tracking, from the same options[] array as the
|
||||
# selected course -- shared by washer.py (issue #9) and dryer.py (issue
|
||||
# #258); both families use identical DrumCleanProposal_/WashingTimes_/
|
||||
# DrumCleanLog_ tokens. DrumCleanProposal_<N> is the wash/dry-cycle interval
|
||||
# between recommended cleans; WashingTimes_<N> is the count since the last
|
||||
# one -- their difference is exactly the "N cycles until due" figure the
|
||||
# Samsung app shows (verified on a washer: DrumCleanProposal_40 -
|
||||
# WashingTimes_3 == 37, matching a live app screenshot's "Potreba cistenia
|
||||
# po 37 cykloch").
|
||||
def drum_clean_cycles_remaining(rep):
|
||||
opts = rep.get("x.com.samsung.da.options") or []
|
||||
proposal = option_value(opts, "DrumCleanProposal")
|
||||
washed = option_value(opts, "WashingTimes")
|
||||
if proposal is None or washed is None:
|
||||
return None
|
||||
try:
|
||||
return max(int(proposal) - int(washed), 0)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
# DrumCleanLog_ is the clean-history field: a washer reports one bare ISO
|
||||
# datetime (the last clean, verified against the same app screenshot's "10
|
||||
# days ago"); a dryer (issue #258's Dillton-reported dump) instead reports a
|
||||
# '|'-joined history of every past clean, ten deep on that dump, in
|
||||
# strictly increasing order. Splitting on '|' and taking the last element
|
||||
# handles both shapes identically -- a no-'|' value is unaffected. No
|
||||
# explicit timezone field accompanies either shape, so it's treated as UTC,
|
||||
# matching this integration's convention for other bare ISO datetime fields
|
||||
# (see fridge.py's night-light schedule comment).
|
||||
def drum_clean_last_cleaned(rep):
|
||||
raw = option_value(rep.get("x.com.samsung.da.options"), "DrumCleanLog")
|
||||
if not raw:
|
||||
return None
|
||||
last = raw.rsplit("|", 1)[-1]
|
||||
try:
|
||||
return datetime.fromisoformat(last).replace(tzinfo=UTC)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def _course_codes_from_supported_options(course_rep):
|
||||
"""Fallback for an empty/missing editCourseList: derive the selectable
|
||||
course list from /course/vs/0's own x.com.samsung.da.supportedOptions
|
||||
|
||||
@@ -15,8 +15,6 @@ here; they read washer-only fields off the same shared /course/vs/0 options
|
||||
array.
|
||||
"""
|
||||
|
||||
from datetime import UTC, datetime
|
||||
|
||||
from ..capability import Capability
|
||||
from ..entities import BinarySensorDesc, SelectDesc, SensorDesc
|
||||
from .laundry import (
|
||||
@@ -24,6 +22,8 @@ from .laundry import (
|
||||
bool_option_switch,
|
||||
cycle_options,
|
||||
cycle_select,
|
||||
drum_clean_cycles_remaining,
|
||||
drum_clean_last_cleaned,
|
||||
hex_pairs,
|
||||
option_value,
|
||||
option_write,
|
||||
@@ -149,36 +149,10 @@ WASHER_SETTINGS = Capability(
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
# Drum Clean+ maintenance tracking, from the same options[] array as the
|
||||
# selected course. DrumCleanProposal_<N> is the wash-cycle interval between
|
||||
# recommended cleans; WashingTimes_<N> is the count since the last one --
|
||||
# their difference is exactly the "N cycles until due" figure the Samsung
|
||||
# app shows (verified: DrumCleanProposal_40 - WashingTimes_3 == 37, matching
|
||||
# a live app screenshot's "Potreba cistenia po 37 cykloch"). DrumCleanLog_
|
||||
# is the last-clean timestamp (verified against the same screenshot's "10
|
||||
# days ago"); no explicit timezone field accompanies it on this resource,
|
||||
# so it's treated as UTC, matching this integration's convention for other
|
||||
# bare ISO datetime fields (see fridge.py's night-light schedule comment).
|
||||
def _drum_clean_cycles_remaining(rep):
|
||||
opts = rep.get("x.com.samsung.da.options") or []
|
||||
proposal = option_value(opts, "DrumCleanProposal")
|
||||
washed = option_value(opts, "WashingTimes")
|
||||
if proposal is None or washed is None:
|
||||
return None
|
||||
try:
|
||||
return max(int(proposal) - int(washed), 0)
|
||||
except ValueError:
|
||||
return None
|
||||
|
||||
|
||||
def _drum_clean_last_cleaned(rep):
|
||||
raw = option_value(rep.get("x.com.samsung.da.options"), "DrumCleanLog")
|
||||
if not raw:
|
||||
return None
|
||||
try:
|
||||
return datetime.fromisoformat(raw).replace(tzinfo=UTC)
|
||||
except ValueError:
|
||||
return None
|
||||
# Drum Clean+ maintenance tracking (issue #9): drum_clean_cycles_remaining/
|
||||
# drum_clean_last_cleaned live in laundry.py, shared with dryer.py (issue
|
||||
# #258) since both families report identical DrumCleanProposal_/
|
||||
# WashingTimes_/DrumCleanLog_ tokens on the same options[] array.
|
||||
|
||||
|
||||
# Detergent/softener auto-dispense dosing, from the same options[] array
|
||||
@@ -340,16 +314,16 @@ WASHER_COURSE = Capability(
|
||||
unit="cycles",
|
||||
icon="mdi:washing-machine-alert",
|
||||
state_class="measurement",
|
||||
exists_fn=lambda rep, resources: _drum_clean_cycles_remaining(rep) is not None,
|
||||
rep_fn=_drum_clean_cycles_remaining,
|
||||
exists_fn=lambda rep, resources: drum_clean_cycles_remaining(rep) is not None,
|
||||
rep_fn=drum_clean_cycles_remaining,
|
||||
),
|
||||
SensorDesc(
|
||||
key="drum_clean_last_cleaned",
|
||||
device_class="timestamp",
|
||||
icon="mdi:calendar-clock",
|
||||
entity_category="diagnostic",
|
||||
exists_fn=lambda rep, resources: _drum_clean_last_cleaned(rep) is not None,
|
||||
rep_fn=_drum_clean_last_cleaned,
|
||||
exists_fn=lambda rep, resources: drum_clean_last_cleaned(rep) is not None,
|
||||
rep_fn=drum_clean_last_cleaned,
|
||||
),
|
||||
SelectDesc(
|
||||
key="detergent_quantity",
|
||||
|
||||
@@ -278,9 +278,9 @@
|
||||
"name": "Cyklus",
|
||||
"state": {
|
||||
"80": "Jemné",
|
||||
"83": "Express 60",
|
||||
"83": "Normální",
|
||||
"84": "Intenzivní",
|
||||
"86": "Normální",
|
||||
"86": "Express 60",
|
||||
"90": "Samočištění",
|
||||
"0e": "AI mytí",
|
||||
"07": "Předoplach",
|
||||
@@ -325,7 +325,10 @@
|
||||
"1e": "Outdoor",
|
||||
"1f": "Smíšená náplň",
|
||||
"2b": "Sušení bubnu",
|
||||
"4c": "Osvěžení vzduchem"
|
||||
"4c": "Osvěžení vzduchem",
|
||||
"51": "Eko bavlna",
|
||||
"53": "AI sušení+",
|
||||
"4e": "Automatické sušení"
|
||||
}
|
||||
},
|
||||
"favorite_capacity": {
|
||||
@@ -621,6 +624,28 @@
|
||||
},
|
||||
"zone_mode": {
|
||||
"name": "Režim zóny"
|
||||
},
|
||||
"watertank_light_color": {
|
||||
"name": "Barva osvětlení nádržky na vodu",
|
||||
"state": {
|
||||
"warmwhite": "Teplá bílá",
|
||||
"naturalwhite": "Přirozená bílá",
|
||||
"coolwhite": "Studená bílá",
|
||||
"green": "Zelená",
|
||||
"purple": "Fialová",
|
||||
"blue": "Modrá",
|
||||
"orange": "Oranžová",
|
||||
"pink": "Růžová"
|
||||
}
|
||||
},
|
||||
"watertank_light_brightness": {
|
||||
"name": "Jas osvětlení nádržky na vodu"
|
||||
},
|
||||
"air_filter_pm1_threshold": {
|
||||
"name": "Práh alarmu PM1 filtru"
|
||||
},
|
||||
"freezer_temperature_setpoint": {
|
||||
"name": "Teplota mrazicí zóny"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
@@ -969,6 +994,15 @@
|
||||
},
|
||||
"zone_temperature": {
|
||||
"name": "Teplota zóny"
|
||||
},
|
||||
"watertank_full_alarm_status": {
|
||||
"name": "Stav alarmu plné nádržky na vodu"
|
||||
},
|
||||
"air_filter_pm1_usage": {
|
||||
"name": "Využití PM1 filtru"
|
||||
},
|
||||
"air_filter_pm1_usage_hours": {
|
||||
"name": "Hodiny využití PM1 filtru"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
@@ -1136,6 +1170,15 @@
|
||||
},
|
||||
"away_mode": {
|
||||
"name": "Režim nepřítomnosti"
|
||||
},
|
||||
"watertank_light": {
|
||||
"name": "Osvětlení nádržky na vodu"
|
||||
},
|
||||
"uv_led": {
|
||||
"name": "UV LED"
|
||||
},
|
||||
"ventilation_alarm": {
|
||||
"name": "Alarm větrání"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
|
||||
@@ -278,9 +278,9 @@
|
||||
"name": "Cycle",
|
||||
"state": {
|
||||
"80": "Delicate",
|
||||
"83": "Express 60",
|
||||
"83": "Normal",
|
||||
"84": "Heavy",
|
||||
"86": "Normal",
|
||||
"86": "Express 60",
|
||||
"90": "Self clean",
|
||||
"0e": "AI Wash",
|
||||
"07": "Pre blast",
|
||||
@@ -325,7 +325,10 @@
|
||||
"1e": "Outdoor",
|
||||
"1f": "Mixed load",
|
||||
"2b": "Self Tub Dry",
|
||||
"4c": "Air Refresh"
|
||||
"4c": "Air Refresh",
|
||||
"51": "Eco Cotton",
|
||||
"53": "AI Dry+",
|
||||
"4e": "Self Dry"
|
||||
}
|
||||
},
|
||||
"favorite_capacity": {
|
||||
@@ -621,6 +624,28 @@
|
||||
},
|
||||
"zone_mode": {
|
||||
"name": "Zone mode"
|
||||
},
|
||||
"watertank_light_color": {
|
||||
"name": "Water tank light color",
|
||||
"state": {
|
||||
"warmwhite": "Warm white",
|
||||
"naturalwhite": "Natural white",
|
||||
"coolwhite": "Cool white",
|
||||
"green": "Green",
|
||||
"purple": "Purple",
|
||||
"blue": "Blue",
|
||||
"orange": "Orange",
|
||||
"pink": "Pink"
|
||||
}
|
||||
},
|
||||
"watertank_light_brightness": {
|
||||
"name": "Water tank light brightness"
|
||||
},
|
||||
"air_filter_pm1_threshold": {
|
||||
"name": "PM1 filter alarm threshold"
|
||||
},
|
||||
"freezer_temperature_setpoint": {
|
||||
"name": "Freezer temperature"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
@@ -969,6 +994,15 @@
|
||||
},
|
||||
"zone_temperature": {
|
||||
"name": "Zone temperature"
|
||||
},
|
||||
"watertank_full_alarm_status": {
|
||||
"name": "Water tank full alarm status"
|
||||
},
|
||||
"air_filter_pm1_usage": {
|
||||
"name": "PM1 filter usage"
|
||||
},
|
||||
"air_filter_pm1_usage_hours": {
|
||||
"name": "PM1 filter usage hours"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
@@ -1136,6 +1170,15 @@
|
||||
},
|
||||
"away_mode": {
|
||||
"name": "Away mode"
|
||||
},
|
||||
"watertank_light": {
|
||||
"name": "Water tank light"
|
||||
},
|
||||
"uv_led": {
|
||||
"name": "UV LED"
|
||||
},
|
||||
"ventilation_alarm": {
|
||||
"name": "Ventilation alarm"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
|
||||
@@ -392,9 +392,9 @@
|
||||
"name": "Ciclo",
|
||||
"state": {
|
||||
"80": "Delicado",
|
||||
"83": "Express 60",
|
||||
"83": "Normal",
|
||||
"84": "Intenso",
|
||||
"86": "Normal",
|
||||
"86": "Express 60",
|
||||
"90": "Autolimpieza",
|
||||
"0e": "Lavado IA",
|
||||
"07": "Prelavado intenso",
|
||||
@@ -439,7 +439,10 @@
|
||||
"1e": "Exterior",
|
||||
"1f": "Carga mixta",
|
||||
"2b": "Secado de tambor",
|
||||
"4c": "Renovación de aire"
|
||||
"4c": "Renovación de aire",
|
||||
"51": "Eco algodón",
|
||||
"53": "Secado IA+",
|
||||
"4e": "Autosecado"
|
||||
}
|
||||
},
|
||||
"favorite_capacity": {
|
||||
@@ -735,6 +738,28 @@
|
||||
},
|
||||
"zone_mode": {
|
||||
"name": "Modo de zona"
|
||||
},
|
||||
"watertank_light_color": {
|
||||
"name": "Color de la luz del depósito de agua",
|
||||
"state": {
|
||||
"warmwhite": "Blanco cálido",
|
||||
"naturalwhite": "Blanco natural",
|
||||
"coolwhite": "Blanco frío",
|
||||
"green": "Verde",
|
||||
"purple": "Púrpura",
|
||||
"blue": "Azul",
|
||||
"orange": "Naranja",
|
||||
"pink": "Rosa"
|
||||
}
|
||||
},
|
||||
"watertank_light_brightness": {
|
||||
"name": "Brillo de la luz del depósito de agua"
|
||||
},
|
||||
"air_filter_pm1_threshold": {
|
||||
"name": "Umbral de alarma del filtro PM1"
|
||||
},
|
||||
"freezer_temperature_setpoint": {
|
||||
"name": "Temperatura del congelador"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
@@ -1083,6 +1108,15 @@
|
||||
},
|
||||
"zone_temperature": {
|
||||
"name": "Temperatura de zona"
|
||||
},
|
||||
"watertank_full_alarm_status": {
|
||||
"name": "Estado de alarma de depósito de agua lleno"
|
||||
},
|
||||
"air_filter_pm1_usage": {
|
||||
"name": "Uso del filtro PM1"
|
||||
},
|
||||
"air_filter_pm1_usage_hours": {
|
||||
"name": "Horas de uso del filtro PM1"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
@@ -1250,6 +1284,15 @@
|
||||
},
|
||||
"zone_power": {
|
||||
"name": "Alimentación de zona"
|
||||
},
|
||||
"watertank_light": {
|
||||
"name": "Luz del depósito de agua"
|
||||
},
|
||||
"uv_led": {
|
||||
"name": "LED UV"
|
||||
},
|
||||
"ventilation_alarm": {
|
||||
"name": "Alarma de ventilación"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
|
||||
@@ -278,9 +278,9 @@
|
||||
"name": "Ciclo",
|
||||
"state": {
|
||||
"80": "Delicato",
|
||||
"83": "Express 60",
|
||||
"83": "Normale",
|
||||
"84": "Intenso",
|
||||
"86": "Normale",
|
||||
"86": "Express 60",
|
||||
"90": "Autopulizia",
|
||||
"0e": "AI Wash",
|
||||
"07": "Prelavaggio intenso",
|
||||
@@ -325,7 +325,10 @@
|
||||
"1e": "Capi outdoor",
|
||||
"1f": "Carico misto",
|
||||
"2b": "Asciugatura cestello",
|
||||
"4c": "Rinfresca"
|
||||
"4c": "Rinfresca",
|
||||
"51": "Eco cotone",
|
||||
"53": "Asciugatura AI+",
|
||||
"4e": "Autoasciugatura"
|
||||
}
|
||||
},
|
||||
"favorite_capacity": {
|
||||
@@ -621,6 +624,28 @@
|
||||
},
|
||||
"zone_mode": {
|
||||
"name": "Modalità zona"
|
||||
},
|
||||
"watertank_light_color": {
|
||||
"name": "Colore della luce del serbatoio dell'acqua",
|
||||
"state": {
|
||||
"warmwhite": "Bianco caldo",
|
||||
"naturalwhite": "Bianco naturale",
|
||||
"coolwhite": "Bianco freddo",
|
||||
"green": "Verde",
|
||||
"purple": "Viola",
|
||||
"blue": "Blu",
|
||||
"orange": "Arancione",
|
||||
"pink": "Rosa"
|
||||
}
|
||||
},
|
||||
"watertank_light_brightness": {
|
||||
"name": "Luminosità della luce del serbatoio dell'acqua"
|
||||
},
|
||||
"air_filter_pm1_threshold": {
|
||||
"name": "Soglia di allarme del filtro PM1"
|
||||
},
|
||||
"freezer_temperature_setpoint": {
|
||||
"name": "Temperatura freezer"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
@@ -969,6 +994,15 @@
|
||||
},
|
||||
"zone_temperature": {
|
||||
"name": "Temperatura zona"
|
||||
},
|
||||
"watertank_full_alarm_status": {
|
||||
"name": "Stato allarme serbatoio d'acqua pieno"
|
||||
},
|
||||
"air_filter_pm1_usage": {
|
||||
"name": "Utilizzo del filtro PM1"
|
||||
},
|
||||
"air_filter_pm1_usage_hours": {
|
||||
"name": "Ore di utilizzo del filtro PM1"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
@@ -1136,6 +1170,15 @@
|
||||
},
|
||||
"away_mode": {
|
||||
"name": "Modalità assenza"
|
||||
},
|
||||
"watertank_light": {
|
||||
"name": "Luce del serbatoio dell'acqua"
|
||||
},
|
||||
"uv_led": {
|
||||
"name": "LED UV"
|
||||
},
|
||||
"ventilation_alarm": {
|
||||
"name": "Allarme ventilazione"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
|
||||
@@ -278,9 +278,9 @@
|
||||
"name": "Programma",
|
||||
"state": {
|
||||
"80": "Delicaat",
|
||||
"83": "Express 60",
|
||||
"83": "Normaal",
|
||||
"84": "Intensief",
|
||||
"86": "Normaal",
|
||||
"86": "Express 60",
|
||||
"90": "Zelfreiniging",
|
||||
"0e": "AI Wash",
|
||||
"07": "Voorspoelen",
|
||||
@@ -325,7 +325,10 @@
|
||||
"1e": "Outdoor",
|
||||
"1f": "Gemengde was",
|
||||
"2b": "Zelf trommel drogen",
|
||||
"4c": "Opfrissen"
|
||||
"4c": "Opfrissen",
|
||||
"51": "Eco katoen",
|
||||
"53": "AI drogen+",
|
||||
"4e": "Zelf drogen"
|
||||
}
|
||||
},
|
||||
"favorite_capacity": {
|
||||
@@ -621,6 +624,28 @@
|
||||
},
|
||||
"zone_mode": {
|
||||
"name": "Zonemodus"
|
||||
},
|
||||
"watertank_light_color": {
|
||||
"name": "Kleur van het waterreservoirlicht",
|
||||
"state": {
|
||||
"warmwhite": "Warm wit",
|
||||
"naturalwhite": "Natuurlijk wit",
|
||||
"coolwhite": "Koel wit",
|
||||
"green": "Groen",
|
||||
"purple": "Paars",
|
||||
"blue": "Blauw",
|
||||
"orange": "Oranje",
|
||||
"pink": "Roze"
|
||||
}
|
||||
},
|
||||
"watertank_light_brightness": {
|
||||
"name": "Helderheid van het waterreservoirlicht"
|
||||
},
|
||||
"air_filter_pm1_threshold": {
|
||||
"name": "PM1-filteralarmdrempel"
|
||||
},
|
||||
"freezer_temperature_setpoint": {
|
||||
"name": "Temperatuur vriesgedeelte"
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
@@ -969,6 +994,15 @@
|
||||
},
|
||||
"zone_temperature": {
|
||||
"name": "Zonetemperatuur"
|
||||
},
|
||||
"watertank_full_alarm_status": {
|
||||
"name": "Status alarm waterreservoir vol"
|
||||
},
|
||||
"air_filter_pm1_usage": {
|
||||
"name": "PM1-filtergebruik"
|
||||
},
|
||||
"air_filter_pm1_usage_hours": {
|
||||
"name": "PM1-filtergebruik in uren"
|
||||
}
|
||||
},
|
||||
"switch": {
|
||||
@@ -1136,6 +1170,15 @@
|
||||
},
|
||||
"away_mode": {
|
||||
"name": "Afwezigheidsmodus"
|
||||
},
|
||||
"watertank_light": {
|
||||
"name": "Waterreservoirlicht"
|
||||
},
|
||||
"uv_led": {
|
||||
"name": "Uv-led"
|
||||
},
|
||||
"ventilation_alarm": {
|
||||
"name": "Ventilatiealarm"
|
||||
}
|
||||
},
|
||||
"time": {
|
||||
|
||||
@@ -0,0 +1,641 @@
|
||||
{
|
||||
"device0": [
|
||||
{
|
||||
"rt": [
|
||||
"x.com.samsung.devcol",
|
||||
"oic.wk.col"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.ll",
|
||||
"oic.if.b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"href": "/personality/presence/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "",
|
||||
"x.com.samsung.da.deviceId": "**REDACTED**",
|
||||
"x.com.samsung.da.value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/realtimenotiforclient/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.timeforshortnoti": "0",
|
||||
"x.com.samsung.da.longnotisubscription": "true",
|
||||
"x.com.samsung.da.periodicnotisubscription": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/filter/airdustfilter/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.filterUsage": "100",
|
||||
"x.com.samsung.da.filterUsageResolution": "1",
|
||||
"x.com.samsung.da.filterDesiredUsage": "224",
|
||||
"x.com.samsung.da.filterStatus": "wash",
|
||||
"x.com.samsung.da.filterCapacity": "224",
|
||||
"x.com.samsung.da.filterCapacityUnit": "Hour",
|
||||
"x.com.samsung.da.filterResetType": [
|
||||
"washable"
|
||||
],
|
||||
"x.com.samsung.da.supportedFilterDesiredUsage": [
|
||||
"112",
|
||||
"224",
|
||||
"336",
|
||||
"448"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/filter/airdustPM1filter/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.filterCapacity": "3",
|
||||
"x.com.samsung.da.filterCapacityUnit": "Month",
|
||||
"x.com.samsung.da.filterResetType": [
|
||||
"notresetable"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperature/control/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.increment": "0.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/convenient/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "Off",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"Off",
|
||||
"Sleep",
|
||||
"Nano",
|
||||
"NanoSleep"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/option/airpurify/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "Off",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/option/autoclean/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.status": "Stop",
|
||||
"x.com.samsung.da.settingStatus": "On",
|
||||
"x.com.samsung.da.progress": "0",
|
||||
"x.com.samsung.da.supportedStatus": [
|
||||
"Start",
|
||||
"SpeedClean",
|
||||
"QuietClean",
|
||||
"Stop"
|
||||
],
|
||||
"x.com.samsung.da.supportedSettingStatus": [
|
||||
"On",
|
||||
"SpeedClean",
|
||||
"QuietClean",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wind/strength/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "12",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"0",
|
||||
"11",
|
||||
"12",
|
||||
"13",
|
||||
"14",
|
||||
"15",
|
||||
"16"
|
||||
],
|
||||
"x.com.samsung.da.modesName": [
|
||||
"Auto",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"5",
|
||||
"Max"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wind/direction/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "NotSupported",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"NotSupported"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/subdevices/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.subdeviceIdList": "**REDACTED**"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/alarms/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Alarm",
|
||||
"x.com.samsung.da.alarmType": "Device",
|
||||
"x.com.samsung.da.code": "ErrorCode_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-08-03T14:14:25"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Alarm",
|
||||
"x.com.samsung.da.alarmType": "Device",
|
||||
"x.com.samsung.da.code": "AC_V_0002_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-08-03T14:14:25"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperatures/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Temperature",
|
||||
"x.com.samsung.da.desired": "27.0",
|
||||
"x.com.samsung.da.current": "28.0",
|
||||
"x.com.samsung.da.maximum": "30",
|
||||
"x.com.samsung.da.minimum": "18",
|
||||
"x.com.samsung.da.increment": "0.5",
|
||||
"x.com.samsung.da.unit": "Celsius"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperature/current/0",
|
||||
"rep": {
|
||||
"range": [
|
||||
18.0,
|
||||
30.0
|
||||
],
|
||||
"units": "C",
|
||||
"temperature": 28.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperature/desired/0",
|
||||
"rep": {
|
||||
"range": [
|
||||
18.0,
|
||||
30.0
|
||||
],
|
||||
"units": "C",
|
||||
"temperature": 27.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/diagnosis/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.cumulativeConsumption": "400.000000",
|
||||
"x.com.samsung.da.instantaneousPower": "14.000000",
|
||||
"x.com.samsung.da.cumulativePower": "882861",
|
||||
"x.com.samsung.da.cumulativeSavedPower": "0",
|
||||
"x.com.samsung.da.cumulativeDate": "1785798000",
|
||||
"x.com.samsung.da.cumulativeUnit": "Wh",
|
||||
"x.com.samsung.da.instantaneousPowerUnit": "W",
|
||||
"x.com.samsung.da.cumulativePowerType": "individual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/0",
|
||||
"rep": {
|
||||
"energy": 400.0,
|
||||
"power": 14.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"AIComfort",
|
||||
"Cool",
|
||||
"Dry",
|
||||
"Wind"
|
||||
],
|
||||
"x.com.samsung.da.modes": [
|
||||
"Cool"
|
||||
],
|
||||
"x.com.samsung.da.options": [
|
||||
"ArtificialWorking_Off",
|
||||
"welcomecare_Off",
|
||||
"Volume_Mute",
|
||||
"Operation_Family",
|
||||
"ComfortAICooling_Off",
|
||||
"OnTimer_0",
|
||||
"OffTimer_0",
|
||||
"Sleep_0",
|
||||
"Booster_Off",
|
||||
"OutdoorSilence_Off",
|
||||
"AiTempChanged_Off",
|
||||
"AiTemp_250",
|
||||
"StopAutoClean_Idle",
|
||||
"Weather_Off",
|
||||
"Service_Off",
|
||||
"SmartCoolClean_Off",
|
||||
"ProgressSmartClean_0",
|
||||
"OutDoorVentil_Off",
|
||||
"InDoorVentil_Off",
|
||||
"FreezeAlarmSetting_Off",
|
||||
"DesiredFreezeAlarm_240",
|
||||
"ProtectOperation_Off",
|
||||
"EnergySaveIcon_Off",
|
||||
"ExtendOptionCode_16975",
|
||||
"OptionCode_2589",
|
||||
"RacInfo_First",
|
||||
"ModelInfo_16K_BORA_VENT2",
|
||||
"RacInfo_None_Second",
|
||||
"OutdoorConnection_Connected",
|
||||
"DurationOn_0",
|
||||
"UpdateAllow_NotAllowed",
|
||||
"welcomecareElapsedTime_0",
|
||||
"welcomecareThresholdTemp_0",
|
||||
"welcomecareStartDate_0000",
|
||||
"welcomecareEndDate_0000",
|
||||
"welcomecareSeason_None"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.power": "Off",
|
||||
"causeSource": "SMTS"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/0",
|
||||
"rep": {
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modelNum": "TP1X_FAC_TIME_23K|10250841|600007110017112BCE00CE2200937000",
|
||||
"x.com.samsung.da.description": "TP1X_FAC_TIME_23K",
|
||||
"x.com.samsung.da.serialNum": "**REDACTED**",
|
||||
"x.com.samsung.da.otnDUID": "**REDACTED**",
|
||||
"x.com.samsung.da.diagProtocolType": "BLE_OCF",
|
||||
"x.com.samsung.da.diagLogType": [
|
||||
"errCode",
|
||||
"dump"
|
||||
],
|
||||
"x.com.samsung.da.diagDumpType": "file",
|
||||
"x.com.samsung.da.diagEndPoint": "SSM",
|
||||
"x.com.samsung.da.diagMnid": "0AJT",
|
||||
"x.com.samsung.da.diagSetupid": "AF2",
|
||||
"x.com.samsung.da.diagMinVersion": "3.0",
|
||||
"x.com.samsung.da.diagTsId": "DA01",
|
||||
"x.com.samsung.da.serialNumOption": "**REDACTED**",
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Software",
|
||||
"x.com.samsung.da.number": "02517A260330",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "1",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Firmware",
|
||||
"x.com.samsung.da.number": "02508A23020200,02509A24030701",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Outdoor",
|
||||
"x.com.samsung.da.number": "02502A23011300,02299A10000300"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "3",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "LED",
|
||||
"x.com.samsung.da.number": "02510A22121900,FFFFFFFFFFFFFF"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "4",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "BLERemoteController",
|
||||
"x.com.samsung.da.number": "22021760"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/file/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.timeoffset": "+09:00",
|
||||
"x.com.samsung.supprtedtype": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/configuration/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.region": "1138000000",
|
||||
"x.com.samsung.da.airconOptionList": [
|
||||
"HOMECARE_WIZARD_V2",
|
||||
"ENERGY_2.0",
|
||||
"AI_2.0",
|
||||
"DeviceTypeMaster",
|
||||
"CLEAN_OPTION_SUPPORT",
|
||||
"DR",
|
||||
"SingleCommand_1"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/humidity/0",
|
||||
"rep": {
|
||||
"humidity": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/humidity/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.humidity": "0.000000",
|
||||
"x.com.samsung.da.fivepercentHumidity": "71"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/drlc/0",
|
||||
"rep": {
|
||||
"DRLevel": 0,
|
||||
"start": "1970-01-01T00:00:00Z",
|
||||
"durationminutes": 0,
|
||||
"override": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/drlc/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.drlcLevel": "0",
|
||||
"x.com.samsung.da.durationminutes": "0",
|
||||
"x.com.samsung.da.start": "1970-01-01T00:00:00Z",
|
||||
"x.com.samsung.da.override": "Off",
|
||||
"x.com.samsung.da.realSaving": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/runn/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.runningMode": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/availablecontrolsets/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.sets": "000000B4012C0000000D04000000",
|
||||
"x.com.samsung.da.id": "FAC",
|
||||
"x.com.samsung.da.version": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/keepnormalstate/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.keepnormal": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/uvled/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "On",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/remotedatacontrol/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.status": "Off",
|
||||
"x.com.samsung.da.connectionStatus": "Disconnected"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/remotetemperature/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.temperature": "",
|
||||
"x.com.samsung.da.unit": "",
|
||||
"x.com.samsung.da.error": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/aisleep/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.displayNightMode": "Off",
|
||||
"x.com.samsung.da.elapsedTime": "0",
|
||||
"x.com.samsung.da.requestFeedback": "Off",
|
||||
"x.com.samsung.da.resultFeedback": "0",
|
||||
"x.com.samsung.da.statusFeedback": "Idle",
|
||||
"x.com.samsung.da.sleepTime": "14002200"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/remotedeviceinfo/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.didList": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/otninformation/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.target": "",
|
||||
"x.com.samsung.da.newVersionAvailable": "false",
|
||||
"x.com.samsung.da.newVersionNo": "00000000",
|
||||
"x.com.samsung.da.currentVersionInfo": "00000000",
|
||||
"otnStatus": "None",
|
||||
"flashingProgress": "",
|
||||
"otnTarget": "main",
|
||||
"otnCompleteDate": "noHistory",
|
||||
"otnList": [
|
||||
{
|
||||
"type": "WIFI",
|
||||
"modelId": "AFA-WW-TP1-23-AFXX00",
|
||||
"versions": [
|
||||
"10260330"
|
||||
],
|
||||
"visVersion": "260330"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "845110250241FFFFFFFF",
|
||||
"versions": [
|
||||
"23011300",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "230113"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "04511025084110250941",
|
||||
"versions": [
|
||||
"23020200",
|
||||
"24030701"
|
||||
],
|
||||
"visVersion": "240307"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "04511025024110229941",
|
||||
"versions": [
|
||||
"23011300",
|
||||
"10000300"
|
||||
],
|
||||
"visVersion": "230113"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "045110240441FFFFFFFF",
|
||||
"versions": [
|
||||
"23121900",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "231219"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "045110251041FFFFFFFF",
|
||||
"versions": [
|
||||
"22121900",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "221219"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/option/muteonce/vs/0",
|
||||
"rep": {
|
||||
"muteonce": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/selfcheck/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.start": "Cancel",
|
||||
"x.com.samsung.da.status": "Ready",
|
||||
"x.com.samsung.da.progress": "1",
|
||||
"x.com.samsung.da.result": "NA",
|
||||
"x.com.samsung.da.supportedActions": [
|
||||
"Start",
|
||||
"Cancel"
|
||||
],
|
||||
"x.com.samsung.da.error": [
|
||||
"DA_ERROR_NONE"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/reserverulesets/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.sets": "1DFFFFFFFF121E121EFFFFFFFFFFFF01000000013F0100013F000000001C0C",
|
||||
"x.com.samsung.da.id": "FAC",
|
||||
"x.com.samsung.da.version": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/ventilation/setting/vs/0",
|
||||
"rep": {
|
||||
"alarm": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/light/vs/0",
|
||||
"rep": {
|
||||
"mode": "Off",
|
||||
"supportedModes": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/timezone/vs/0",
|
||||
"rep": {
|
||||
"timezoneid": "Asia/Seoul",
|
||||
"offset": "+09:00",
|
||||
"DST": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/connectionconfig/vs/0",
|
||||
"rep": {
|
||||
"autoReconnectionMinVersion": "1.0",
|
||||
"autoReconnection": "true",
|
||||
"autoReconnectionProtocolType": [
|
||||
"helper_hotspot",
|
||||
"ble_ocf"
|
||||
],
|
||||
"supportedWiFiAuthType": [
|
||||
"OPEN",
|
||||
"WEP",
|
||||
"WPA-PSK",
|
||||
"WPA2-PSK",
|
||||
"SAE"
|
||||
],
|
||||
"supportedWiFiCryptoType": [
|
||||
"TKIP",
|
||||
"AES",
|
||||
"WEP-64",
|
||||
"WEP-128"
|
||||
],
|
||||
"supportedWiFiFreq": [
|
||||
"2.4G"
|
||||
],
|
||||
"calmConnectionCare": {
|
||||
"version": "1.0",
|
||||
"role": [
|
||||
"things"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wirelessinfo/vs/0",
|
||||
"rep": {
|
||||
"macaddressWiFi": "**REDACTED**",
|
||||
"macaddressBLE": "**REDACTED**",
|
||||
"connectedApSsid": "**REDACTED**"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/quickcontrol/info/vs/0",
|
||||
"rep": {
|
||||
"supportedVersion": "1.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,426 @@
|
||||
{
|
||||
"device0": [
|
||||
{
|
||||
"rt": [
|
||||
"x.com.samsung.devcol",
|
||||
"oic.wk.col"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.ll",
|
||||
"oic.if.b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"href": "/personality/presence/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "",
|
||||
"x.com.samsung.da.deviceId": "**REDACTED**",
|
||||
"x.com.samsung.da.value": ""
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/realtimenotiforclient/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.timeforshortnoti": "0",
|
||||
"x.com.samsung.da.longnotisubscription": "false",
|
||||
"x.com.samsung.da.periodicnotisubscription": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/filter/airdustfilter/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.filterUsage": "100",
|
||||
"x.com.samsung.da.filterUsageResolution": "1",
|
||||
"x.com.samsung.da.filterDesiredUsage": "224",
|
||||
"x.com.samsung.da.filterStatus": "wash",
|
||||
"x.com.samsung.da.filterCapacity": "224",
|
||||
"x.com.samsung.da.filterCapacityUnit": "Hour",
|
||||
"x.com.samsung.da.filterResetType": [
|
||||
"washable"
|
||||
],
|
||||
"x.com.samsung.da.supportedFilterDesiredUsage": [
|
||||
"224",
|
||||
"300",
|
||||
"500",
|
||||
"700"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/convenient/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"Off",
|
||||
"Sleep"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/option/autoclean/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.status": "Stop",
|
||||
"x.com.samsung.da.settingStatus": "On",
|
||||
"x.com.samsung.da.progress": "0",
|
||||
"cleaningTime": "30",
|
||||
"minCleaningTime": "10",
|
||||
"maxCleaningTime": "60",
|
||||
"cleaningTimeUnit": "10",
|
||||
"x.com.samsung.da.supportedStatus": [
|
||||
"Start",
|
||||
"TimedClean",
|
||||
"Stop"
|
||||
],
|
||||
"x.com.samsung.da.supportedSettingStatus": [
|
||||
"On",
|
||||
"TimedClean",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/alarms/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Alarm",
|
||||
"x.com.samsung.da.alarmType": "Device",
|
||||
"x.com.samsung.da.code": "ErrorCode_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-08-03T14:54:15",
|
||||
"x.com.samsung.da.state": "Deleted"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Alarm",
|
||||
"x.com.samsung.da.alarmType": "Device",
|
||||
"x.com.samsung.da.code": "WaterTankFull_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-08-03T14:54:15",
|
||||
"x.com.samsung.da.state": "Deleted"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.instantaneousPower": "145.000000",
|
||||
"x.com.samsung.da.cumulativePower": "101100",
|
||||
"x.com.samsung.da.cumulativeSavedPower": "0",
|
||||
"x.com.samsung.da.cumulativeUnit": "Wh",
|
||||
"x.com.samsung.da.instantaneousPowerUnit": "W",
|
||||
"x.com.samsung.da.cumulativePowerType": "total"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"Smart",
|
||||
"Max",
|
||||
"High",
|
||||
"Medium",
|
||||
"Quiet",
|
||||
"ClothesDrying"
|
||||
],
|
||||
"x.com.samsung.da.modes": [
|
||||
"Quiet"
|
||||
],
|
||||
"x.com.samsung.da.options": [
|
||||
"Volume_Mute",
|
||||
"RacInfo_None",
|
||||
"UpdateAllow_NotAllowed",
|
||||
"WelcomeCoolingState_Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.power": "On",
|
||||
"operationNumber": "1",
|
||||
"displayCondition": "Enable"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/sensors/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modelNum": "TP1X_DA_AC_DHM_01001_0000|10283341|77000000001700000A00000000000000",
|
||||
"x.com.samsung.da.description": "TP1X_DA_AC_DHM_01001_0000",
|
||||
"x.com.samsung.da.serialNum": "**REDACTED**",
|
||||
"x.com.samsung.da.otnDUID": "**REDACTED**",
|
||||
"x.com.samsung.da.diagProtocolType": "BLE_OCF",
|
||||
"x.com.samsung.da.diagLogType": [
|
||||
"errCode",
|
||||
"dump"
|
||||
],
|
||||
"x.com.samsung.da.diagDumpType": "file",
|
||||
"x.com.samsung.da.diagEndPoint": "SSM",
|
||||
"x.com.samsung.da.diagMnid": "0AJT",
|
||||
"x.com.samsung.da.diagSetupid": "AY0",
|
||||
"x.com.samsung.da.diagMinVersion": "3.0",
|
||||
"x.com.samsung.da.diagTsId": "DA01",
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Software",
|
||||
"x.com.samsung.da.number": "02544A260401",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "1",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Firmware",
|
||||
"x.com.samsung.da.number": "02833A26010600,FFFFFFFFFFFFFF",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Outdoor",
|
||||
"x.com.samsung.da.number": "02590A10000100,FFFFFFFFFFFFFF"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "4",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Touch IC",
|
||||
"x.com.samsung.da.number": "02552A23020200,FFFFFFFFFFFFFF"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/file/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.timeoffset": "+09:00",
|
||||
"x.com.samsung.supprtedtype": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/configuration/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.region": "0000000000",
|
||||
"x.com.samsung.da.airconOptionList": [
|
||||
"SingleCommand_1",
|
||||
"DR",
|
||||
"HOMECARE_WIZARD_V2",
|
||||
"PRODUCT_GLOBAL",
|
||||
"AI_RAC_GLOBAL_2.0",
|
||||
"AI_Heat"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/humidity/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.humidity": "63",
|
||||
"x.com.samsung.da.desiredHumidity": "60",
|
||||
"increment": "5",
|
||||
"x.com.samsung.da.fivepercentHumidity": "64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/drlc/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.drlcLevel": "0",
|
||||
"x.com.samsung.da.durationminutes": "0",
|
||||
"x.com.samsung.da.start": "1970-01-01T00:00:00Z",
|
||||
"x.com.samsung.da.override": "Off",
|
||||
"x.com.samsung.da.realSaving": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/availablecontrolsets/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.sets": "04001E46070A5A00000000000000",
|
||||
"x.com.samsung.da.id": "DHM",
|
||||
"x.com.samsung.da.version": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/da/softreset/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.softwarereset": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/keepnormalstate/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.keepnormal": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/otninformation/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.target": "",
|
||||
"x.com.samsung.da.newVersionAvailable": "false",
|
||||
"x.com.samsung.da.newVersionNo": "00000000",
|
||||
"x.com.samsung.da.currentVersionInfo": "00000000",
|
||||
"otnStatus": "None",
|
||||
"flashingProgress": "",
|
||||
"otnTarget": "main",
|
||||
"otnCompleteDate": "2026-06-24",
|
||||
"otnList": [
|
||||
{
|
||||
"type": "WIFI",
|
||||
"modelId": "ADH-WW-TP1-23-AY7100",
|
||||
"versions": [
|
||||
"18260401"
|
||||
],
|
||||
"visVersion": "260401"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "042110283341FFFFFFFF",
|
||||
"versions": [
|
||||
"26010600",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "260106"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "042110259041FFFFFFFF",
|
||||
"versions": [
|
||||
"10000100",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "100001"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "042110255241FFFFFFFF",
|
||||
"versions": [
|
||||
"23020200",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "230202"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/timezone/vs/0",
|
||||
"rep": {
|
||||
"timezoneid": "Asia/Seoul",
|
||||
"offset": "+09:00",
|
||||
"DST": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/option/muteonce/vs/0",
|
||||
"rep": {
|
||||
"muteonce": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/reserverulesets/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.sets": "3F1E461E461E46FFFFFFFF1E4600",
|
||||
"x.com.samsung.da.id": "DHM",
|
||||
"x.com.samsung.da.version": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/display/vs/0",
|
||||
"rep": {
|
||||
"mode": "On",
|
||||
"supportedModes": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/connectionconfig/vs/0",
|
||||
"rep": {
|
||||
"autoReconnectionMinVersion": "1.0",
|
||||
"autoReconnection": "true",
|
||||
"autoReconnectionProtocolType": [
|
||||
"helper_hotspot",
|
||||
"ble_ocf"
|
||||
],
|
||||
"supportedWiFiAuthType": [
|
||||
"OPEN",
|
||||
"WEP",
|
||||
"WPA-PSK",
|
||||
"WPA2-PSK",
|
||||
"SAE"
|
||||
],
|
||||
"supportedWiFiCryptoType": [
|
||||
"TKIP",
|
||||
"AES",
|
||||
"WEP-64",
|
||||
"WEP-128"
|
||||
],
|
||||
"supportedWiFiFreq": [
|
||||
"2.4G"
|
||||
],
|
||||
"calmConnectionCare": {
|
||||
"version": "1.0",
|
||||
"role": [
|
||||
"things"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/welcome/humidity/vs/0",
|
||||
"rep": {
|
||||
"requestId": "0000",
|
||||
"operatingStatus": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/kidslock/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.kidsLock": "Ready"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/watertank/lighting/vs/0",
|
||||
"rep": {
|
||||
"status": "On",
|
||||
"colorOption": "NaturalWhite",
|
||||
"mode": "High",
|
||||
"waterfullAlarmStatus": "On",
|
||||
"colorSupportedList": [
|
||||
"WarmWhite",
|
||||
"NaturalWhite",
|
||||
"CoolWhite",
|
||||
"Green",
|
||||
"Purple",
|
||||
"Blue",
|
||||
"Orange",
|
||||
"Pink"
|
||||
],
|
||||
"modeSupportedList": [
|
||||
"High",
|
||||
"Low"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wirelessinfo/vs/0",
|
||||
"rep": {
|
||||
"macaddressWiFi": "**REDACTED**",
|
||||
"macaddressBLE": "**REDACTED**"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/quickcontrol/info/vs/0",
|
||||
"rep": {
|
||||
"supportedVersion": "1.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+438
@@ -0,0 +1,438 @@
|
||||
{
|
||||
"device0": [
|
||||
{
|
||||
"rt": [
|
||||
"x.com.samsung.devcol",
|
||||
"oic.wk.col"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.ll",
|
||||
"oic.if.b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"href": "/realtimenotiforclient/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.timeforshortnoti": "0",
|
||||
"x.com.samsung.da.periodicnotisubscription": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/alarms/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/diagnosis/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.diagnosisStart": "Ready"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.instantaneousPower": "-500",
|
||||
"x.com.samsung.da.instantaneousPowerUnit": "W",
|
||||
"x.com.samsung.da.cumulativePower": "211700",
|
||||
"x.com.samsung.da.cumulativeUnit": "Wh",
|
||||
"x.com.samsung.da.cumulativeDate": "1785693600",
|
||||
"x.com.samsung.da.cumulativeDateUTC": "1785686400",
|
||||
"x.com.samsung.da.cumulativeSavedPower": "0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/course/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"HOMECARE_WIZARD_V2"
|
||||
],
|
||||
"x.com.samsung.da.options": [
|
||||
"DeviceType_0165",
|
||||
"UpdateAllow_NotAllowed",
|
||||
"Course_16",
|
||||
"AiOption_On",
|
||||
"MixedLoadBell_Disable",
|
||||
"MixedLoadBellNoti_Nothing",
|
||||
"LaundryOutTime_0",
|
||||
"SeamlessControl_Enable",
|
||||
"KidsLockBypass_On",
|
||||
"WashingTimes_25",
|
||||
"DrumCleanProposal_25",
|
||||
"DetergentOnce_1",
|
||||
"DetergentLeft_0",
|
||||
"DetergentBase_5",
|
||||
"DetergentAlarm_Off",
|
||||
"DetergentType_3",
|
||||
"DetergentTotal_0",
|
||||
"SpecialFunction_20",
|
||||
"AvailableDelayTime_215",
|
||||
"LaundryPlannerUserSetTime_0",
|
||||
"ProgressTimeSet_B214DCB4003C",
|
||||
"WrinklePreventRunning_Off",
|
||||
"QuickDrive_Off",
|
||||
"SendToDevice_Off",
|
||||
"GMT_04",
|
||||
"DrumLight_Off",
|
||||
"DryTimeSet_FF00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000060007FE020007FE020007FE0000000000000000",
|
||||
"EnergyLevelSet_05030403050302040503050203030402010205",
|
||||
"MostUsed_16D31E",
|
||||
"WrinklePreventSet_0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0FF0",
|
||||
"MixedLoadBellSet_0202FF0202FFFFFF02FFFFFFFFFFFFFFFFFF",
|
||||
"EmptyingTheBucket_Nothing",
|
||||
"SavingModeCondition_01010202171D0300",
|
||||
"SavingMode_Off",
|
||||
"QuickDriveSet_F0000000F000000000000000000000000000",
|
||||
"GeoFenceAlarm",
|
||||
"UsagesDB_ok",
|
||||
"EnergyKW_396",
|
||||
"DrumCleanLog_2023-12-03T22:07:18|2024-02-09T15:18:59|2024-07-07T23:06:16|2024-10-19T19:29:45|2025-01-26T16:10:23|2025-05-10T19:59:59|2025-07-13T14:58:26|2026-01-09T21:27:43|2026-03-21T18:52:46|2026-05-24T21:38:08",
|
||||
"TimeSync_NotSupported"
|
||||
],
|
||||
"x.com.samsung.da.supportedOptions": [
|
||||
"116D31E29D31E23D00017D31E18D21E19D20C1DD3181BD3181CD31E21D4101AD1021ED31820D10227D00025D00024D0004CD21C2BD000"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.power": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/0",
|
||||
"rep": {
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/cycleinterface/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.cycleInterfaceEnabled": "On"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/kidslock/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.kidsLock": "Ready"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/kidslock/0",
|
||||
"rep": {
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/operational/state/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.state": "Ready",
|
||||
"x.com.samsung.da.remainingTime": "03:35:00",
|
||||
"x.com.samsung.da.progressPercentage": "1",
|
||||
"x.com.samsung.da.progress": "None",
|
||||
"x.com.samsung.da.delayEndTime": "00:00:00",
|
||||
"x.com.samsung.da.supportedProgress": [
|
||||
"None",
|
||||
"Drying",
|
||||
"Cooling",
|
||||
"Finish"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/operational/state/0",
|
||||
"rep": {
|
||||
"currentMachineState": "**REDACTED**",
|
||||
"machineStates": "**REDACTED**",
|
||||
"jobStates": [
|
||||
"None",
|
||||
"Drying",
|
||||
"Cooling",
|
||||
"Finish"
|
||||
],
|
||||
"currentJobState": "None",
|
||||
"remainingTime": "03:35:00",
|
||||
"progressPercentage": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modelNum": "DA_WM_TP1_21_COMMON|20317441|30010102001611000AA3031F00000000",
|
||||
"x.com.samsung.da.description": "DA_WM_TP1_21_COMMON_DV9400B/DC92-03267A_2C56",
|
||||
"x.com.samsung.da.serialNum": "**REDACTED**",
|
||||
"x.com.samsung.da.otnDUID": "**REDACTED**",
|
||||
"x.com.samsung.da.diagProtocolType": "BLE_OCF",
|
||||
"x.com.samsung.da.diagLogType": [
|
||||
"errCode",
|
||||
"dump"
|
||||
],
|
||||
"x.com.samsung.da.diagDumpType": "file",
|
||||
"x.com.samsung.da.diagEndPoint": "SSM",
|
||||
"x.com.samsung.da.diagMnid": "0AJT",
|
||||
"x.com.samsung.da.diagSetupid": "DR1",
|
||||
"x.com.samsung.da.diagMinVersion": "3.0",
|
||||
"x.com.samsung.da.diagTsId": "DA01",
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "DA_WM_TP1_21_COMMON|20317441|30010102001611000AA3031F00000000",
|
||||
"x.com.samsung.da.type": "Software",
|
||||
"x.com.samsung.da.number": "02986A260118(A182)",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "1",
|
||||
"x.com.samsung.da.description": "Firmware_1_DB_20317441221114080FFFFF203267412210245204FFFF(01652031744120326741_30221118)(FileDown:0)(Type:0)",
|
||||
"x.com.samsung.da.type": "Firmware",
|
||||
"x.com.samsung.da.number": "03174A22111408,03267A22102452",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Firmware_2_DB_2032244122050903042FFFFFFFFFFFFFFFFFFFFFFFFE(016520322441FFFFFFFF_30000000)(FileDown:0)(Type:0)",
|
||||
"x.com.samsung.da.type": "Firmware",
|
||||
"x.com.samsung.da.number": "03224A22050903,FFFFFFFFFFFFFF"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/file/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.timeoffset": "+02:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/washer/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.wrinklePrevent": "Off",
|
||||
"x.com.samsung.da.dryLevel": "Normal",
|
||||
"x.com.samsung.da.supportedDryLevel": [
|
||||
"None",
|
||||
"Damp",
|
||||
"Less",
|
||||
"Normal",
|
||||
"More"
|
||||
],
|
||||
"x.com.samsung.da.dryTime": "00:00:00",
|
||||
"x.com.samsung.da.supportedDryTime": [
|
||||
"00:00:00",
|
||||
"00:20:00",
|
||||
"00:30:00",
|
||||
"00:40:00",
|
||||
"00:50:00",
|
||||
"01:00:00",
|
||||
"01:30:00",
|
||||
"02:00:00",
|
||||
"02:30:00",
|
||||
"03:00:00",
|
||||
"04:00:00"
|
||||
],
|
||||
"x.com.samsung.da.dryerType": "Electricity"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/st/dryercourse/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.st.dryerMode": "Table_03_Course_16",
|
||||
"x.com.samsung.da.st.courseTable": "Table_03"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/setting/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/wm/editcourse/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.editCourseList": "EditCourseList_161B1D29231718191C211A1E202725244C2B",
|
||||
"x.com.samsung.da.fixedCourseList": "FixedCourseList_1618202B"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wm/setinfo/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.isModelSettingWithoutSC": "true",
|
||||
"x.com.samsung.da.aiCourse": "false",
|
||||
"x.com.samsung.da.isModelSettingPowerOnOff": "false",
|
||||
"x.com.samsung.da.modelCode": "M(None),W(DV90BB7445GES7)"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wm/jobbeginingstatus/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.currentStatus": "None"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wm/welcomemsg/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/wm/personalcourse/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.courses": [
|
||||
"F1_00",
|
||||
"F2_00",
|
||||
"F3_00",
|
||||
"F4_00",
|
||||
"F5_00",
|
||||
"F6_00",
|
||||
"F7_00",
|
||||
"F8_00",
|
||||
"F9_00",
|
||||
"FA_00"
|
||||
],
|
||||
"x.com.samsung.da.maxCourseNum": "10"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/otninformation/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.target": "",
|
||||
"x.com.samsung.da.newVersionAvailable": "false",
|
||||
"x.com.samsung.da.newVersionNo": "00000000",
|
||||
"x.com.samsung.da.currentVersionInfo": "00000000",
|
||||
"otnStatus": "None",
|
||||
"flashingProgress": "",
|
||||
"otnTarget": "main",
|
||||
"otnCompleteDate": "2026-03-04",
|
||||
"otnList": [
|
||||
{
|
||||
"type": "WIFI",
|
||||
"modelId": "DA_WM_TP1_21_COMMON",
|
||||
"versions": [
|
||||
"30260118"
|
||||
],
|
||||
"visVersion": "260118"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "01652031744120326741",
|
||||
"versions": [
|
||||
"22111408",
|
||||
"22102452"
|
||||
],
|
||||
"visVersion": "221114"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "016520322441FFFFFFFF",
|
||||
"versions": [
|
||||
"22050903",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "220509"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/buzzersound/vs/0",
|
||||
"rep": {
|
||||
"supportedBuzzerSound": [
|
||||
"Off",
|
||||
"On"
|
||||
],
|
||||
"setBuzzerSound": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/remotectrl/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.remoteControlEnabled": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/remotectrl/0",
|
||||
"rep": {
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/configuration/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.region": "0000000000",
|
||||
"x.com.samsung.da.countryCode": "CZ"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/drlc/0",
|
||||
"rep": {
|
||||
"DRLevel": 0,
|
||||
"start": "0000-00-00T00:00:00Z",
|
||||
"duration": 0,
|
||||
"override": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/drlc/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.drlcLevel": "0",
|
||||
"x.com.samsung.da.durationminutes": "0",
|
||||
"x.com.samsung.da.start": "0000-00-00T00:00:00Z",
|
||||
"x.com.samsung.da.override": "Off",
|
||||
"x.com.samsung.da.realSaving": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/timezone/vs/0",
|
||||
"rep": {
|
||||
"timezoneid": "Europe/Prague",
|
||||
"offset": "+02:00",
|
||||
"DST": "ON"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/connectionconfig/vs/0",
|
||||
"rep": {
|
||||
"autoReconnectionMinVersion": "1.0",
|
||||
"autoReconnection": "true",
|
||||
"autoReconnectionProtocolType": [
|
||||
"helper_hotspot",
|
||||
"ble_ocf"
|
||||
],
|
||||
"supportedWiFiAuthType": [
|
||||
"OPEN",
|
||||
"WEP",
|
||||
"WPA-PSK",
|
||||
"WPA2-PSK",
|
||||
"SAE"
|
||||
],
|
||||
"supportedWiFiCryptoType": [
|
||||
"TKIP",
|
||||
"AES",
|
||||
"WEP-64",
|
||||
"WEP-128"
|
||||
],
|
||||
"supportedWiFiFreq": [
|
||||
"2.4G"
|
||||
],
|
||||
"calmConnectionCare": {
|
||||
"version": "1.0",
|
||||
"role": [
|
||||
"things"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wirelessinfo/vs/0",
|
||||
"rep": {
|
||||
"macaddressWiFi": "**REDACTED**",
|
||||
"macaddressBLE": "**REDACTED**"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/quickcontrol/info/vs/0",
|
||||
"rep": {
|
||||
"supportedVersion": "1.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+5
-1
@@ -2,6 +2,9 @@
|
||||
"state_keys": [
|
||||
"absence_power_saving_active",
|
||||
"absence_power_saving_mode",
|
||||
"air_filter_pm1_status",
|
||||
"air_filter_pm1_usage",
|
||||
"air_filter_pm1_usage_hours",
|
||||
"air_filter_status",
|
||||
"air_filter_usage",
|
||||
"air_filter_usage_hours",
|
||||
@@ -29,6 +32,7 @@
|
||||
"selfcheck_result",
|
||||
"selfcheck_status",
|
||||
"super_fine_dust",
|
||||
"tropical_night_mode"
|
||||
"tropical_night_mode",
|
||||
"uv_led"
|
||||
]
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
{
|
||||
"state_keys": [
|
||||
"air_filter_status",
|
||||
"air_filter_threshold",
|
||||
"air_filter_usage",
|
||||
"air_filter_usage_hours",
|
||||
"air_purify",
|
||||
"alarm_code",
|
||||
"auto_clean",
|
||||
"auto_clean_progress",
|
||||
"auto_clean_running",
|
||||
"beep",
|
||||
"climate",
|
||||
"current_temperature_c",
|
||||
"diagnosis_status",
|
||||
"display_light",
|
||||
"energy_kwh",
|
||||
"energy_saved_kwh",
|
||||
"firmware_update",
|
||||
"humidity",
|
||||
"mute_once",
|
||||
"odor_controller_active",
|
||||
"odor_controller_progress",
|
||||
"power_energy_kwh",
|
||||
"power_watts",
|
||||
"selfcheck_error",
|
||||
"selfcheck_result",
|
||||
"selfcheck_status",
|
||||
"tropical_night_mode",
|
||||
"uv_led",
|
||||
"ventilation_alarm"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"state_keys": [
|
||||
"air_filter_status",
|
||||
"air_filter_threshold",
|
||||
"air_filter_usage",
|
||||
"air_filter_usage_hours",
|
||||
"alarm_code",
|
||||
"auto_clean",
|
||||
"auto_clean_progress",
|
||||
"auto_clean_running",
|
||||
"child_lock",
|
||||
"display",
|
||||
"energy_kwh",
|
||||
"energy_saved_kwh",
|
||||
"firmware_update",
|
||||
"humidity",
|
||||
"mute_once",
|
||||
"operating_mode",
|
||||
"power_switch",
|
||||
"power_watts",
|
||||
"target_humidity",
|
||||
"watertank_full_alarm_status",
|
||||
"watertank_light",
|
||||
"watertank_light_brightness",
|
||||
"watertank_light_color"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"state_keys": [
|
||||
"alarm_code",
|
||||
"buzzer_sound",
|
||||
"child_lock",
|
||||
"completion_minutes",
|
||||
"cycle",
|
||||
"cycle_active",
|
||||
"delay_start_hours",
|
||||
"diagnosis",
|
||||
"drum_clean_cycles_remaining",
|
||||
"drum_clean_last_cleaned",
|
||||
"dry_level",
|
||||
"dry_time",
|
||||
"dryer_type",
|
||||
"energy_kwh",
|
||||
"energy_saved_kwh",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
"job_beginning_status",
|
||||
"machine_state",
|
||||
"power_switch",
|
||||
"progress",
|
||||
"progress_percentage",
|
||||
"remote_control",
|
||||
"wrinkle_prevent"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"state_keys": [
|
||||
"ai_energy_level",
|
||||
"alarm_code",
|
||||
"auto_door_opener",
|
||||
"brightness_level",
|
||||
"cabinet_light_dim",
|
||||
"cabinet_light_switch",
|
||||
"cooler_temperature_setpoint",
|
||||
"day_brightness",
|
||||
"door_alert",
|
||||
"door_cooler_open",
|
||||
"door_freezer_open",
|
||||
"energy_kwh",
|
||||
"energy_saved_kwh",
|
||||
"firmware_update",
|
||||
"flex_zone_mode",
|
||||
"freezer_temperature_setpoint",
|
||||
"fridge_sound",
|
||||
"night_end",
|
||||
"night_start",
|
||||
"power_energy_kwh",
|
||||
"power_watts",
|
||||
"rapid_freezing",
|
||||
"rapid_fridge",
|
||||
"selfcheck_error",
|
||||
"selfcheck_result",
|
||||
"selfcheck_status"
|
||||
]
|
||||
}
|
||||
@@ -10,6 +10,7 @@
|
||||
"detergent_low",
|
||||
"diagnosis_status",
|
||||
"drum_clean_cycles_remaining",
|
||||
"drum_clean_last_cleaned",
|
||||
"dry_level",
|
||||
"energy_kwh",
|
||||
"finish_time",
|
||||
|
||||
+1
@@ -9,6 +9,7 @@
|
||||
"detergent_low",
|
||||
"diagnosis_status",
|
||||
"drum_clean_cycles_remaining",
|
||||
"drum_clean_last_cleaned",
|
||||
"energy_kwh",
|
||||
"finish_time",
|
||||
"job_beginning_status",
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@
|
||||
"detergent_water_hardness",
|
||||
"diagnosis_status",
|
||||
"drum_clean_cycles_remaining",
|
||||
"drum_clean_last_cleaned",
|
||||
"energy_kwh",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
@@ -27,4 +28,4 @@
|
||||
"spin_speed",
|
||||
"wash_temperature"
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -9,6 +9,7 @@
|
||||
"detergent_low",
|
||||
"diagnosis_status",
|
||||
"drum_clean_cycles_remaining",
|
||||
"drum_clean_last_cleaned",
|
||||
"energy_kwh",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
|
||||
@@ -0,0 +1,467 @@
|
||||
{
|
||||
"device0": [
|
||||
{
|
||||
"rt": [
|
||||
"x.com.samsung.devcol",
|
||||
"oic.wk.col"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.ll",
|
||||
"oic.if.b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"href": "/alarms/vs/0",
|
||||
"rep": {
|
||||
"href": "/alarms/vs/0",
|
||||
"rt": [
|
||||
"x.com.samsung.da.alarms"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/cabinet/light/total/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.lightLevel": "100",
|
||||
"x.com.samsung.da.lightResolution": "3",
|
||||
"x.com.samsung.da.lightControl.off.include": "Off",
|
||||
"x.com.samsung.da.lightControl": "Off",
|
||||
"x.com.samsung.da.lightControl.hide": "true",
|
||||
"light.dimming.status": "Off",
|
||||
"href": "/cabinet/light/total/vs/0",
|
||||
"rt": [
|
||||
"x.com.samsung.da.cabinetlight"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/settings/sound/alert/door/vs/0",
|
||||
"rep": {
|
||||
"alert.door": "1",
|
||||
"supportedAlert.door": [
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4"
|
||||
],
|
||||
"href": "/settings/sound/alert/door/vs/0",
|
||||
"rt": [
|
||||
"x.com.samsung.alert.door"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/cabinet/light/enhanced/vs/0",
|
||||
"rep": {
|
||||
"light.control.status": "On",
|
||||
"level.brightness.daytime": "100",
|
||||
"level.brightness.nighttime": "66",
|
||||
"night.starttime": "2026-07-31T15:30:00",
|
||||
"night.duration.minute": "540",
|
||||
"timezone.offset": "+05:30",
|
||||
"href": "/cabinet/light/enhanced/vs/0",
|
||||
"rt": [
|
||||
"x.com.samsung.da.light.enhanced"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/configuration/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.region": "",
|
||||
"x.com.samsung.da.countryCode": "",
|
||||
"href": "/configuration/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperature/definite/freezer/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.definite.desired": "-19",
|
||||
"x.com.samsung.da.definite.supportedList": [
|
||||
"-23",
|
||||
"-21",
|
||||
"-19",
|
||||
"-17",
|
||||
"-15"
|
||||
],
|
||||
"x.com.samsung.da.unit": "Celsius",
|
||||
"href": "/temperature/definite/freezer/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperature/definite/cooler/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.definite.desired": "4",
|
||||
"x.com.samsung.da.definite.supportedList": [
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"4",
|
||||
"7"
|
||||
],
|
||||
"x.com.samsung.da.unit": "Celsius",
|
||||
"href": "/temperature/definite/cooler/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/door/freezer/0",
|
||||
"rep": {
|
||||
"openState": "Close",
|
||||
"href": "/door/freezer/0",
|
||||
"rt": [
|
||||
"oic.r.door"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.s"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/door/cooler/0",
|
||||
"rep": {
|
||||
"openState": "Close",
|
||||
"href": "/door/cooler/0",
|
||||
"rt": [
|
||||
"oic.r.door"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.s"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/doors/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.openState": "Close",
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Door"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.openState": "Close",
|
||||
"x.com.samsung.da.id": "1",
|
||||
"x.com.samsung.da.description": "Door"
|
||||
}
|
||||
],
|
||||
"href": "/doors/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/drlc/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.drlcLevel": "0",
|
||||
"x.com.samsung.da.override": "Not_Supported",
|
||||
"x.com.samsung.da.durationminutes": "0",
|
||||
"x.com.samsung.da.realSaving": "Off",
|
||||
"href": "/drlc/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.cumulativeConsumption": "1274",
|
||||
"x.com.samsung.da.instantaneousPower": "46",
|
||||
"x.com.samsung.da.cumulativePower": "34106",
|
||||
"x.com.samsung.da.cumulativeSavedPower": "0",
|
||||
"x.com.samsung.da.cumulativeUnit": "Wh",
|
||||
"x.com.samsung.da.instantaneousPowerUnit": "W",
|
||||
"href": "/energy/consumption/vs/0",
|
||||
"x.com.samsung.da.cumulativeDateUTC": "1785402720"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/file/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.timeoffset": "+05:30",
|
||||
"x.com.samsung.supprtedtype": 1,
|
||||
"href": "/file/information/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/refrigeration/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.rapidFridge": "Off",
|
||||
"x.com.samsung.da.rapidFreezing": "Off",
|
||||
"href": "/refrigeration/vs/0",
|
||||
"rt": [
|
||||
"x.com.samsung.da.fridge"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/ailevel/vs/0",
|
||||
"rep": {
|
||||
"aiLevel": "1",
|
||||
"supportedAiLevel": [
|
||||
"1",
|
||||
"2"
|
||||
],
|
||||
"href": "/energy/ailevel/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modelNum": "TP1X_REF_21K|70657341|00060123001811344100000020090400",
|
||||
"x.com.samsung.da.description": "TP1X_REF_21K",
|
||||
"x.com.samsung.da.serialNum": "**REDACTED**",
|
||||
"x.com.samsung.da.otnDUID": "**REDACTED**",
|
||||
"x.com.samsung.da.diagDumpType": "file",
|
||||
"x.com.samsung.da.diagEndPoint": "SSM",
|
||||
"x.com.samsung.da.diagLogType": [
|
||||
"errCode",
|
||||
"dump"
|
||||
],
|
||||
"x.com.samsung.da.diagMnid": "0AJT",
|
||||
"x.com.samsung.da.diagSetupid": "RT1",
|
||||
"x.com.samsung.da.diagProtocolType": "BLE_OCF",
|
||||
"x.com.samsung.da.diagMinVersion": "3.0",
|
||||
"x.com.samsung.da.diagTsId": "DA01",
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "WiFi Module",
|
||||
"x.com.samsung.da.type": "Software",
|
||||
"x.com.samsung.da.number": "260617",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "1",
|
||||
"x.com.samsung.da.description": "Micom",
|
||||
"x.com.samsung.da.type": "Firmware",
|
||||
"x.com.samsung.da.number": "2602020C, FFFFFFFF, 24062000, FFFFFFFF",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
}
|
||||
],
|
||||
"href": "/information/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/status/lock/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.device.sound": "On",
|
||||
"x.com.samsung.da.doorAlarmSound": "On",
|
||||
"href": "/status/lock/vs/0",
|
||||
"rt": [
|
||||
"x.com.samsung.da.lockstatus"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": [
|
||||
"RVACATION_OFF",
|
||||
"FCONVERT_FREEZER"
|
||||
],
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"HOMECARE_WIZARD_V2",
|
||||
"ENERGY_REPORT_MODEL",
|
||||
"18K_REF_OUTDOOR_CONTROL_V2",
|
||||
"VACATION_MODE_CONTROL"
|
||||
],
|
||||
"x.com.samsung.da.supportedOptions": [
|
||||
"FCONVERT_FREEZER",
|
||||
"FCONVERT_FRIDGE",
|
||||
"FCONVERT_OFF"
|
||||
],
|
||||
"href": "/mode/vs/0",
|
||||
"rt": [
|
||||
"x.com.samsung.da.mode"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/realtimenotiforclient/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.timeforshortnoti": "0",
|
||||
"x.com.samsung.da.periodicnotisubscription": "true",
|
||||
"href": "/realtimenotiforclient/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/runningmode/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.runningMode": 0,
|
||||
"href": "/runningmode/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/selfcheck/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.supportedActions": [
|
||||
"Start"
|
||||
],
|
||||
"x.com.samsung.da.status": "Ready",
|
||||
"x.com.samsung.da.result": "Success",
|
||||
"x.com.samsung.da.error": [
|
||||
"ErrorCode_None"
|
||||
],
|
||||
"href": "/selfcheck/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/rm/control/vs/0",
|
||||
"rep": {
|
||||
"minPeriod": "9000",
|
||||
"href": "/rm/control/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/otninformation/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.target": "",
|
||||
"x.com.samsung.da.newVersionAvailable": "false",
|
||||
"otnStatus": "None",
|
||||
"flashingProgress": "0",
|
||||
"otnCompleteDate": "noHistory",
|
||||
"scheduledTime": "None",
|
||||
"swVersionInfo": {
|
||||
"platform": "Tizen Lite",
|
||||
"oneUiVersion": "7.0 Refrigerator",
|
||||
"osVersion": "4.0"
|
||||
},
|
||||
"otnList": [
|
||||
{
|
||||
"type": "WIFI",
|
||||
"modelId": "A-RFWW-TP1-24-T4-COM",
|
||||
"versions": [
|
||||
"20260617"
|
||||
],
|
||||
"visVersion": "260617"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "835070657341FFFFFFFF",
|
||||
"versions": [
|
||||
"2602020C",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "260202"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "035070657341FFFFFFFF",
|
||||
"versions": [
|
||||
"2602020C",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "260202"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "035070658641FFFFFFFF",
|
||||
"versions": [
|
||||
"24062000",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "240620"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/timezone/vs/0",
|
||||
"rep": {
|
||||
"timezoneid": "Asia/Kolkata",
|
||||
"offset": "+05:30",
|
||||
"DST": "OFF"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/connectionconfig/vs/0",
|
||||
"rep": {
|
||||
"autoReconnectionMinVersion": "1.0",
|
||||
"autoReconnection": "true",
|
||||
"autoReconnectionProtocolType": [
|
||||
"helper_hotspot",
|
||||
"ble_ocf"
|
||||
],
|
||||
"supportedWiFiAuthType": [
|
||||
"OPEN",
|
||||
"WEP",
|
||||
"WPA-PSK",
|
||||
"WPA2-PSK",
|
||||
"SAE"
|
||||
],
|
||||
"supportedWiFiCryptoType": [
|
||||
"TKIP",
|
||||
"AES",
|
||||
"WEP-64",
|
||||
"WEP-128"
|
||||
],
|
||||
"supportedWiFiFreq": [
|
||||
"2.4G"
|
||||
],
|
||||
"calmConnectionCare": {
|
||||
"version": "1.0",
|
||||
"role": [
|
||||
"things"
|
||||
]
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wirelessinfo/vs/0",
|
||||
"rep": {
|
||||
"macaddressWiFi": "**REDACTED**",
|
||||
"macaddressBLE": "**REDACTED**",
|
||||
"connectedApSsid": "IoT0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/quickcontrol/info/vs/0",
|
||||
"rep": {
|
||||
"supportedVersion": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/dginformation/vs/0",
|
||||
"rep": {
|
||||
"enrolmentstatus": "UnEnrolled",
|
||||
"devicestate": "Deactivated",
|
||||
"lockstatus": "Unknown",
|
||||
"nextduedate": "",
|
||||
"workingminutes": 0,
|
||||
"paymentinfo": {
|
||||
"emiplan": "Unknown",
|
||||
"currency": "Unknown",
|
||||
"totalemi": 0,
|
||||
"totalemipaid": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -6,12 +6,18 @@ token -- this board was the one exception (its oneUiVersion self-reports
|
||||
"7.0 Air conditioner", but 'CAC' had never been added to the board-token
|
||||
table), so it silently fell back to common caps and lost its climate entity.
|
||||
|
||||
This dump is NOT fully covered yet -- ten hrefs remain unbound (edge
|
||||
lighting, PM1 filter, a second stateful light resource, absence-clean, four
|
||||
`/settings/sound/*` resources, smart-sensing-cooling, UV LED), all genuinely
|
||||
new to this board generation. That's a real device-support gap, left
|
||||
documented here rather than guessed at, per the 'don't guess' rule -- fixing
|
||||
the routing regression was the scope of #191.
|
||||
This dump is NOT fully covered yet -- eight hrefs remain unbound (edge
|
||||
lighting, a second stateful light resource, absence-clean, four
|
||||
`/settings/sound/*` resources, smart-sensing-cooling), all genuinely new to
|
||||
this board generation. That's a real device-support gap, left documented
|
||||
here rather than guessed at, per the 'don't guess' rule -- fixing the
|
||||
routing regression was the scope of #191.
|
||||
|
||||
/uvled/vs/0 and /filter/airdustPM1filter/vs/0 used to be on this list too,
|
||||
until issue #270 (TP1X_FAC_TIME_23K) added real capabilities for both --
|
||||
this board's own live filterUsage/filterStatus data on the PM1 filter binds
|
||||
through the same exists_fn-gated entities #270's dump (which has neither
|
||||
field) leaves empty.
|
||||
"""
|
||||
|
||||
from custom_components.localthings.registry.adapter import flatten
|
||||
@@ -22,7 +28,6 @@ from tests.conftest import _load_device
|
||||
_STILL_UNBOUND = frozenset(
|
||||
{
|
||||
"/edgelighting/vs/0",
|
||||
"/filter/airdustPM1filter/vs/0",
|
||||
"/light/stateful/vs/0",
|
||||
"/mds/absenceclean/vs/0",
|
||||
"/settings/sound/mode/vs/0",
|
||||
@@ -30,7 +35,6 @@ _STILL_UNBOUND = frozenset(
|
||||
"/settings/sound/output/vs/0",
|
||||
"/settings/sound/volume/vs/0",
|
||||
"/smartsensingcooling/vs/0",
|
||||
"/uvled/vs/0",
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
@@ -0,0 +1,83 @@
|
||||
"""Tests for the TP1X_FAC_TIME_23K air conditioner (issue #270).
|
||||
|
||||
A 2-in-1 system (x.com.samsung.da.numofsubdevice='2') whose UUID-prefixed
|
||||
sibling materializes via the flat fallback (issue #205) -- unrelated to the
|
||||
three capability gaps this fixture actually locks in (UV LED, ventilation
|
||||
alarm, and the unmodeled PM1 filter), which live entirely on canonical
|
||||
hrefs already exercised by the master's own resources.
|
||||
"""
|
||||
|
||||
from custom_components.localthings.registry.adapter import flatten
|
||||
from custom_components.localthings.registry.by_type import for_device_by_model
|
||||
from custom_components.localthings.registry.discovery import discover
|
||||
from custom_components.localthings.registry.entities import SwitchDesc
|
||||
from tests.conftest import _load_device
|
||||
|
||||
|
||||
def _airconditioner():
|
||||
resources = _load_device("airconditioner_tp1x_fac_time_23k")
|
||||
info = resources["/information/vs/0"]
|
||||
reg = for_device_by_model(
|
||||
info["x.com.samsung.da.modelNum"],
|
||||
info["x.com.samsung.da.description"],
|
||||
)
|
||||
return reg, resources
|
||||
|
||||
|
||||
def _bound():
|
||||
reg, resources = _airconditioner()
|
||||
return discover(resources, reg.capabilities, reg.pattern_capabilities), resources
|
||||
|
||||
|
||||
def _state():
|
||||
bound, resources = _bound()
|
||||
return flatten(bound, resources)
|
||||
|
||||
|
||||
def _desc(key):
|
||||
bound, _ = _bound()
|
||||
return next(b.desc for b in bound if b.desc.key == key)
|
||||
|
||||
|
||||
def test_model_resolves_to_airconditioner_registry():
|
||||
reg, _ = _airconditioner()
|
||||
assert reg is not None and reg.name == "airconditioner"
|
||||
|
||||
|
||||
def test_no_unbound_hrefs():
|
||||
reg, resources = _airconditioner()
|
||||
unbound = []
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities, log=unbound.append)
|
||||
assert unbound == []
|
||||
|
||||
|
||||
def test_uv_led_switch_reads_on_and_has_write_contract():
|
||||
state = _state()
|
||||
assert state["uv_led"] is True
|
||||
desc = _desc("uv_led")
|
||||
assert isinstance(desc, SwitchDesc)
|
||||
path, body = desc.write_fn("Off", {})
|
||||
assert path == ["uvled", "vs", "0"]
|
||||
assert body == {"x.com.samsung.da.modes": "Off"}
|
||||
|
||||
|
||||
def test_ventilation_alarm_switch_reads_off_and_has_write_contract():
|
||||
state = _state()
|
||||
assert state["ventilation_alarm"] is False
|
||||
desc = _desc("ventilation_alarm")
|
||||
assert isinstance(desc, SwitchDesc)
|
||||
path, body = desc.write_fn("On", {})
|
||||
assert path == ["ventilation", "setting", "vs", "0"]
|
||||
assert body == {"alarm": "On"}
|
||||
|
||||
|
||||
def test_pm1_filter_has_no_live_fields_so_no_state_is_reported():
|
||||
"""This dump's /filter/airdustPM1filter/vs/0 has only
|
||||
filterCapacity/filterCapacityUnit/filterResetType -- no filterUsage or
|
||||
filterStatus -- so every AIR_FILTER_PM1 entity's exists_fn gates it out.
|
||||
The href still covers (see test_no_unbound_hrefs above) without
|
||||
fabricating a reading from nothing (the 'don't guess' rule); contrast
|
||||
with test_airconditioner_cac.py, whose dump has live data on the same
|
||||
href and does get real air_filter_pm1_* state."""
|
||||
state = _state()
|
||||
assert not any(k.startswith("air_filter_pm1_") for k in state)
|
||||
@@ -0,0 +1,80 @@
|
||||
"""Tests for issue #235: HOMECARE_WIZARD_V2 false-positive unmapped-mode
|
||||
warning, and the entity_id-is-None logging gap it surfaced.
|
||||
|
||||
Uses the pre-existing airconditioner_tp2x_rac_20k fixture (issue #37) --
|
||||
its /mode/vs/0 already carries the exact reporter-confirmed shape:
|
||||
supportedModes includes 'HOMECARE_WIZARD_V2' alongside the real modes, the
|
||||
current mode ('Cool') never is it, and /configuration/vs/0's
|
||||
airconOptionList lists it alongside other plain capability flags.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
import logging
|
||||
|
||||
import pytest
|
||||
from homeassistant.components.climate import HVACMode
|
||||
from homeassistant.core import HomeAssistant
|
||||
|
||||
from custom_components.localthings.climate import _NON_HVAC_OPTION_CODES, LocalThingsClimate
|
||||
from custom_components.localthings.registry.entities import ClimateDesc
|
||||
from tests.test_subdevice_discovery import _coordinator, _discover
|
||||
|
||||
|
||||
@pytest.fixture
|
||||
async def climate(hass: HomeAssistant):
|
||||
coordinator = _coordinator(hass)
|
||||
await _discover(coordinator, "airconditioner_tp2x_rac_20k")
|
||||
bound = next(b for b in coordinator.bound if isinstance(b.desc, ClimateDesc))
|
||||
return LocalThingsClimate(coordinator, bound)
|
||||
|
||||
|
||||
def test_homecare_wizard_v2_excluded_from_hvac_modes(climate):
|
||||
"""supportedModes is ['Auto', 'Cool', 'Dry', 'Wind', 'Heat',
|
||||
'HOMECARE_WIZARD_V2'] -- five real modes plus the option flag. Every
|
||||
real mode maps through; the flag contributes no extra (or bogus)
|
||||
HVACMode entry."""
|
||||
modes = climate.hvac_modes
|
||||
assert set(modes) == {
|
||||
HVACMode.OFF,
|
||||
HVACMode.AUTO,
|
||||
HVACMode.COOL,
|
||||
HVACMode.DRY,
|
||||
HVACMode.HEAT,
|
||||
HVACMode.FAN_ONLY,
|
||||
}
|
||||
|
||||
|
||||
def test_homecare_wizard_v2_reports_no_warning(climate, caplog):
|
||||
"""Reading hvac_modes must not emit the issue #93 unmapped-mode warning
|
||||
for HOMECARE_WIZARD_V2 -- that's the actual bug report: every owner of
|
||||
an affected unit saw this fire on every start."""
|
||||
with caplog.at_level(logging.WARNING):
|
||||
_ = climate.hvac_modes
|
||||
assert "HOMECARE_WIZARD_V2" not in caplog.text
|
||||
|
||||
|
||||
def test_hvac_mode_is_off_when_powered_off(climate):
|
||||
"""The fixture's power is off -- hvac_mode short-circuits to OFF before
|
||||
ever reading /mode/vs/0's 'Cool', matching real behavior (mode is only
|
||||
meaningful while the unit is on)."""
|
||||
assert climate.hvac_mode == HVACMode.OFF
|
||||
|
||||
|
||||
def test_homecare_wizard_v2_is_the_known_non_hvac_set():
|
||||
assert "HOMECARE_WIZARD_V2" in _NON_HVAC_OPTION_CODES
|
||||
|
||||
|
||||
def test_warn_unmapped_falls_back_to_unique_id_when_entity_id_unset(climate, caplog):
|
||||
"""Issue #235's secondary bug: _warn_unmapped logged 'None: device mode
|
||||
...' because entity_id is unset until the entity is added to hass --
|
||||
exactly the state a fixture-backed entity is in here, without ever
|
||||
calling async_add_entities. unique_id is set eagerly in __init__
|
||||
(entity.py), so it must appear in the log line instead of a bare
|
||||
'None'."""
|
||||
assert climate.entity_id is None
|
||||
assert climate.unique_id is not None
|
||||
with caplog.at_level(logging.WARNING):
|
||||
climate._warn_unmapped("/mode/vs/0", "TotallyUnknownCode")
|
||||
assert "None:" not in caplog.text
|
||||
assert climate.unique_id in caplog.text
|
||||
@@ -0,0 +1,94 @@
|
||||
"""Tests for the TP1X_DA_AC_DHM_01001_0000 dehumidifier revision
|
||||
(issues #271/#231, model AY70H18100GTD).
|
||||
|
||||
Both issues submitted the identical dump: same board, same two previously
|
||||
unbound hrefs (/display/vs/0, /watertank/lighting/vs/0). Confirms both the
|
||||
new capabilities and the /oic/d device-type routing added alongside them.
|
||||
"""
|
||||
|
||||
from custom_components.localthings.registry.adapter import flatten
|
||||
from custom_components.localthings.registry.by_type import (
|
||||
for_device_by_model,
|
||||
for_device_by_oic_type,
|
||||
)
|
||||
from custom_components.localthings.registry.discovery import discover
|
||||
from custom_components.localthings.registry.entities import SelectDesc, SwitchDesc
|
||||
from tests.conftest import _load_device
|
||||
|
||||
|
||||
def _dehumidifier():
|
||||
resources = _load_device("dehumidifier_tp1x_dhm01001")
|
||||
info = resources["/information/vs/0"]
|
||||
reg = for_device_by_model(
|
||||
info["x.com.samsung.da.modelNum"],
|
||||
info["x.com.samsung.da.description"],
|
||||
)
|
||||
return reg, resources
|
||||
|
||||
|
||||
def _bound():
|
||||
reg, resources = _dehumidifier()
|
||||
return discover(resources, reg.capabilities, reg.pattern_capabilities), resources
|
||||
|
||||
|
||||
def _state():
|
||||
bound, resources = _bound()
|
||||
return flatten(bound, resources)
|
||||
|
||||
|
||||
def _desc(key):
|
||||
bound, _ = _bound()
|
||||
return next(b.desc for b in bound if b.desc.key == key)
|
||||
|
||||
|
||||
def test_model_resolves_to_dehumidifier_registry():
|
||||
reg, _ = _dehumidifier()
|
||||
assert reg is not None and reg.name == "dehumidifier"
|
||||
|
||||
|
||||
def test_oic_device_type_resolves_to_dehumidifier_registry():
|
||||
reg = for_device_by_oic_type(("oic.wk.d", "x.com.st.d.dehumidifier"))
|
||||
assert reg is not None and reg.name == "dehumidifier"
|
||||
|
||||
|
||||
def test_no_unbound_hrefs():
|
||||
reg, resources = _dehumidifier()
|
||||
unbound = []
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities, log=unbound.append)
|
||||
assert unbound == []
|
||||
|
||||
|
||||
def test_display_switch_present_and_reads_on():
|
||||
state = _state()
|
||||
assert state["display"] is True
|
||||
|
||||
|
||||
def test_watertank_light_switch_write_contract():
|
||||
desc = _desc("watertank_light")
|
||||
assert isinstance(desc, SwitchDesc)
|
||||
path, body = desc.write_fn("On", {})
|
||||
assert path == ["watertank", "lighting", "vs", "0"]
|
||||
assert body == {"status": "On"}
|
||||
|
||||
|
||||
def test_watertank_light_color_options_come_from_live_supported_list():
|
||||
desc = _desc("watertank_light_color")
|
||||
assert isinstance(desc, SelectDesc)
|
||||
assert desc.options_field == "colorSupportedList"
|
||||
path, body = desc.write_fn("Green", {})
|
||||
assert path == ["watertank", "lighting", "vs", "0"]
|
||||
assert body == {"colorOption": "Green"}
|
||||
|
||||
|
||||
def test_watertank_light_brightness_options_come_from_live_supported_list():
|
||||
desc = _desc("watertank_light_brightness")
|
||||
assert isinstance(desc, SelectDesc)
|
||||
assert desc.options_field == "modeSupportedList"
|
||||
path, body = desc.write_fn("Low", {})
|
||||
assert path == ["watertank", "lighting", "vs", "0"]
|
||||
assert body == {"mode": "Low"}
|
||||
|
||||
|
||||
def test_watertank_full_alarm_status_exposed_read_only():
|
||||
state = _state()
|
||||
assert state["watertank_full_alarm_status"] == "On"
|
||||
@@ -0,0 +1,87 @@
|
||||
"""Tests for dryer Drum Clean+ maintenance tracking (issue #258).
|
||||
|
||||
Same DrumCleanProposal_/WashingTimes_/DrumCleanLog_ options[] tokens as
|
||||
washer.py's issue #9 feature, shared via laundry.drum_clean_cycles_remaining/
|
||||
drum_clean_last_cleaned -- except DrumCleanLog_ on a dryer is a '|'-joined
|
||||
history of every past clean rather than one bare timestamp.
|
||||
"""
|
||||
|
||||
from custom_components.localthings.registry.adapter import flatten
|
||||
from custom_components.localthings.registry.by_type import for_device_by_model
|
||||
from custom_components.localthings.registry.capabilities.laundry import (
|
||||
drum_clean_cycles_remaining,
|
||||
drum_clean_last_cleaned,
|
||||
)
|
||||
from custom_components.localthings.registry.discovery import discover
|
||||
from tests.conftest import _load_device
|
||||
|
||||
|
||||
def _dryer(fixture_name):
|
||||
resources = _load_device(fixture_name)
|
||||
info = resources["/information/vs/0"]
|
||||
reg = for_device_by_model(
|
||||
info["x.com.samsung.da.modelNum"],
|
||||
info["x.com.samsung.da.description"],
|
||||
)
|
||||
return reg, resources
|
||||
|
||||
|
||||
def _state(fixture_name):
|
||||
reg, resources = _dryer(fixture_name)
|
||||
bound = discover(resources, reg.capabilities, reg.pattern_capabilities)
|
||||
return flatten(bound, resources)
|
||||
|
||||
|
||||
def test_no_unbound_hrefs():
|
||||
reg, resources = _dryer("dryer_tp1_21_drum_clean")
|
||||
unbound = []
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities, log=unbound.append)
|
||||
assert unbound == []
|
||||
|
||||
|
||||
def test_confirmed_dump_reports_cycles_remaining_and_last_cleaned():
|
||||
"""DA_WM_TP1_21_COMMON/DV9400B reports DrumCleanProposal_25/
|
||||
WashingTimes_25 (0 cycles remaining -- due now) and a ten-entry
|
||||
'|'-joined DrumCleanLog_, most recent 2026-05-24T21:38:08."""
|
||||
state = _state("dryer_tp1_21_drum_clean")
|
||||
assert state["drum_clean_cycles_remaining"] == 0
|
||||
assert str(state["drum_clean_last_cleaned"]) == "2026-05-24 21:38:08+00:00"
|
||||
|
||||
|
||||
def test_dump_with_no_drum_clean_data_reports_neither_entity():
|
||||
"""The default dryer fixture only has 'DrumCleanLog_Empty', no
|
||||
DrumCleanProposal_/WashingTimes_ tokens at all -- both entities stay
|
||||
gated off rather than reporting a fabricated 0 or an unparseable date."""
|
||||
state = _state("dryer")
|
||||
assert "drum_clean_cycles_remaining" not in state
|
||||
assert "drum_clean_last_cleaned" not in state
|
||||
|
||||
|
||||
def test_multi_entry_drum_clean_log_takes_the_last_timestamp():
|
||||
rep = {
|
||||
"x.com.samsung.da.options": [
|
||||
"DrumCleanLog_2023-12-03T22:07:18|2024-02-09T15:18:59|2026-05-24T21:38:08",
|
||||
]
|
||||
}
|
||||
assert str(drum_clean_last_cleaned(rep)) == "2026-05-24 21:38:08+00:00"
|
||||
|
||||
|
||||
def test_single_entry_drum_clean_log_matches_washer_shape():
|
||||
"""A bare, no-'|' value (the washer's own shape) parses identically."""
|
||||
rep = {"x.com.samsung.da.options": ["DrumCleanLog_2024-02-09T15:18:59"]}
|
||||
assert str(drum_clean_last_cleaned(rep)) == "2024-02-09 15:18:59+00:00"
|
||||
|
||||
|
||||
def test_empty_drum_clean_log_reports_none():
|
||||
rep = {"x.com.samsung.da.options": ["DrumCleanLog_Empty"]}
|
||||
assert drum_clean_last_cleaned(rep) is None
|
||||
|
||||
|
||||
def test_cycles_remaining_never_negative():
|
||||
rep = {
|
||||
"x.com.samsung.da.options": [
|
||||
"DrumCleanProposal_25",
|
||||
"WashingTimes_40",
|
||||
]
|
||||
}
|
||||
assert drum_clean_cycles_remaining(rep) == 0
|
||||
@@ -329,6 +329,56 @@ class TestDefiniteTemperatureCooler:
|
||||
assert rep["x.com.samsung.da.definite.supportedList"] == ["1", "2", "3", "4", "7"]
|
||||
|
||||
|
||||
class TestDefiniteTemperatureFreezer:
|
||||
"""Discrete freezer setpoint (TP1X_REF_21K, issue #229) -- the same
|
||||
definite-setpoint pattern as DEFINITE_TEMPERATURE_COOLER above, on a
|
||||
fridge/freezer combo that reports it for *both* compartments. Identical
|
||||
field shape, just negative supportedList values."""
|
||||
|
||||
def test_href(self):
|
||||
assert fridge.DEFINITE_TEMPERATURE_FREEZER.href == "/temperature/definite/freezer/vs/0"
|
||||
|
||||
def test_write(self):
|
||||
desc = next(
|
||||
e for e in fridge.DEFINITE_TEMPERATURE_FREEZER.entities if isinstance(e, SelectDesc)
|
||||
)
|
||||
assert desc.write_fn is not None
|
||||
result = desc.write_fn("-19", {})
|
||||
assert result is not None
|
||||
path, body = result
|
||||
assert path == ["temperature", "definite", "freezer", "vs", "0"]
|
||||
assert body == {"x.com.samsung.da.definite.desired": "-19"}
|
||||
|
||||
def test_no_unbound_hrefs_and_discrete_options(self):
|
||||
from custom_components.localthings.registry.adapter import flatten
|
||||
from custom_components.localthings.registry.by_type import refrigerator
|
||||
from custom_components.localthings.registry.discovery import discover
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("refrigerator_tp1x_ref_21k_definite")
|
||||
unbound = []
|
||||
bound = discover(
|
||||
resources,
|
||||
refrigerator.REGISTRY.capabilities,
|
||||
refrigerator.REGISTRY.pattern_capabilities,
|
||||
log=unbound.append,
|
||||
)
|
||||
assert unbound == []
|
||||
|
||||
state = flatten(bound, resources)
|
||||
assert state["cooler_temperature_setpoint"] == "4"
|
||||
assert state["freezer_temperature_setpoint"] == "-19"
|
||||
|
||||
rep = resources["/temperature/definite/freezer/vs/0"]
|
||||
assert rep["x.com.samsung.da.definite.supportedList"] == [
|
||||
"-23",
|
||||
"-21",
|
||||
"-19",
|
||||
"-17",
|
||||
"-15",
|
||||
]
|
||||
|
||||
|
||||
class TestKimchiZone:
|
||||
"""Kimchi-refrigerator compartments (TP2X_REF_20K-class, issue #26) --
|
||||
top/middle/bottom each report an identically-shaped currentMode/
|
||||
|
||||
@@ -72,7 +72,12 @@ def test_registry_reproduces_golden_state_keys_for_ehs():
|
||||
def test_registry_reproduces_golden_state_keys_for_washer_wa8000t():
|
||||
"""Top-load washer (WA8000T, issue #106) reports no oneUiVersion and
|
||||
used the 'WA' consumer-model prefix, previously unmapped in
|
||||
_CONSUMER_PREFIX_TO_KEY -- fell back to 'unknown'."""
|
||||
_CONSUMER_PREFIX_TO_KEY -- fell back to 'unknown'.
|
||||
|
||||
Also gains drum_clean_last_cleaned (issue #258): this fixture's
|
||||
DrumCleanLog_ is a '|'-joined multi-entry history, which always failed
|
||||
datetime.fromisoformat and silently returned None before
|
||||
laundry.drum_clean_last_cleaned learned to take the last entry."""
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("washer_wa8000t")
|
||||
@@ -270,7 +275,10 @@ def test_registry_reproduces_golden_state_keys_for_range_hood():
|
||||
def test_registry_reproduces_golden_state_keys_for_washer_flexwash():
|
||||
"""FlexWash twin washers (WV-prefix consumer model, e.g. WV55M9600AW)
|
||||
report no oneUiVersion and previously fell through for_device_by_model's
|
||||
consumer-prefix map entirely -- issue #19."""
|
||||
consumer-prefix map entirely -- issue #19.
|
||||
|
||||
Also gains drum_clean_last_cleaned (issue #258) -- see the wa8000t test
|
||||
above for why."""
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("washer_flexwash")
|
||||
@@ -285,7 +293,10 @@ def test_registry_reproduces_golden_state_keys_for_washer_flexwash():
|
||||
|
||||
def test_registry_reproduces_golden_state_keys_for_washer_dryer_combo():
|
||||
"""Washer/dryer combo units carry a writable dryLevel field on
|
||||
/washer/vs/0 itself, with no separate dryer resource -- issue #22."""
|
||||
/washer/vs/0 itself, with no separate dryer resource -- issue #22.
|
||||
|
||||
Also gains drum_clean_last_cleaned (issue #258) -- see the wa8000t test
|
||||
above for why."""
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("washer_dryer_combo")
|
||||
@@ -622,7 +633,10 @@ def test_registry_reproduces_golden_state_keys_for_washer_wa55a7700av():
|
||||
-- a different board generation than the WA8000T's TP2_20_COMMON,
|
||||
reached through the same 'WA' consumer-model-prefix fallback (issue
|
||||
#106). Binds cleanly against the existing washer registry with zero
|
||||
unbound hrefs."""
|
||||
unbound hrefs.
|
||||
|
||||
Also gains drum_clean_last_cleaned (issue #258) -- see the wa8000t test
|
||||
above for why."""
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("washer_wa55a7700av")
|
||||
@@ -1226,6 +1240,79 @@ def test_registry_reproduces_golden_state_keys_for_range_ne6516a():
|
||||
)
|
||||
|
||||
|
||||
def test_registry_reproduces_golden_state_keys_for_dehumidifier_tp1x_dhm01001():
|
||||
"""TP1X_DA_AC_DHM_01001_0000 revision (issues #271/#231) additionally
|
||||
reports /display/vs/0 (air_purifier.DISPLAY's exact shape, reused as-is)
|
||||
and /watertank/lighting/vs/0 (new WATERTANK_LIGHTING capability), both
|
||||
unbound on the original issue #88 dump."""
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("dehumidifier_tp1x_dhm01001")
|
||||
golden = json.loads((GOLDEN / "dehumidifier_tp1x_dhm01001.json").read_text())
|
||||
state_keys = _new_state_keys("dehumidifier_tp1x_dhm01001", resources)
|
||||
assert set(state_keys) == set(golden["state_keys"]), (
|
||||
f"state_keys mismatch:\n"
|
||||
f" extra: {sorted(set(state_keys) - set(golden['state_keys']))}\n"
|
||||
f" missing: {sorted(set(golden['state_keys']) - set(state_keys))}"
|
||||
)
|
||||
|
||||
|
||||
def test_registry_reproduces_golden_state_keys_for_airconditioner_tp1x_fac_time_23k():
|
||||
"""TP1X_FAC_TIME_23K (issue #270) reports a UV-C LED, a ventilation-alarm
|
||||
toggle, and a second (PM1-rated, no live usage field) dust filter, none
|
||||
previously modeled. Also a 2-in-1 system on this dump (numofsubdevice=2,
|
||||
a UUID-prefixed sibling materializes via the flat fallback) -- the three
|
||||
new/ignored hrefs are fixed on their canonical form so the sibling picks
|
||||
them up too, per the adding-device-support skill's 'never index or
|
||||
prefix a registry href' rule."""
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("airconditioner_tp1x_fac_time_23k")
|
||||
golden = json.loads((GOLDEN / "airconditioner_tp1x_fac_time_23k.json").read_text())
|
||||
state_keys = _new_state_keys("airconditioner_tp1x_fac_time_23k", resources)
|
||||
assert set(state_keys) == set(golden["state_keys"]), (
|
||||
f"state_keys mismatch:\n"
|
||||
f" extra: {sorted(set(state_keys) - set(golden['state_keys']))}\n"
|
||||
f" missing: {sorted(set(golden['state_keys']) - set(state_keys))}"
|
||||
)
|
||||
|
||||
|
||||
def test_registry_reproduces_golden_state_keys_for_dryer_tp1_21_drum_clean():
|
||||
"""DA_WM_TP1_21_COMMON/DV9400B (issue #258) is the first dryer dump with
|
||||
live DrumCleanProposal_/WashingTimes_ tokens (dryer's default fixture
|
||||
only ever had 'DrumCleanLog_Empty', same as the parallel washer capability
|
||||
started from) -- locks in the new drum_clean_cycles_remaining/
|
||||
drum_clean_last_cleaned entities, including the dryer-specific
|
||||
'|'-joined multi-timestamp DrumCleanLog_ shape."""
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("dryer_tp1_21_drum_clean")
|
||||
golden = json.loads((GOLDEN / "dryer_tp1_21_drum_clean.json").read_text())
|
||||
state_keys = _new_state_keys("dryer_tp1_21_drum_clean", resources)
|
||||
assert set(state_keys) == set(golden["state_keys"]), (
|
||||
f"state_keys mismatch:\n"
|
||||
f" extra: {sorted(set(state_keys) - set(golden['state_keys']))}\n"
|
||||
f" missing: {sorted(set(golden['state_keys']) - set(state_keys))}"
|
||||
)
|
||||
|
||||
|
||||
def test_registry_reproduces_golden_state_keys_for_refrigerator_tp1x_ref_21k_definite():
|
||||
"""TP1X_REF_21K (issue #229) reports the discrete definite-setpoint
|
||||
pattern (issue #186) on *both* compartments -- previously only the
|
||||
cooler half was modeled; DEFINITE_TEMPERATURE_FREEZER covers the
|
||||
freezer's identical-shape /temperature/definite/freezer/vs/0."""
|
||||
from tests.conftest import _load_device
|
||||
|
||||
resources = _load_device("refrigerator_tp1x_ref_21k_definite")
|
||||
golden = json.loads((GOLDEN / "refrigerator_tp1x_ref_21k_definite.json").read_text())
|
||||
state_keys = _new_state_keys("refrigerator_tp1x_ref_21k_definite", resources)
|
||||
assert set(state_keys) == set(golden["state_keys"]), (
|
||||
f"state_keys mismatch:\n"
|
||||
f" extra: {sorted(set(state_keys) - set(golden['state_keys']))}\n"
|
||||
f" missing: {sorted(set(golden['state_keys']) - set(state_keys))}"
|
||||
)
|
||||
|
||||
|
||||
def test_resources_from_batch_preferred_over_flat():
|
||||
from tests.conftest import _resources_from_dump
|
||||
|
||||
|
||||
Reference in New Issue
Block a user