Merge pull request #198 from mbillow/claude/issue-triage-ujtam3
Morning issue triage: #191, #192, #193, #190, #186, #136, #183, #56
This commit is contained in:
37 files changed
+2963
-105
No files matched your search
@@ -194,7 +194,17 @@ def _find_live_ports(host: str, ports: list[int], timeout: float) -> list[int]:
|
||||
except OSError:
|
||||
pass
|
||||
|
||||
return _order_candidates(live)
|
||||
# The sweep's ICMP-based verdict isn't reliable on every network path --
|
||||
# issue #192 captured a segregated-VLAN device where it called three
|
||||
# ports live that a concurrent nmap scan showed as closed, while the
|
||||
# port nmap found genuinely open|filtered (49154, one of our historically
|
||||
# confirmed ports) never showed up as live at all. Rather than trust a
|
||||
# wrong "not live" verdict on a port we already have strong prior
|
||||
# evidence for, always give the historically-confirmed ports a real
|
||||
# handshake attempt too. Bounded cost: at most len(PREFERRED_PROBE_PORTS)
|
||||
# extra handshakes, only when the sweep disagrees with the prior.
|
||||
rescued = [p for p in PREFERRED_PROBE_PORTS if p in ports and p not in live]
|
||||
return _order_candidates(live + rescued)
|
||||
|
||||
|
||||
def _is_placeholder_serial(serial: str) -> bool:
|
||||
@@ -238,14 +248,13 @@ def _probe_and_validate(host: str, ca_cert_pem: str, ca_key_pem: str) -> dict:
|
||||
candidates = _find_live_ports(
|
||||
host, PROBE_PORT_RANGE, LIVENESS_PROBE_TIMEOUT_S
|
||||
)
|
||||
if not candidates:
|
||||
# Every port in the range actively refused: there is no DTLS/CoAP
|
||||
# listener on this host, so a handshake can't succeed. Fail now with a
|
||||
# clear message instead of retrying doomed ports.
|
||||
raise CannotConnect(
|
||||
f"no live DTLS port found on {host} "
|
||||
f"in {PROBE_PORT_RANGE[0]}-{PROBE_PORT_RANGE[-1]}"
|
||||
)
|
||||
# No early "every port refused" fast-fail here: _find_live_ports always
|
||||
# rescues PREFERRED_PROBE_PORTS (issue #192), so candidates is never
|
||||
# empty as long as that table is non-empty and within PROBE_PORT_RANGE --
|
||||
# both true today, which made this branch permanently unreachable. A
|
||||
# genuinely dead host now fails via the handshake loop's own error below,
|
||||
# which carries the actual per-port timeout/refusal reason instead of a
|
||||
# generic "no live port found" message.
|
||||
_LOGGER.debug("Live DTLS port candidates on %s: %s", host, candidates)
|
||||
|
||||
last_exc = None
|
||||
|
||||
@@ -75,17 +75,24 @@ _BOARD_TOKEN_TO_KEY: dict[str, str] = {
|
||||
# Air conditioners. Every one of these is a distinct board family with
|
||||
# the same resource surface: room (issues #37, #91), package, Korean
|
||||
# (#136), window (#87), 2-in-1 floor+wall (#150, #153), system/commercial
|
||||
# (#52), and ARA-WW wall-mount (#115, #116, #117, #120).
|
||||
# (#52), cassette (#191), and ARA-WW wall-mount (#115, #116, #117, #120).
|
||||
'RAC': 'airconditioner',
|
||||
'PRAC': 'airconditioner',
|
||||
'KRAC': 'airconditioner',
|
||||
'WAC': 'airconditioner',
|
||||
'FAC': 'airconditioner',
|
||||
'CAWW': 'airconditioner',
|
||||
'CAC': 'airconditioner', # issue #191 -- TP1X_DA-AC-CAC-01001_0000
|
||||
'ARA': 'airconditioner',
|
||||
'DHM': 'dehumidifier', # issue #88 -- target humidity, no climate
|
||||
'TVTL': 'air_purifier', # issue #56 (ARTIK051)
|
||||
'VTWW': 'air_purifier', # issue #151 (BESPOKE Cube Air)
|
||||
'AVT': 'air_purifier', # issue #190 -- AVT-WW-TP1-23-AXX500, a
|
||||
# next-gen BESPOKE Cube Air board; same
|
||||
# lineage as VTWW above but the '-WW-'
|
||||
# delimiter now falls one letter to the
|
||||
# left ('A-VTWW-' -> 'AVT-WW-'), splitting
|
||||
# into a token the existing entry can't see
|
||||
'AIR': 'air_purifier', # issue #130 (TP1X_DA-AC-AIR)
|
||||
'WATERPURIFIER': 'water_purifier', # issue #90
|
||||
'ADW': 'dishwasher',
|
||||
|
||||
@@ -16,6 +16,11 @@ match_fn discriminators that keep them from colliding):
|
||||
token, added for it. Its fan
|
||||
is WIND_STRENGTH_FAN on /wind/strength/vs/0 rather than FAN on
|
||||
/mode/vs/0 -- see that capability's comment.
|
||||
- AVT-WW-TP1-23-class (issue #190). A next-gen board in the same VTWW
|
||||
lineage, resolved via its own 'AVT' board token since the '-WW-' delimiter
|
||||
falls one letter to the left of 'VTWW's whole-token spelling. Same
|
||||
resource surface as A-VTWW-TP2-21-COMMON above; no new capabilities
|
||||
needed.
|
||||
|
||||
Reuses dishwasher.DIAGNOSIS for /diagnosis/vs/0 (identical field/write
|
||||
contract).
|
||||
|
||||
@@ -7,6 +7,13 @@ this registry includes *common.UNIVERSAL but deliberately NOT common.POWER --
|
||||
on/off is the climate entity's HVACMode.OFF / TURN_ON/OFF. See common.POWER's
|
||||
own comment in capabilities/common.py for why it's excluded.
|
||||
|
||||
common.ENERGY_METER itself is also excluded from UNIVERSAL here, replaced by
|
||||
the ENERGY_METER_GENERIC/ENERGY_METER_LEGACY pair -- the legacy ARTIK051 board
|
||||
generation (issue #193) reports cumulativePower in a different unit than
|
||||
every other AC family, so this registry needs two mutually-exclusive variants
|
||||
of that one capability instead of the single shared one every other registry
|
||||
uses unconditionally.
|
||||
|
||||
Reuses dishwasher.DIAGNOSIS for /diagnosis/vs/0.
|
||||
"""
|
||||
from ..capabilities import airconditioner, common, dishwasher, ignored
|
||||
@@ -16,7 +23,9 @@ REGISTRY = DeviceRegistry(
|
||||
name='airconditioner',
|
||||
capabilities=_build([
|
||||
*ignored.IGNORED,
|
||||
*common.UNIVERSAL,
|
||||
*[c for c in common.UNIVERSAL if c is not common.ENERGY_METER],
|
||||
airconditioner.ENERGY_METER_GENERIC,
|
||||
airconditioner.ENERGY_METER_LEGACY,
|
||||
dishwasher.DIAGNOSIS,
|
||||
airconditioner.CLIMATE,
|
||||
airconditioner.AIR_PURIFY,
|
||||
|
||||
@@ -25,6 +25,7 @@ REGISTRY = DeviceRegistry(
|
||||
fridge.DEFROST_DELAY,
|
||||
fridge.DEFROST_DELAY_NATIVE_DUPLICATE,
|
||||
fridge.DEFROST_BLOCK_STATUS,
|
||||
fridge.DEFINITE_TEMPERATURE_COOLER,
|
||||
fridge.DOORS_FALLBACK,
|
||||
fridge.TEMPERATURES_FALLBACK,
|
||||
fridge.ICEMAKER_STATUS_FALLBACK,
|
||||
|
||||
@@ -14,10 +14,13 @@ None of these caps may go into the global `ALL`/`CAPABILITIES`: `/mode/vs/0`,
|
||||
different schema (see capabilities/__init__.py). They live only in the AC
|
||||
by_type registry.
|
||||
"""
|
||||
from dataclasses import replace
|
||||
|
||||
from ..capability import Capability
|
||||
from ..entities import (
|
||||
BinarySensorDesc, ClimateDesc, NumberDesc, SelectDesc, SensorDesc, SwitchDesc,
|
||||
)
|
||||
from . import common
|
||||
from .common import filter_usage_percent, normalize_temp_unit
|
||||
from .laundry import option_write
|
||||
|
||||
@@ -285,17 +288,64 @@ def _option_token(rep, prefix):
|
||||
def is_legacy_board(resources):
|
||||
"""True for the board generation whose airflow lives in /airflow/vs/0.
|
||||
|
||||
Newer families carry several of the same option tokens (Volume, Sleep,
|
||||
OutdoorTemp, Autoclean) *alongside* dedicated resources for those settings,
|
||||
so an ungated token entity would either duplicate an existing one or apply a
|
||||
scale calibrated elsewhere. Every AC dump on record has one shape or the
|
||||
other: /airflow/vs/0 with no /wind/* at all, or /wind/strength/vs/0 with no
|
||||
/airflow/vs/0. Same test as climate.py's _legacy_airflow(), so the entities
|
||||
below and the climate entity can never disagree about the generation.
|
||||
Newer families carry several of the same option tokens (Sleep, OutdoorTemp,
|
||||
Autoclean) *alongside* dedicated resources for those settings, so an
|
||||
ungated token entity would either duplicate an existing one or apply a
|
||||
scale calibrated elsewhere. (Volume used to be in this list too, back when
|
||||
it had its own gated buzzer_volume Number for this board generation --
|
||||
issue #136 replaced that with the unified 'beep' switch, which applies
|
||||
across every generation and isn't gated here at all.) Every AC dump on
|
||||
record has one shape or the other: /airflow/vs/0 with no /wind/* at all,
|
||||
or /wind/strength/vs/0 with no /airflow/vs/0. Same test as climate.py's
|
||||
_legacy_airflow(), so the entities below and the climate entity can never
|
||||
disagree about the generation.
|
||||
"""
|
||||
return HREF_AIRFLOW in resources and HREF_WIND_STRENGTH not in resources
|
||||
|
||||
|
||||
# This legacy ARTIK051 board generation (issue #193, model AR12NXWXCWKNEU /
|
||||
# ARTIK051_KRAC_18K) reports /energy/consumption/vs/0's cumulativePower in
|
||||
# centiwatt-hours -- raw value 100x the plain Wh every other AC board family
|
||||
# (and common.wh_to_kwh's assumed unit) reports. Confirmed against the
|
||||
# reporter's own SmartThings-app reading: raw '117430000' vs the app's
|
||||
# authoritative 1,174.30 kWh is exactly a /100000 factor (i.e. /100 on top of
|
||||
# wh_to_kwh's own /1000), not wh_to_kwh's plain /1000 alone. No other field in
|
||||
# ENERGY_METER's entities is present on this board's dump, so only
|
||||
# 'energy_kwh' needs a replacement value_fn here; the rest pass through
|
||||
# unchanged in case a future legacy dump ever reports them.
|
||||
def _legacy_cumulative_power_kwh(v):
|
||||
# float, not _int -- matches common.wh_to_kwh's own numeric parsing
|
||||
# (float via _num) rather than this module's integer-only _int, so a
|
||||
# decimal-formatted reading doesn't raise and silently go 'unknown'.
|
||||
try:
|
||||
n = float(v)
|
||||
except (TypeError, ValueError):
|
||||
return None
|
||||
return round(n / 100000.0, 2)
|
||||
|
||||
|
||||
ENERGY_METER_LEGACY = replace(
|
||||
common.ENERGY_METER,
|
||||
match_fn=lambda rep, resources: is_legacy_board(resources),
|
||||
entities=tuple(
|
||||
replace(e, value_fn=_legacy_cumulative_power_kwh)
|
||||
if e.key == 'energy_kwh' else e
|
||||
for e in common.ENERGY_METER.entities
|
||||
),
|
||||
)
|
||||
|
||||
# The non-legacy counterpart to ENERGY_METER_LEGACY above -- identical to
|
||||
# common.ENERGY_METER, just excluding the legacy board generation so the two
|
||||
# capabilities can share /energy/consumption/vs/0 in this registry without
|
||||
# the 'multiple caps need a discriminator' build check tripping (common.
|
||||
# ENERGY_METER itself has no match_fn, since every *other* registry includes
|
||||
# it unconditionally and alone).
|
||||
ENERGY_METER_GENERIC = replace(
|
||||
common.ENERGY_METER,
|
||||
match_fn=lambda rep, resources: not is_legacy_board(resources),
|
||||
)
|
||||
|
||||
|
||||
def _has_option_token(prefix):
|
||||
return lambda rep, resources: (
|
||||
is_legacy_board(resources) and _option_token(rep, prefix) is not None)
|
||||
@@ -445,14 +495,19 @@ CLIMATE = Capability(
|
||||
icon='mdi:led-on', entity_category='config'),
|
||||
# Beep on/off from the `Volume_*` option token (Volume_Mute/Volume_100).
|
||||
# Single-token option_write; a full options RMW reverts on ARTIK051_PRAC.
|
||||
# Gated off the legacy ARTIK051 board generation (see is_legacy_board):
|
||||
# that generation's own Volume_ token is already modeled as the
|
||||
# buzzer_volume Number below, and both reading the same options[] slot
|
||||
# into two entities would be redundant.
|
||||
#
|
||||
# Applies uniformly across board generations, including legacy
|
||||
# ARTIK051 boards -- issue #136: this token was originally modeled as
|
||||
# a 0-100 buzzer_volume Number for legacy boards on the assumption it
|
||||
# was a real graduated volume level, but every unit confirmed on
|
||||
# hardware (three units across two reporters) only ever carries
|
||||
# Volume_100 or Volume_Mute, never an intermediate value, and the
|
||||
# Number's write path (a plain integer string) could never produce
|
||||
# the literal 'Mute' token needed to actually turn it off -- writing
|
||||
# '0' is simply not a token this firmware recognizes. A switch is
|
||||
# both the correct model and the actual fix.
|
||||
SwitchDesc(key='beep', rep_fn=_beep_on,
|
||||
exists_fn=lambda rep, resources: (
|
||||
not is_legacy_board(resources)
|
||||
and _option_token(rep, 'Volume') is not None),
|
||||
exists_fn=lambda rep, resources: _option_token(rep, 'Volume') is not None,
|
||||
write_fn=_beep_write,
|
||||
icon='mdi:volume-high', entity_category='config'),
|
||||
# Tropical night mode level (0-16) from the `Sleep_<N>` option token.
|
||||
@@ -498,11 +553,6 @@ CLIMATE = Capability(
|
||||
exists_fn=_has_option_token('AirMonitoring'),
|
||||
write_fn=_option_switch_write('AirMonitoring'),
|
||||
icon='mdi:air-filter', entity_category='config'),
|
||||
NumberDesc(key='buzzer_volume', rep_fn=_option_token_num('Volume'),
|
||||
exists_fn=_has_option_token('Volume'),
|
||||
write_fn=_option_number_write('Volume'),
|
||||
native_min=0, native_max=100, step=10,
|
||||
icon='mdi:volume-high', entity_category='config'),
|
||||
# "Good Sleep" timer. 0 = off; the upper bound is a guess (the token
|
||||
# carries no range hint and only 0 has been observed on hardware), so a
|
||||
# write above 0 is unverified.
|
||||
|
||||
@@ -259,6 +259,12 @@ def sensor_item_value(items, sensor_type, index=0):
|
||||
|
||||
POWER_GENERIC = Capability(
|
||||
href='/power/0',
|
||||
# Neither href of this pair carried a poll_tier before (issue #56's
|
||||
# follow-up), so power state only ever refreshed on the once-per-30s
|
||||
# summary poll instead of the subscribe/subpoll cadence 'warm' and 'hot'
|
||||
# hrefs get -- the same "signal drives real-time state, but sat in the
|
||||
# slow default tier" gap as REMOTE_CONTROL_GENERIC/VS_FALLBACK above.
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
# Writable when firmware allows remote power; otherwise a read-only
|
||||
# binary_sensor with the same key keeps HA state without a dead switch.
|
||||
@@ -277,6 +283,7 @@ POWER_GENERIC = Capability(
|
||||
POWER_VS_FALLBACK = Capability(
|
||||
href='/power/vs/0',
|
||||
match_fn=lambda rep, resources: '/power/0' not in resources,
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
SwitchDesc(key='power_switch', field='x.com.samsung.da.power',
|
||||
value_fn=lambda v: v == 'On',
|
||||
@@ -604,15 +611,22 @@ SELF_CHECK = Capability(
|
||||
# level: 2 of 6 families confirmed, blanket-added everywhere else).
|
||||
#
|
||||
# POWER is kept separate -- airconditioner is the one family that opts out
|
||||
# of it. Canonical reason (see by_type/airconditioner.py and its test for
|
||||
# pointers back here, not restatements): AC's climate entity already owns
|
||||
# /power/0 and /power/vs/0 via bare, no-entity Capability objects
|
||||
# (airconditioner.COVERAGE), and a second, real POWER_GENERIC/
|
||||
# of it entirely. Canonical reason (see by_type/airconditioner.py and its
|
||||
# test for pointers back here, not restatements): AC's climate entity
|
||||
# already owns /power/0 and /power/vs/0 via bare, no-entity Capability
|
||||
# objects (airconditioner.COVERAGE), and a second, real POWER_GENERIC/
|
||||
# POWER_VS_FALLBACK cap on the same href would make _build() raise (a href
|
||||
# with >1 cap must have every cap discriminated by rt_filter/match_fn, and
|
||||
# the bare COVERAGE cap has neither). Kids-lock/remote-control don't have
|
||||
# this conflict -- no AC dump has ever reported those hrefs -- so they stay
|
||||
# in UNIVERSAL.
|
||||
#
|
||||
# Airconditioner also partially opts out of UNIVERSAL itself, not just
|
||||
# POWER: issue #193 needs ENERGY_METER's cumulativePower scale to differ by
|
||||
# board generation, so by_type/airconditioner.py excludes just that one
|
||||
# member (`*[c for c in common.UNIVERSAL if c is not common.ENERGY_METER]`)
|
||||
# and substitutes airconditioner.ENERGY_METER_GENERIC/ENERGY_METER_LEGACY in
|
||||
# its place -- every other registry still unpacks UNIVERSAL wholesale.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
UNIVERSAL = (
|
||||
|
||||
@@ -108,6 +108,37 @@ TEMP_SETPOINT = Capability(
|
||||
),
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Discrete cooler setpoint (issue #186) -- some single-door ("cooler only")
|
||||
# fridges report no /temperature/current|desired/* pair at all (this href
|
||||
# doesn't match TEMP_CURRENT_GENERIC/TEMP_SETPOINT's '/temperature/current/'
|
||||
# or '/temperature/desired/' prefixes), only this one vendor resource that
|
||||
# bundles the live desired value together with the *specific* values the
|
||||
# unit accepts. That supportedList (e.g. ['1','2','3','4','7'] on the issue
|
||||
# #186 dump) is not a contiguous range -- 5 and 6 genuinely aren't valid
|
||||
# setpoints on this model -- so a NumberDesc with a min/max/step would let a
|
||||
# user pick an unsupported value; modeled as a select reading its own live
|
||||
# options list instead, same shape as BEVERAGE_ZONE/PANTRY_ZONE above.
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
def _definite_cooler_write(p, rep, href=None):
|
||||
return (['temperature', 'definite', 'cooler', 'vs', '0'],
|
||||
{'x.com.samsung.da.definite.desired': p})
|
||||
|
||||
|
||||
DEFINITE_TEMPERATURE_COOLER = Capability(
|
||||
href='/temperature/definite/cooler/vs/0',
|
||||
poll_tier='warm',
|
||||
entities=(
|
||||
SelectDesc(key='cooler_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_cooler_write),
|
||||
),
|
||||
)
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Icemaker nighttime quiet mode
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
@@ -24,6 +24,7 @@ but is effectively read-only in practice.
|
||||
"""
|
||||
from datetime import datetime, timezone, timedelta
|
||||
|
||||
from ..batch import is_stub_rep
|
||||
from ..capability import Capability
|
||||
from ..entities import (
|
||||
BinarySensorDesc, NumberDesc, SelectDesc, SensorDesc, SwitchDesc,
|
||||
@@ -130,6 +131,28 @@ def _option_value(options, prefix):
|
||||
return None
|
||||
|
||||
|
||||
def _has_option(prefix):
|
||||
"""exists_fn for an options-array switch: bind only when the device's own
|
||||
options[] actually carries a `<prefix>_<value>` token.
|
||||
|
||||
fast_preheat/natural_steam were shipped unconditionally (no exists_fn) as
|
||||
an unverified guess (see module docstring) -- issue #183's dump (model
|
||||
NE6516A) reports neither `fastpreheat_*` nor `NaturalSteam_*` in its
|
||||
options[] at all, so both switches were phantom controls: always read as
|
||||
off, and toggling them wrote a token the firmware never recognized in
|
||||
the first place, hence "does not appear to do anything."
|
||||
|
||||
`is_stub_rep(rep) or` keeps the same stub carve-out as cooktop.py's
|
||||
identical per-token exists_fn on its own options[]-array href: a stub
|
||||
/device/0 seed rep (not yet sub-polled) has no options[] at all, and
|
||||
without this an entity whose token is genuinely present would never get
|
||||
a first chance to bind, since exists_fn runs before that first real
|
||||
fetch lands.
|
||||
"""
|
||||
return lambda rep, resources: is_stub_rep(rep) or _option_value(
|
||||
rep.get('x.com.samsung.da.options'), prefix) is not None
|
||||
|
||||
|
||||
def _option_write(prefix, new_value):
|
||||
"""A one-token x.com.samsung.da.options write, mirroring
|
||||
laundry.option_write. NOT independently confirmed on an oven -- issue
|
||||
@@ -199,44 +222,19 @@ def _oven_mode_write(p, rep, href=None):
|
||||
return ['mode', 'vs', '0'], {'x.com.samsung.da.modes': [p]}
|
||||
|
||||
|
||||
def _lamp_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
if not rep.get('x.com.samsung.da.options'):
|
||||
return None
|
||||
return ['mode', 'vs', '0'], {
|
||||
'x.com.samsung.da.options': _option_write('UpperLamp', p),
|
||||
}
|
||||
|
||||
|
||||
def _sound_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
if not rep.get('x.com.samsung.da.options'):
|
||||
return None
|
||||
return ['mode', 'vs', '0'], {
|
||||
'x.com.samsung.da.options': _option_write('Sound', p),
|
||||
}
|
||||
|
||||
|
||||
def _fastpreheat_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
if not rep.get('x.com.samsung.da.options'):
|
||||
return None
|
||||
return ['mode', 'vs', '0'], {
|
||||
'x.com.samsung.da.options': _option_write('fastpreheat', p),
|
||||
}
|
||||
|
||||
|
||||
def _naturalsteam_write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
if not rep.get('x.com.samsung.da.options'):
|
||||
return None
|
||||
return ['mode', 'vs', '0'], {
|
||||
'x.com.samsung.da.options': _option_write('NaturalSteam', p),
|
||||
}
|
||||
def _option_switch_write(prefix):
|
||||
"""Factory for a single-token on/off options-array write -- lamp, sound,
|
||||
fast_preheat, natural_steam, energy_saving, and cooktop_on_alert were all
|
||||
a byte-for-byte copy of this same shape, one per prefix."""
|
||||
def write(p, rep, href=None):
|
||||
if p not in ('On', 'Off'):
|
||||
return None
|
||||
if not rep.get('x.com.samsung.da.options'):
|
||||
return None
|
||||
return ['mode', 'vs', '0'], {
|
||||
'x.com.samsung.da.options': _option_write(prefix, p),
|
||||
}
|
||||
return write
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
@@ -377,19 +375,38 @@ OVEN_MODE = Capability(
|
||||
SwitchDesc(key='lamp', field='x.com.samsung.da.options',
|
||||
icon='mdi:track-light',
|
||||
value_fn=lambda opts: _option_value(opts, 'UpperLamp') == 'On',
|
||||
write_fn=_lamp_write),
|
||||
write_fn=_option_switch_write('UpperLamp')),
|
||||
SwitchDesc(key='sound', field='x.com.samsung.da.options',
|
||||
icon='mdi:volume-high',
|
||||
entity_category='config',
|
||||
value_fn=lambda opts: _option_value(opts, 'Sound') == 'On',
|
||||
write_fn=_sound_write),
|
||||
write_fn=_option_switch_write('Sound')),
|
||||
SwitchDesc(key='fast_preheat', field='x.com.samsung.da.options',
|
||||
icon='mdi:fire',
|
||||
exists_fn=_has_option('fastpreheat'),
|
||||
value_fn=lambda opts: _option_value(opts, 'fastpreheat') == 'On',
|
||||
write_fn=_fastpreheat_write),
|
||||
write_fn=_option_switch_write('fastpreheat')),
|
||||
SwitchDesc(key='natural_steam', field='x.com.samsung.da.options',
|
||||
icon='mdi:kettle-steam',
|
||||
exists_fn=_has_option('NaturalSteam'),
|
||||
value_fn=lambda opts: _option_value(opts, 'NaturalSteam') == 'On',
|
||||
write_fn=_naturalsteam_write),
|
||||
write_fn=_option_switch_write('NaturalSteam')),
|
||||
# 120-hour energy-saving standby (issue #183): confirmed present in
|
||||
# this unit's options[] (EnergySaving_On) and directly requested --
|
||||
# unlike fast_preheat/natural_steam above, this token is real on this
|
||||
# hardware, just previously unbound entirely.
|
||||
SwitchDesc(key='energy_saving', field='x.com.samsung.da.options',
|
||||
icon='mdi:leaf', entity_category='config',
|
||||
exists_fn=_has_option('EnergySaving'),
|
||||
value_fn=lambda opts: _option_value(opts, 'EnergySaving') == 'On',
|
||||
write_fn=_option_switch_write('EnergySaving')),
|
||||
# Cooktop-on alert (issue #183): also confirmed present
|
||||
# (BurnerOnAlert_Off) though the reporter noted it mainly matters for
|
||||
# the SmartThings app's own alerting, not local automation.
|
||||
SwitchDesc(key='cooktop_on_alert', field='x.com.samsung.da.options',
|
||||
icon='mdi:alert-circle-outline', entity_category='config',
|
||||
exists_fn=_has_option('BurnerOnAlert'),
|
||||
value_fn=lambda opts: _option_value(opts, 'BurnerOnAlert') == 'On',
|
||||
write_fn=_option_switch_write('BurnerOnAlert')),
|
||||
),
|
||||
)
|
||||
@@ -158,9 +158,6 @@
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"buzzer_volume": {
|
||||
"name": "Beep volume"
|
||||
},
|
||||
"cook_time": {
|
||||
"name": "Cook time"
|
||||
},
|
||||
@@ -214,6 +211,9 @@
|
||||
"100": "High"
|
||||
}
|
||||
},
|
||||
"cooler_temperature_setpoint": {
|
||||
"name": "Cooler temperature"
|
||||
},
|
||||
"day_brightness": {
|
||||
"name": "Cabinet brightness",
|
||||
"state": {
|
||||
@@ -1018,6 +1018,12 @@
|
||||
"natural_steam": {
|
||||
"name": "Natural steam"
|
||||
},
|
||||
"energy_saving": {
|
||||
"name": "Energy saving"
|
||||
},
|
||||
"cooktop_on_alert": {
|
||||
"name": "Cooktop-on alert"
|
||||
},
|
||||
"power_switch": {
|
||||
"name": "Power"
|
||||
},
|
||||
|
||||
@@ -158,9 +158,6 @@
|
||||
}
|
||||
},
|
||||
"number": {
|
||||
"buzzer_volume": {
|
||||
"name": "Zoemervolume"
|
||||
},
|
||||
"cook_time": {
|
||||
"name": "Bereidingstijd"
|
||||
},
|
||||
@@ -214,6 +211,9 @@
|
||||
"100": "Hoog"
|
||||
}
|
||||
},
|
||||
"cooler_temperature_setpoint": {
|
||||
"name": "Koeler temperatuur"
|
||||
},
|
||||
"day_brightness": {
|
||||
"name": "Helderheid kast",
|
||||
"state": {
|
||||
@@ -1018,6 +1018,12 @@
|
||||
"natural_steam": {
|
||||
"name": "Natuurlijke stoom"
|
||||
},
|
||||
"energy_saving": {
|
||||
"name": "Energiebesparing"
|
||||
},
|
||||
"cooktop_on_alert": {
|
||||
"name": "Waarschuwing kookplaat aan"
|
||||
},
|
||||
"power_switch": {
|
||||
"name": "Voeding"
|
||||
},
|
||||
|
||||
+381
@@ -0,0 +1,381 @@
|
||||
{
|
||||
"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.longnotisubscription": "true",
|
||||
"x.com.samsung.da.periodicnotisubscription": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/airlevelcheck/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.periodicSensingActivationState": "On",
|
||||
"x.com.samsung.da.periodicSensingInterval": "600",
|
||||
"x.com.samsung.da.startSensingOnce": "On",
|
||||
"x.com.samsung.da.sensingState": "NonProcessing",
|
||||
"x.com.samsung.da.lastSensingTime": "1785320820",
|
||||
"x.com.samsung.da.lastSensingLevel": "Kr1",
|
||||
"x.com.samsung.da.autoExeState": "Off",
|
||||
"x.com.samsung.da.supportedAutoExeState": [
|
||||
"Off",
|
||||
"Airpurify",
|
||||
"Alarm"
|
||||
],
|
||||
"x.com.samsung.da.periodicSensingSkipStatus": "Off",
|
||||
"x.com.samsung.da.periodicSensingSkipTime": "03002300"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/convenient/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/wind/strength/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "87",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"87",
|
||||
"89",
|
||||
"90",
|
||||
"91"
|
||||
],
|
||||
"x.com.samsung.da.modesName": [
|
||||
"SMART",
|
||||
"MAX",
|
||||
"WINDFREE",
|
||||
"Sleep"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/filter/hepafilter/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.filterUsage": "30",
|
||||
"x.com.samsung.da.filterUsageResolution": "1",
|
||||
"x.com.samsung.da.filterStatus": "normal",
|
||||
"x.com.samsung.da.filterCapacity": "8760",
|
||||
"x.com.samsung.da.filterCapacityUnit": "Hour",
|
||||
"x.com.samsung.da.filterResetType": [
|
||||
"replaceable"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/dnd/autosleep/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.startTime": "15:00:00",
|
||||
"x.com.samsung.da.endTime": "23:30:00",
|
||||
"x.com.samsung.da.visible": "true",
|
||||
"x.com.samsung.da.useTimeSetting": "true",
|
||||
"x.com.samsung.da.functionState": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/availablecontrolsets/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.sets": "0000000000000000000000000000",
|
||||
"x.com.samsung.da.id": "VTL",
|
||||
"x.com.samsung.da.version": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/da/softreset/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.softwarereset": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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-07-29T10:34:52",
|
||||
"x.com.samsung.da.state": "Deleted"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.cumulativePower": "48656",
|
||||
"x.com.samsung.da.cumulativeSavedPower": "0",
|
||||
"x.com.samsung.da.cumulativeDate": "1785353679",
|
||||
"x.com.samsung.da.cumulativeDateUTC": "1785321279",
|
||||
"x.com.samsung.da.cumulativeUnit": "Wh"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/mode/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.options": [
|
||||
"CountOfSlave_0",
|
||||
"SlavePower01_NotSupported",
|
||||
"Pollution_Off",
|
||||
"SmartSave_Off",
|
||||
"OptionCode_23418",
|
||||
"SmartSleep_Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.power": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/0",
|
||||
"rep": {
|
||||
"value": false
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/sensors/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Sensor for Dust",
|
||||
"x.com.samsung.da.type": "Dust",
|
||||
"x.com.samsung.da.value": [
|
||||
"10",
|
||||
"1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "1",
|
||||
"x.com.samsung.da.description": "Sensor for FineDust",
|
||||
"x.com.samsung.da.type": "FineDust",
|
||||
"x.com.samsung.da.value": [
|
||||
"9",
|
||||
"1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Sensor for Odor",
|
||||
"x.com.samsung.da.type": "Odor",
|
||||
"x.com.samsung.da.value": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "3",
|
||||
"x.com.samsung.da.description": "Sensor for CleanLevel",
|
||||
"x.com.samsung.da.type": "CleanLevel",
|
||||
"x.com.samsung.da.value": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "4",
|
||||
"x.com.samsung.da.description": "Sensor for SuperFineDust",
|
||||
"x.com.samsung.da.type": "SuperFineDust",
|
||||
"x.com.samsung.da.value": [
|
||||
"6",
|
||||
"1"
|
||||
]
|
||||
}
|
||||
],
|
||||
"x.com.samsung.da.total": "5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modelNum": "AVT-WW-TP1-23-AXX500|10238841|70000535001611CC0D10090301080000",
|
||||
"x.com.samsung.da.description": "AVT-WW-TP1-23-AXX500",
|
||||
"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": "AC0",
|
||||
"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": "02530A260327",
|
||||
"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": "22120702,22022301",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Firmware",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/file/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.timeoffset": "+09:00"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/configuration/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.region": "2824500000",
|
||||
"x.com.samsung.da.airconOptionList": [
|
||||
"WELCOMECARE",
|
||||
"AI_PURIFY"
|
||||
],
|
||||
"x.com.samsung.da.countryCode": ""
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/humidity/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/humidity/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/devicespecificinfo/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.deviceActive": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "AVT-WW-TP1-23-AXX500",
|
||||
"versions": [
|
||||
"12260327"
|
||||
],
|
||||
"visVersion": "260327"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "",
|
||||
"versions": [
|
||||
"22120702",
|
||||
"22022301"
|
||||
],
|
||||
"visVersion": "221207"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "",
|
||||
"versions": [
|
||||
"22120702",
|
||||
"22022301"
|
||||
],
|
||||
"visVersion": "221207"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "/option/muteonce/vs/0",
|
||||
"rep": {
|
||||
"muteonce": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wirelessinfo/vs/0",
|
||||
"rep": {
|
||||
"macaddressWiFi": "**REDACTED**",
|
||||
"macaddressBLE": "**REDACTED**",
|
||||
"connectedApSsid": "ASUS_2.4G"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/quickcontrol/info/vs/0",
|
||||
"rep": {
|
||||
"supportedVersion": "1.0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,231 @@
|
||||
{
|
||||
"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": "/airflow/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.speedLevel": "0",
|
||||
"x.com.samsung.da.direction": "All"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/airflow/0",
|
||||
"rep": {
|
||||
"speed": 0,
|
||||
"direction": "All"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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-07-29T12:29:36",
|
||||
"x.com.samsung.da.state": "Deleted"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "1",
|
||||
"x.com.samsung.da.description": "Alarm",
|
||||
"x.com.samsung.da.alarmType": "Device",
|
||||
"x.com.samsung.da.code": "FilterAlarm_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-07-29T12:29:36",
|
||||
"x.com.samsung.da.state": "Deleted"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "23",
|
||||
"x.com.samsung.da.current": "23",
|
||||
"x.com.samsung.da.maximum": "30",
|
||||
"x.com.samsung.da.minimum": "16",
|
||||
"x.com.samsung.da.unit": "Celsius"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperature/current/0",
|
||||
"rep": {
|
||||
"range": [
|
||||
16.0,
|
||||
30.0
|
||||
],
|
||||
"units": "C",
|
||||
"temperature": 23.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperature/desired/0",
|
||||
"rep": {
|
||||
"range": [
|
||||
16.0,
|
||||
30.0
|
||||
],
|
||||
"units": "C",
|
||||
"temperature": 23.0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/diagnosis/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.diagnosisStart": "Ready"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.cumulativePower": "117430000",
|
||||
"x.com.samsung.da.cumulativeDate": "1785337200"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/mode/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"Cool",
|
||||
"Dry",
|
||||
"Wind",
|
||||
"Auto",
|
||||
"Heat"
|
||||
],
|
||||
"x.com.samsung.da.modes": [
|
||||
"Cool"
|
||||
],
|
||||
"x.com.samsung.da.options": [
|
||||
"Comode_Off",
|
||||
"Sleep_0",
|
||||
"OutdoorTemp_85",
|
||||
"CoolCapa_35",
|
||||
"WarmCapa_35",
|
||||
"Spi_Off",
|
||||
"Autoclean_Off",
|
||||
"Light_Off",
|
||||
"Volume_100",
|
||||
"AirMonitoring_Off",
|
||||
"AutocleanProgress_0",
|
||||
"StopAutoClean_Idle",
|
||||
"FilterTime_1425",
|
||||
"FilterAlarmTime_500",
|
||||
"OptionCode_56378",
|
||||
"ExtendOptionCode_7",
|
||||
"RacInfo_None",
|
||||
"UpdateAllow_NotAllowed"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/0",
|
||||
"rep": {
|
||||
"supportedModes": [
|
||||
"Cool",
|
||||
"Dry",
|
||||
"Wind",
|
||||
"Auto",
|
||||
"Heat"
|
||||
],
|
||||
"modes": [
|
||||
"Cool"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.power": "On"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/0",
|
||||
"rep": {
|
||||
"value": true
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modelNum": "ARTIK051_KRAC_18K|10193441|60010123001111110100000000000000",
|
||||
"x.com.samsung.da.description": "ARTIK051_KRAC_18K",
|
||||
"x.com.samsung.da.serialNum": "**REDACTED**",
|
||||
"x.com.samsung.da.otnDUID": "**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": "02016A200825",
|
||||
"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": "17110700,17110600",
|
||||
"x.com.samsung.da.newVersionAvailable": "0"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/file/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.timeoffset": "+03:00",
|
||||
"x.com.samsung.supprtedtype": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/configuration/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.region": "0000000000"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/humidity/0",
|
||||
"rep": {
|
||||
"humidity": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/humidity/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.humidity": "0"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+919
@@ -0,0 +1,919 @@
|
||||
{
|
||||
"device0": [
|
||||
{
|
||||
"rt": [
|
||||
"x.com.samsung.devcol",
|
||||
"oic.wk.col"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.ll",
|
||||
"oic.if.b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"href": "/airlevelcheck/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.periodicSensingInterval": "1800",
|
||||
"x.com.samsung.da.sensingState": "NonProcessing",
|
||||
"x.com.samsung.da.lastSensingTime": "1785327477",
|
||||
"x.com.samsung.da.lastSensingLevel": "Kr1",
|
||||
"x.com.samsung.da.periodicSensingSkipStatus": "Off",
|
||||
"x.com.samsung.da.periodicSensingSkipTime": "00000000",
|
||||
"x.com.samsung.da.periodicSensingActivationState": "On",
|
||||
"x.com.samsung.da.autoExeState": "Alarm",
|
||||
"x.com.samsung.da.supportedAutoExeState": [
|
||||
"Airpurify",
|
||||
"Alarm",
|
||||
"Sensing"
|
||||
],
|
||||
"x.com.samsung.da.startSensingOnce": "Off",
|
||||
"x.com.samsung.da.autoExeSetting": "On",
|
||||
"x.com.samsung.da.supportedAutoExeSetting": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "/alarms/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.alarmType": "Device",
|
||||
"x.com.samsung.da.code": "ErrorCode_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-07-29T12:19:55",
|
||||
"x.com.samsung.da.state": "Deleted"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "1",
|
||||
"x.com.samsung.da.alarmType": "Device",
|
||||
"x.com.samsung.da.code": "FilterAlarm_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-07-29T12:19:55",
|
||||
"x.com.samsung.da.state": "Deleted"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.alarmType": "Device",
|
||||
"x.com.samsung.da.code": "DA_SAC_M_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-07-29T12:19:55",
|
||||
"x.com.samsung.da.state": "Deleted"
|
||||
}
|
||||
],
|
||||
"rt": [
|
||||
"x.com.samsung.da.alarms"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/availablecontrolsets/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.sets": "000100B4012C0000B20001000000",
|
||||
"x.com.samsung.da.id": "CAC",
|
||||
"x.com.samsung.da.version": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/configuration/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.region": "4146100000",
|
||||
"x.com.samsung.da.airconOptionList": [
|
||||
"AI_KOREA_COOLONLY_4.0",
|
||||
"HOMECARE_WIZARD_V2",
|
||||
"CLEAN_OPTION_SUPPORT",
|
||||
"DR",
|
||||
"SingleCommand_1"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/da/softreset/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.softwarereset": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/drlc/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.start": "2026-07-29T07:26:56Z",
|
||||
"x.com.samsung.da.override": "Off",
|
||||
"x.com.samsung.da.durationminutes": "1019",
|
||||
"x.com.samsung.da.drlcLevel": "1",
|
||||
"x.com.samsung.da.realSaving": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/edgelighting/vs/0",
|
||||
"rep": {
|
||||
"status": "On",
|
||||
"convenientMode": "On",
|
||||
"operatingOption": "On",
|
||||
"welcomeLightStatus": "Off",
|
||||
"colorOption": "3000K",
|
||||
"mode": "Smart",
|
||||
"modeSupportedList": [
|
||||
"Smart",
|
||||
"High",
|
||||
"Low"
|
||||
],
|
||||
"colorSupportedList": [
|
||||
"3000K",
|
||||
"4000K",
|
||||
"6500K"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/energy/consumption/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.cumulativeDate": "1785327589",
|
||||
"x.com.samsung.da.instantaneousPower": "15",
|
||||
"x.com.samsung.da.cumulativeSavedPower": "1611",
|
||||
"x.com.samsung.da.cumulativePower": "84044",
|
||||
"x.com.samsung.da.cumulativeUnit": "Wh",
|
||||
"x.com.samsung.da.instantaneousPowerUnit": "W",
|
||||
"x.com.samsung.da.cumulativePowerType": "individual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/file/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.timeoffset": "+09:00",
|
||||
"x.com.samsung.supprtedtype": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/filter/airdustPM1filter/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.filterUsageResolution": "1",
|
||||
"x.com.samsung.da.filterCapacity": "2400",
|
||||
"x.com.samsung.da.filterCapacityUnit": "Hour",
|
||||
"x.com.samsung.da.filterResetType": [
|
||||
"washable"
|
||||
],
|
||||
"x.com.samsung.da.filterStatus": "normal",
|
||||
"x.com.samsung.da.filterUsage": "11"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/filter/airdustfilter/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.filterUsageResolution": "1",
|
||||
"x.com.samsung.da.filterCapacity": "180",
|
||||
"x.com.samsung.da.filterCapacityUnit": "Hour",
|
||||
"x.com.samsung.da.filterResetType": [
|
||||
"washable"
|
||||
],
|
||||
"x.com.samsung.da.filterStatus": "normal",
|
||||
"x.com.samsung.da.filterUsage": "26"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/humidity/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.humidity": "0",
|
||||
"x.com.samsung.da.fivepercentHumidity": "59"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.otnDUID": "**REDACTED**",
|
||||
"x.com.samsung.da.modelNum": "TP1X_DA-AC-CAC-01001_0000|10255541|60030748171811DF42005F2A00F2ED00",
|
||||
"x.com.samsung.da.description": "TP1X_DA-AC-CAC-01001_0000",
|
||||
"x.com.samsung.da.serialNum": "**REDACTED**",
|
||||
"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": "02706A260401",
|
||||
"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.newVersionAvailable": "0",
|
||||
"x.com.samsung.da.number": "02555A25052600,02556A24040200"
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Version",
|
||||
"x.com.samsung.da.type": "Outdoor",
|
||||
"x.com.samsung.da.newVersionAvailable": "0",
|
||||
"x.com.samsung.da.number": "FFFFFFFFFFFFFF,FFFFFFFFFFFFFF"
|
||||
}
|
||||
],
|
||||
"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": "AS3",
|
||||
"x.com.samsung.da.diagProtocolType": "BLE_OCF",
|
||||
"x.com.samsung.da.diagMinVersion": "3.0",
|
||||
"x.com.samsung.da.diagTsId": "DA01"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/keepnormalstate/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.keepnormal": 0
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/light/stateful/vs/0",
|
||||
"rep": {
|
||||
"status": "On",
|
||||
"mode": "Smart",
|
||||
"supportedModes": [
|
||||
"Smart",
|
||||
"Low",
|
||||
"High"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mds/absenceclean/vs/0",
|
||||
"rep": {
|
||||
"mode": "Off",
|
||||
"supportedModes": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mds/absencemonitoring/vs/0",
|
||||
"rep": {
|
||||
"status": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mds/absencepowersaving/vs/0",
|
||||
"rep": {
|
||||
"status": "On",
|
||||
"modes": "Cooling",
|
||||
"switchPowerSaveMode": "Normal",
|
||||
"supportedModes": [
|
||||
"Standby",
|
||||
"Cooling"
|
||||
],
|
||||
"supportedSwitchPowerSaveMode": [
|
||||
"Eco",
|
||||
"Normal",
|
||||
"Comfort"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mds/absencestate/vs/0",
|
||||
"rep": {
|
||||
"status": "On",
|
||||
"absenceTime": "0",
|
||||
"maxDetectCount": [
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"3",
|
||||
"3",
|
||||
"3",
|
||||
"2",
|
||||
"3",
|
||||
"0",
|
||||
"0",
|
||||
"3",
|
||||
"0",
|
||||
"3",
|
||||
"3",
|
||||
"3",
|
||||
"0",
|
||||
"3",
|
||||
"1",
|
||||
"2",
|
||||
"3",
|
||||
"3",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"1",
|
||||
"0",
|
||||
"3",
|
||||
"2",
|
||||
"3",
|
||||
"1",
|
||||
"2",
|
||||
"1",
|
||||
"0",
|
||||
"0",
|
||||
"0",
|
||||
"0"
|
||||
],
|
||||
"supportedTimes": [
|
||||
"0",
|
||||
"30",
|
||||
"60",
|
||||
"120"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/convenient/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "Off",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"Off",
|
||||
"Nano",
|
||||
"LongWind",
|
||||
"Speed",
|
||||
"Sleep",
|
||||
"NanoSleep"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": [
|
||||
"Cool"
|
||||
],
|
||||
"workingMode": "Cool",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"AIComfort",
|
||||
"Auto",
|
||||
"Cool",
|
||||
"Dry",
|
||||
"Fan"
|
||||
],
|
||||
"x.com.samsung.da.options": [
|
||||
"OptionCode_512",
|
||||
"Sleep_0",
|
||||
"ArtificialWorking_Off",
|
||||
"ComfortAICooling_Off",
|
||||
"AiTempChanged_Off",
|
||||
"AiTemp_240",
|
||||
"welcomecareElapsedTime_0",
|
||||
"welcomecareThresholdTemp_0",
|
||||
"welcomecareStartDate_0000",
|
||||
"welcomecareEndDate_0000",
|
||||
"welcomecareSeason_None",
|
||||
"welcomecare_Off",
|
||||
"DiagnosisAI_Off",
|
||||
"ProgressDiagnosisAI_0",
|
||||
"ResultDiagnosisAI_Normal",
|
||||
"SmartCoolClean_Off",
|
||||
"ProgressSmartClean_0",
|
||||
"FreezeAlarmSetting_On",
|
||||
"DesiredFreezeAlarm_112",
|
||||
"ExtendOptionCode_0",
|
||||
"UpdateAllow_NotAllowed",
|
||||
"DurationOn_0",
|
||||
"OutdoorTemp_55",
|
||||
"KeyInputPermit_On",
|
||||
"ModePermit_NoLimit"
|
||||
],
|
||||
"rt": [
|
||||
"x.com.samsung.da.mode"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
],
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Temperature",
|
||||
"x.com.samsung.da.current": "28.5",
|
||||
"x.com.samsung.da.desired": "28.0",
|
||||
"x.com.samsung.da.minimum": "18",
|
||||
"x.com.samsung.da.maximum": "30",
|
||||
"x.com.samsung.da.increment": "0.5",
|
||||
"x.com.samsung.da.unit": "Celsius"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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.supportedStatus": [
|
||||
"Start",
|
||||
"Stop"
|
||||
],
|
||||
"x.com.samsung.da.progress": "0",
|
||||
"x.com.samsung.da.settingStatus": "On",
|
||||
"x.com.samsung.da.supportedSettingStatus": [
|
||||
"On",
|
||||
"Off"
|
||||
],
|
||||
"defaultSettingStatus": "On"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/option/motiondetectwind/stateful/vs/0",
|
||||
"rep": {
|
||||
"status": "On",
|
||||
"modes": "Indirect",
|
||||
"supportedModes": [
|
||||
"Indirect",
|
||||
"Direct"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/option/muteonce/vs/0",
|
||||
"rep": {
|
||||
"muteonce": "Off"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/personality/presence/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/power/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.power": "Off",
|
||||
"operationNumber": "46"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/realtimenotiforclient/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.timeforshortnoti": "0",
|
||||
"x.com.samsung.da.longnotisubscription": "true",
|
||||
"x.com.samsung.da.periodicnotisubscription": "true"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "/reserverulesets/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.sets": "1F121E121E121E121EFFFFFFFF010001000F0001000E0000001C3E",
|
||||
"x.com.samsung.da.id": "CAC",
|
||||
"x.com.samsung.da.version": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/sac/installationinfo/vs/0",
|
||||
"rep": {
|
||||
"installationOptions": [
|
||||
{
|
||||
"id": "0",
|
||||
"option": "184449945E0484800017"
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"option": "28010000010000000100"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"option": "50000000000000000001"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"option": "30000000000000000000"
|
||||
}
|
||||
],
|
||||
"installationDeviceNum": [
|
||||
{
|
||||
"id": "0",
|
||||
"number": "0"
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"number": "5"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"number": "0"
|
||||
}
|
||||
],
|
||||
"outdoorInfo": [
|
||||
{
|
||||
"id": "0",
|
||||
"info": "02571A250514",
|
||||
"serial": "**REDACTED**"
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"info": "000000000000",
|
||||
"serial": "**REDACTED**"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"info": "000000000000",
|
||||
"serial": "**REDACTED**"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"info": "000000000000",
|
||||
"serial": "**REDACTED**"
|
||||
}
|
||||
],
|
||||
"mcuInfo": [
|
||||
{
|
||||
"id": "0",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "1",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "2",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "3",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "4",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "5",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "6",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "7",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "8",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "9",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "10",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "11",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "12",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "13",
|
||||
"info": "000000000000"
|
||||
},
|
||||
{
|
||||
"id": "14",
|
||||
"info": "000000000000"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/selfcheck/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.start": "Cancel",
|
||||
"x.com.samsung.da.status": "Ready",
|
||||
"x.com.samsung.da.progress": "0",
|
||||
"x.com.samsung.da.result": "NA",
|
||||
"x.com.samsung.da.supportedActions": [
|
||||
"Start",
|
||||
"Cancel"
|
||||
],
|
||||
"x.com.samsung.da.error": [
|
||||
"DA_ERROR_NONE"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/sensors/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.cleanLevel": "1",
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Sensor for CleanLevel",
|
||||
"x.com.samsung.da.type": "CleanLevel",
|
||||
"x.com.samsung.da.value": [
|
||||
"1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "2",
|
||||
"x.com.samsung.da.description": "Sensor for Dust",
|
||||
"x.com.samsung.da.type": "Dust",
|
||||
"x.com.samsung.da.value": [
|
||||
"7",
|
||||
"1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "3",
|
||||
"x.com.samsung.da.description": "Sensor for FineDust",
|
||||
"x.com.samsung.da.type": "FineDust",
|
||||
"x.com.samsung.da.value": [
|
||||
"5",
|
||||
"1"
|
||||
]
|
||||
},
|
||||
{
|
||||
"x.com.samsung.da.id": "4",
|
||||
"x.com.samsung.da.description": "Sensor for SuperFineDust",
|
||||
"x.com.samsung.da.type": "SuperFineDust",
|
||||
"x.com.samsung.da.value": [
|
||||
"5",
|
||||
"1"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/settings/sound/mode/vs/0",
|
||||
"rep": {
|
||||
"mode": "voice",
|
||||
"supportedModes": [
|
||||
"mute",
|
||||
"tone",
|
||||
"voice"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/settings/sound/optimization/vs/0",
|
||||
"rep": {
|
||||
"status": "Off",
|
||||
"supportedModes": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/settings/sound/output/vs/0",
|
||||
"rep": {
|
||||
"deviceType": "speaker"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/settings/sound/volume/vs/0",
|
||||
"rep": {
|
||||
"level": "2",
|
||||
"minLevel": "0",
|
||||
"maxLevel": "3",
|
||||
"resolution": "1"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/smartsensingcooling/vs/0",
|
||||
"rep": {
|
||||
"status": "On",
|
||||
"supportedModes": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/temperature/control/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.increment": "0.5"
|
||||
}
|
||||
},
|
||||
{
|
||||
"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.current": "28.5",
|
||||
"x.com.samsung.da.desired": "28.0",
|
||||
"x.com.samsung.da.minimum": "18",
|
||||
"x.com.samsung.da.maximum": "30",
|
||||
"x.com.samsung.da.increment": "0.5",
|
||||
"x.com.samsung.da.unit": "Celsius"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/uvled/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "On",
|
||||
"x.com.samsung.da.start": "Cancel",
|
||||
"x.com.samsung.da.pushAlarmStatus": "Off",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"On",
|
||||
"Off"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wind/direction/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "Fix",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"Left_And_Right",
|
||||
"All"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/wind/strength/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modes": "0",
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"0",
|
||||
"1",
|
||||
"2",
|
||||
"3"
|
||||
],
|
||||
"x.com.samsung.da.modesName": [
|
||||
"Auto",
|
||||
"Low",
|
||||
"Mid",
|
||||
"High"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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 Air conditioner",
|
||||
"osVersion": "4.0"
|
||||
},
|
||||
"otnList": [
|
||||
{
|
||||
"type": "WIFI",
|
||||
"modelId": "ASA-WW-TP1-24-INFSAC",
|
||||
"versions": [
|
||||
"14260401"
|
||||
],
|
||||
"visVersion": "260401"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "04001025554110255641",
|
||||
"versions": [
|
||||
"25052600",
|
||||
"24040200"
|
||||
],
|
||||
"visVersion": "250526"
|
||||
},
|
||||
{
|
||||
"type": "Micom",
|
||||
"modelId": "FGCAN2",
|
||||
"versions": [
|
||||
"",
|
||||
""
|
||||
],
|
||||
"visVersion": "999999"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "boksil"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/quickcontrol/info/vs/0",
|
||||
"rep": {
|
||||
"supportedVersion": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/dginformation/vs/0",
|
||||
"rep": {
|
||||
"enrolmentstatus": "Unknown",
|
||||
"devicestate": "Unknown",
|
||||
"lockstatus": "Unknown",
|
||||
"nextduedate": "",
|
||||
"workingminutes": 0,
|
||||
"paymentinfo": {
|
||||
"emiplan": "Unknown",
|
||||
"currency": "Unknown",
|
||||
"totalemi": 0,
|
||||
"totalemipaid": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
{
|
||||
"state_keys": [
|
||||
"alarm_code",
|
||||
"clean_level",
|
||||
"device_active",
|
||||
"dust",
|
||||
"energy_kwh",
|
||||
"energy_saved_kwh",
|
||||
"fine_dust",
|
||||
"firmware_update",
|
||||
"hepa_filter_status",
|
||||
"hepa_filter_usage",
|
||||
"mute_once",
|
||||
"odor",
|
||||
"power_switch",
|
||||
"super_fine_dust",
|
||||
"wind_strength_fan"
|
||||
]
|
||||
}
|
||||
@@ -3,7 +3,7 @@
|
||||
"air_monitoring",
|
||||
"alarm_code",
|
||||
"auto_clean_legacy",
|
||||
"buzzer_volume",
|
||||
"beep",
|
||||
"climate",
|
||||
"current_temperature_c",
|
||||
"diagnosis_status",
|
||||
@@ -15,4 +15,4 @@
|
||||
"outdoor_temperature",
|
||||
"spi"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
{
|
||||
"state_keys": [
|
||||
"air_monitoring",
|
||||
"alarm_code",
|
||||
"auto_clean_legacy",
|
||||
"beep",
|
||||
"climate",
|
||||
"current_temperature_c",
|
||||
"diagnosis_status",
|
||||
"display_light",
|
||||
"energy_kwh",
|
||||
"filter_time",
|
||||
"good_sleep",
|
||||
"humidity",
|
||||
"outdoor_temperature",
|
||||
"spi"
|
||||
]
|
||||
}
|
||||
+30
@@ -0,0 +1,30 @@
|
||||
{
|
||||
"state_keys": [
|
||||
"absence_power_saving_active",
|
||||
"absence_power_saving_mode",
|
||||
"air_filter_status",
|
||||
"air_filter_usage",
|
||||
"air_filter_usage_hours",
|
||||
"air_purify",
|
||||
"alarm_code",
|
||||
"auto_clean",
|
||||
"clean_level",
|
||||
"climate",
|
||||
"current_temperature_c",
|
||||
"dust",
|
||||
"energy_kwh",
|
||||
"energy_saved_kwh",
|
||||
"fine_dust",
|
||||
"firmware_update",
|
||||
"humidity",
|
||||
"motion_detect_wind_active",
|
||||
"motion_detect_wind_mode",
|
||||
"mute_once",
|
||||
"power_watts",
|
||||
"selfcheck_error",
|
||||
"selfcheck_result",
|
||||
"selfcheck_status",
|
||||
"super_fine_dust",
|
||||
"tropical_night_mode"
|
||||
]
|
||||
}
|
||||
Vendored
+1
-3
@@ -7,12 +7,10 @@
|
||||
"current_temp_c",
|
||||
"cycle_active",
|
||||
"door_open",
|
||||
"fast_preheat",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
"lamp",
|
||||
"machine_state",
|
||||
"natural_steam",
|
||||
"operation_time_minutes",
|
||||
"oven_mode",
|
||||
"oven_setpoint",
|
||||
@@ -22,4 +20,4 @@
|
||||
"remote_control",
|
||||
"sound"
|
||||
]
|
||||
}
|
||||
}
|
||||
Vendored
+2
-3
@@ -27,12 +27,11 @@
|
||||
"current_temp_c",
|
||||
"cycle_active",
|
||||
"door_open",
|
||||
"fast_preheat",
|
||||
"energy_saving",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
"lamp",
|
||||
"machine_state",
|
||||
"natural_steam",
|
||||
"operation_time_minutes",
|
||||
"oven_mode",
|
||||
"oven_setpoint",
|
||||
@@ -42,4 +41,4 @@
|
||||
"remote_control",
|
||||
"sound"
|
||||
]
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -4,16 +4,16 @@
|
||||
"child_lock",
|
||||
"cloud_connected",
|
||||
"cook_time",
|
||||
"cooktop_on_alert",
|
||||
"cooktop_running_state",
|
||||
"current_temp_c",
|
||||
"cycle_active",
|
||||
"door_open",
|
||||
"fast_preheat",
|
||||
"energy_saving",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
"lamp",
|
||||
"machine_state",
|
||||
"natural_steam",
|
||||
"operation_time_minutes",
|
||||
"oven_mode",
|
||||
"oven_setpoint",
|
||||
@@ -24,4 +24,4 @@
|
||||
"sound",
|
||||
"warming_center_state"
|
||||
]
|
||||
}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"state_keys": [
|
||||
"alarm_code",
|
||||
"cooktop_on_alert",
|
||||
"child_lock",
|
||||
"cloud_connected",
|
||||
"cook_time",
|
||||
"cooktop_running_state",
|
||||
"current_temp_c",
|
||||
"cycle_active",
|
||||
"door_open",
|
||||
"energy_saving",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
"lamp",
|
||||
"machine_state",
|
||||
"operation_time_minutes",
|
||||
"oven_mode",
|
||||
"oven_setpoint",
|
||||
"oven_state",
|
||||
"power_switch",
|
||||
"progress_percentage",
|
||||
"remote_control",
|
||||
"sound",
|
||||
"warming_center_state"
|
||||
]
|
||||
}
|
||||
+1
-2
@@ -8,12 +8,11 @@
|
||||
"current_temp_c",
|
||||
"cycle_active",
|
||||
"door_open",
|
||||
"fast_preheat",
|
||||
"energy_saving",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
"lamp",
|
||||
"machine_state",
|
||||
"natural_steam",
|
||||
"operation_time_minutes",
|
||||
"oven_mode",
|
||||
"oven_setpoint",
|
||||
|
||||
+3
-3
@@ -4,16 +4,16 @@
|
||||
"child_lock",
|
||||
"cloud_connected",
|
||||
"cook_time",
|
||||
"cooktop_on_alert",
|
||||
"cooktop_running_state",
|
||||
"current_temp_c",
|
||||
"cycle_active",
|
||||
"door_open",
|
||||
"fast_preheat",
|
||||
"energy_saving",
|
||||
"finish_time",
|
||||
"firmware_update",
|
||||
"lamp",
|
||||
"machine_state",
|
||||
"natural_steam",
|
||||
"operation_time_minutes",
|
||||
"oven_mode",
|
||||
"oven_setpoint",
|
||||
@@ -24,4 +24,4 @@
|
||||
"sound",
|
||||
"warming_center_state"
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
{
|
||||
"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",
|
||||
"energy_kwh",
|
||||
"energy_saved_kwh",
|
||||
"firmware_update",
|
||||
"fridge_sound",
|
||||
"night_end",
|
||||
"night_start",
|
||||
"power_energy_kwh",
|
||||
"power_watts",
|
||||
"rapid_freezing",
|
||||
"rapid_fridge",
|
||||
"selfcheck_error",
|
||||
"selfcheck_result",
|
||||
"selfcheck_status"
|
||||
]
|
||||
}
|
||||
+215
@@ -0,0 +1,215 @@
|
||||
{
|
||||
"device0": [
|
||||
{
|
||||
"rt": [
|
||||
"x.com.samsung.devcol",
|
||||
"oic.wk.col"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.ll",
|
||||
"oic.if.b"
|
||||
]
|
||||
},
|
||||
{
|
||||
"href": "/otninformation/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.target": "",
|
||||
"x.com.samsung.da.newVersionAvailable": "false"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/power/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.power": "On"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/alarms/vs/0",
|
||||
"rep": {
|
||||
"rt": [
|
||||
"x.com.samsung.da.alarms"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.s"
|
||||
],
|
||||
"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": "OV_E_OFF",
|
||||
"x.com.samsung.da.triggeredTime": "2026-07-28T23:15:35"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/kidslock/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.kidsLock": "Run"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/configuration/vs/0",
|
||||
"rep": {}
|
||||
},
|
||||
{
|
||||
"href": "/oven/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.state": "Ready",
|
||||
"rt": [
|
||||
"x.com.samsung.da.oven"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.s"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/remotectrl/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.remoteControlEnabled": "true",
|
||||
"rt": [
|
||||
"x.com.samsung.da.configuration"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.s"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"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": "0",
|
||||
"x.com.samsung.da.current": "175",
|
||||
"x.com.samsung.da.increment": "1",
|
||||
"x.com.samsung.da.unit": "Fahrenheit"
|
||||
}
|
||||
],
|
||||
"rt": [
|
||||
"x.com.samsung.da.temperatures"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/mode/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.supportedModes": [
|
||||
"Bake",
|
||||
"Broil",
|
||||
"ConvectionBake",
|
||||
"ConvectionRoast",
|
||||
"KeepWarm",
|
||||
"BreadProof",
|
||||
"AirFryer",
|
||||
"Dehydrate",
|
||||
"SelfClean",
|
||||
"SteamClean"
|
||||
],
|
||||
"x.com.samsung.da.modes": [
|
||||
"NoOperation"
|
||||
],
|
||||
"x.com.samsung.da.options": [
|
||||
"DeviceType_NE6516A-/AA0",
|
||||
"SettingPossible_0",
|
||||
"meatprobe_disconnected",
|
||||
"UpperLamp_Off",
|
||||
"Sound_On",
|
||||
"AdjustingTemp_23",
|
||||
"Sabbath_Off",
|
||||
"EnergySaving_On",
|
||||
"BurnerOnAlert_Off"
|
||||
],
|
||||
"x.com.samsung.da.defaultMode": "ConvectionBake",
|
||||
"x.com.samsung.da.modeSpec": "[{\"mode\":\"Bake\",\"version\":\"0100\",\"default\":\"Normal\",\"control\":\"Start&Setting\",\"cavity\":\"Single\",\"tempMinC\":\"80\",\"tempMaxC\":\"285\",\"tempDefaultC\":\"175\",\"tempListLengthC\":\"0\",\"tempMinF\":\"175\",\"tempMaxF\":\"550\",\"tempDefaultF\":\"350\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:01:00\",\"timeMax\":\"09:59:00\",\"timeDefault\":\"01:00:00\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"0\",\"tempIntervalF\":\"0\",\"probeIntervalC\":\"0\",\"probeIntervalF\":\"0\"},{\"mode\":\"Broil\",\"version\":\"0100\",\"default\":\"Normal\",\"control\":\"Setting\",\"cavity\":\"Single\",\"tempMinC\":\"61441\",\"tempMaxC\":\"61442\",\"tempDefaultC\":\"61441\",\"tempListLengthC\":\"2\",\"tempListDataC\":[\"61441\",\"61442\"],\"tempMinF\":\"61441\",\"tempMaxF\":\"61442\",\"tempDefaultF\":\"61441\",\"tempListLengthF\":\"2\",\"tempListDataF\":[\"61441\",\"61442\"],\"timeMin\":\"NotSupported\",\"timeMax\":\"NotSupported\",\"timeDefault\":\"NotSupported\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"0\",\"tempIntervalF\":\"0\",\"probeIntervalC\":\"0\",\"probeIntervalF\":\"0\"},{\"mode\":\"ConvectionBake\",\"version\":\"0100\",\"default\":\"Default\",\"control\":\"Start&Setting\",\"cavity\":\"Single\",\"tempMinC\":\"80\",\"tempMaxC\":\"285\",\"tempDefaultC\":\"160\",\"tempListLengthC\":\"0\",\"tempMinF\":\"175\",\"tempMaxF\":\"550\",\"tempDefaultF\":\"325\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:01:00\",\"timeMax\":\"09:59:00\",\"timeDefault\":\"01:00:00\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"0\",\"tempIntervalF\":\"0\",\"probeIntervalC\":\"0\",\"probeIntervalF\":\"0\"},{\"mode\":\"ConvectionRoast\",\"version\":\"0100\",\"default\":\"Normal\",\"control\":\"Start&Setting\",\"cavity\":\"Single\",\"tempMinC\":\"80\",\"tempMaxC\":\"285\",\"tempDefaultC\":\"160\",\"tempListLengthC\":\"0\",\"tempMinF\":\"175\",\"tempMaxF\":\"550\",\"tempDefaultF\":\"325\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:01:00\",\"timeMax\":\"09:59:00\",\"timeDefault\":\"01:00:00\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"0\",\"tempIntervalF\":\"0\",\"probeIntervalC\":\"0\",\"probeIntervalF\":\"0\"},{\"mode\":\"KeepWarm\",\"version\":\"0100\",\"default\":\"Normal\",\"control\":\"Setting\",\"cavity\":\"Single\",\"tempMinC\":\"80\",\"tempMaxC\":\"80\",\"tempDefaultC\":\"80\",\"tempListLengthC\":\"1\",\"tempListDataC\":[\"80\"],\"tempMinF\":\"175\",\"tempMaxF\":\"175\",\"tempDefaultF\":\"175\",\"tempListLengthF\":\"1\",\"tempListDataF\":[\"175\"],\"timeMin\":\"NotSupported\",\"timeMax\":\"NotSupported\",\"timeDefault\":\"NotSupported\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"0\",\"tempIntervalF\":\"0\",\"probeIntervalC\":\"0\",\"probeIntervalF\":\"0\"},{\"mode\":\"BreadProof\",\"version\":\"0100\",\"default\":\"Normal\",\"control\":\"Setting\",\"cavity\":\"Single\",\"tempMinC\":\"35\",\"tempMaxC\":\"35\",\"tempDefaultC\":\"35\",\"tempListLengthC\":\"1\",\"tempListDataC\":[\"35\"],\"tempMinF\":\"95\",\"tempMaxF\":\"95\",\"tempDefaultF\":\"95\",\"tempListLengthF\":\"1\",\"tempListDataF\":[\"95\"],\"timeMin\":\"NotSupported\",\"timeMax\":\"NotSupported\",\"timeDefault\":\"NotSupported\",\"probeMinC\":\"NotSupported\",\"probeMaxC\":\"NotSupported\",\"probeDefaultC\":\"NotSupported\",\"probeMinF\":\"NotSupported\",\"probeMaxF\":\"NotSupported\",\"probeDefaultF\":\"NotSupported\",\"powerDefault\":\"NotSupported\",\"powerListLength\":\"0\",\"tempIntervalC\":\"0\",\"tempIntervalF\":\"0\",\"probeIntervalC\":\"0\",\"probeIntervalF\":\"0\"},{\"mode\":\"AirFryer\",\"version\":\"0100\",\"default\":\"Normal\",\"control\":\"Start&Setting\",\"cavity\":\"Single\",\"tempMinC\":\"175\",\"tempMaxC\":\"260\",\"tempDefaultC\":\"220\",\"tempListLengthC\":\"0\",\"tempMinF\":\"350\",\"tempMaxF\":\"500\",\"tempDefaultF\":\"425\",\"tempListLengthF\":\"0\",\"timeMin\":\"00:Line truncated
|
||||
"rt": [
|
||||
"x.com.samsung.da.mode"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/operational/state/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.state": "Ready",
|
||||
"x.com.samsung.da.operationTime": "00:00:00",
|
||||
"x.com.samsung.da.remainingTime": "00:00:00",
|
||||
"x.com.samsung.da.progressPercentage": "1",
|
||||
"rt": [
|
||||
"x.com.samsung.da.operation"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.a"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/doors/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.items": [
|
||||
{
|
||||
"x.com.samsung.da.id": "0",
|
||||
"x.com.samsung.da.description": "Door",
|
||||
"x.com.samsung.da.openState": "Close",
|
||||
"x.com.samsung.da.lock": "Lock"
|
||||
}
|
||||
],
|
||||
"rt": [
|
||||
"x.com.samsung.da.doors"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.s"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/connected/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.connected": "On",
|
||||
"rt": [
|
||||
"x.com.samsung.da.connected"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.s"
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/cooktopmonitoring/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.warmingCenterState": "Off",
|
||||
"x.com.samsung.da.cooktopMonitoring": "0",
|
||||
"x.com.samsung.da.cooktopRunningState": "Ready",
|
||||
"supportedHoodLampStateList": [
|
||||
"Run",
|
||||
"Ready"
|
||||
],
|
||||
"rt": [
|
||||
"x.com.samsung.da.cooktopMonitoring"
|
||||
],
|
||||
"if": [
|
||||
"oic.if.baseline",
|
||||
"oic.if.s"
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,401 @@
|
||||
{
|
||||
"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": "On",
|
||||
"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": "3",
|
||||
"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": "Off",
|
||||
"level.brightness.daytime": "100",
|
||||
"level.brightness.nighttime": "100",
|
||||
"night.starttime": "N/A",
|
||||
"night.duration.minute": "N/A",
|
||||
"timezone.offset": "-03:00",
|
||||
"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/cooler/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.definite.desired": "2",
|
||||
"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/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": "9",
|
||||
"x.com.samsung.da.instantaneousPower": "51",
|
||||
"x.com.samsung.da.cumulativePower": "593883",
|
||||
"x.com.samsung.da.cumulativeSavedPower": "0",
|
||||
"x.com.samsung.da.cumulativeUnit": "Wh",
|
||||
"x.com.samsung.da.instantaneousPowerUnit": "W",
|
||||
"href": "/energy/consumption/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/file/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.timeoffset": "-03:00",
|
||||
"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"
|
||||
],
|
||||
"href": "/energy/ailevel/vs/0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/information/vs/0",
|
||||
"rep": {
|
||||
"x.com.samsung.da.modelNum": "TP1X_REF_21K|00174941|0006012A001811304100000020010000",
|
||||
"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": "24010202, 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.childlock": "Locked",
|
||||
"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.supportedModes": [
|
||||
"HOMECARE_WIZARD_V2",
|
||||
"ENERGY_REPORT_MODEL",
|
||||
"18K_REF_OUTDOOR_CONTROL_V2"
|
||||
],
|
||||
"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": "/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": "035000174941FFFFFFFF",
|
||||
"versions": [
|
||||
"24010202",
|
||||
"FFFFFFFF"
|
||||
],
|
||||
"visVersion": "240102"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/timezone/vs/0",
|
||||
"rep": {
|
||||
"timezoneid": "America/Sao_Paulo",
|
||||
"offset": "-03: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": "Pumba_IoT"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/quickcontrol/info/vs/0",
|
||||
"rep": {
|
||||
"supportedVersion": "1.0"
|
||||
}
|
||||
},
|
||||
{
|
||||
"href": "/dginformation/vs/0",
|
||||
"rep": {
|
||||
"enrolmentstatus": "Unknown",
|
||||
"devicestate": "Unknown",
|
||||
"lockstatus": "Unknown",
|
||||
"nextduedate": "",
|
||||
"workingminutes": 0,
|
||||
"paymentinfo": {
|
||||
"emiplan": "Unknown",
|
||||
"currency": "Unknown",
|
||||
"totalemi": 0,
|
||||
"totalemipaid": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -105,6 +105,47 @@ def test_find_live_ports_detects_silent_port(socket_enabled) -> None:
|
||||
assert result == [live_port]
|
||||
|
||||
|
||||
def test_find_live_ports_rescues_preferred_ports_the_sweep_missed(
|
||||
socket_enabled, monkeypatch,
|
||||
) -> None:
|
||||
"""Issue #192: a segregated VLAN made the ICMP-based sweep call three
|
||||
closed ports live while missing the one port (a historically confirmed
|
||||
DTLS port) that nmap showed as genuinely open|filtered. The sweep's
|
||||
verdict on a preferred port shouldn't be trusted blindly -- it must
|
||||
always come back as a candidate even if the sweep marked it dead, so the
|
||||
config flow gets a real handshake attempt against it.
|
||||
|
||||
Uses an OS-assigned port monkeypatched into PREFERRED_PROBE_PORTS rather
|
||||
than the real 49154/49155, so this doesn't depend on those specific
|
||||
system ports being free on whatever machine runs the suite.
|
||||
"""
|
||||
import socket
|
||||
|
||||
from custom_components.localthings import config_flow
|
||||
from custom_components.localthings.config_flow import _find_live_ports
|
||||
|
||||
# Bind an OS-assigned port and immediately close it, same technique
|
||||
# test_find_live_ports_detects_silent_port uses for its "closed" ports --
|
||||
# once closed, loopback refuses datagrams to it, standing in for the
|
||||
# sweep wrongly ruling out a port we have strong prior evidence for.
|
||||
reserved = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
reserved.bind(('127.0.0.1', 0))
|
||||
preferred_port = reserved.getsockname()[1]
|
||||
reserved.close()
|
||||
monkeypatch.setattr(config_flow, 'PREFERRED_PROBE_PORTS', [preferred_port])
|
||||
|
||||
live_sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
|
||||
live_sock.bind(('127.0.0.1', 0))
|
||||
live_port = live_sock.getsockname()[1]
|
||||
|
||||
try:
|
||||
result = _find_live_ports('127.0.0.1', [preferred_port, live_port], 0.8)
|
||||
finally:
|
||||
live_sock.close()
|
||||
|
||||
assert set(result) == {preferred_port, live_port}
|
||||
|
||||
|
||||
async def test_probe_uses_discovered_low_port(hass: HomeAssistant, monkeypatch) -> None:
|
||||
"""A device that only answers on 49153 — outside the historical
|
||||
49154/49155 pair — is found by the liveness sweep and its port is stored
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
"""Tests for the AVT-WW-TP1-23-AXX500 air-purifier profile (issue #190).
|
||||
|
||||
Next-gen BESPOKE Cube Air board -- same resource surface as the
|
||||
A-VTWW-TP2-21-COMMON family (issue #151), but the '-WW-' delimiter now falls
|
||||
one letter to the left ('A-VTWW-' -> 'AVT-WW-'), splitting into an 'AVT'/'WW'
|
||||
token pair the existing 'VTWW' whole-token entry can't see. The reporter's
|
||||
diagnostics showed device_type 'unknown' with empty oneUiVersion and every
|
||||
resource unbound -- once routed to the existing air_purifier registry, every
|
||||
resource here binds with zero gaps.
|
||||
"""
|
||||
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 tests.conftest import _load_device
|
||||
|
||||
|
||||
def _resources():
|
||||
return _load_device('air_purifier_avt_ww')
|
||||
|
||||
|
||||
def _reg(resources):
|
||||
info = resources['/information/vs/0']
|
||||
return for_device_by_model(
|
||||
info['x.com.samsung.da.modelNum'], info['x.com.samsung.da.description'])
|
||||
|
||||
|
||||
def test_resolves_to_air_purifier_registry():
|
||||
assert _reg(_resources()).name == 'air_purifier'
|
||||
|
||||
|
||||
def test_no_unbound_hrefs():
|
||||
resources = _resources()
|
||||
reg = _reg(resources)
|
||||
unbound = []
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities, log=unbound.append)
|
||||
assert unbound == []
|
||||
|
||||
|
||||
def test_wind_strength_fan_preset_names():
|
||||
"""This dump's /wind/strength/vs/0 reports the same numeric-code +
|
||||
modesName shape as the original VTWW fixture (SMART/MAX/WINDFREE/Sleep),
|
||||
confirming the shared WIND_STRENGTH_FAN capability applies unchanged."""
|
||||
resources = _resources()
|
||||
reg = _reg(resources)
|
||||
bound = discover(resources, reg.capabilities, reg.pattern_capabilities)
|
||||
state = flatten(bound, resources)
|
||||
assert state['wind_strength_fan'] == '87'
|
||||
wind = resources['/wind/strength/vs/0']
|
||||
assert wind['x.com.samsung.da.modesName'] == ['SMART', 'MAX', 'WINDFREE', 'Sleep']
|
||||
|
||||
|
||||
def test_air_quality_and_filter_sensors_present():
|
||||
resources = _resources()
|
||||
reg = _reg(resources)
|
||||
bound = discover(resources, reg.capabilities, reg.pattern_capabilities)
|
||||
state = flatten(bound, resources)
|
||||
assert state['dust'] == 10
|
||||
assert state['fine_dust'] == 9
|
||||
assert state['odor'] == 1
|
||||
assert state['hepa_filter_usage'] == 0
|
||||
assert state['hepa_filter_status'] == 'normal'
|
||||
@@ -102,7 +102,7 @@ def test_token_entities_present_with_calibrated_values():
|
||||
assert state['filter_time'] == 171.5
|
||||
# token - 55 == 19 C, against a 19.4 C forecast at the time of the dump.
|
||||
assert state['outdoor_temperature'] == 19.0
|
||||
assert state['buzzer_volume'] == 100.0
|
||||
assert state['beep'] is True
|
||||
assert state['good_sleep'] == 0.0
|
||||
assert state['spi'] is False
|
||||
assert state['auto_clean_legacy'] is False
|
||||
@@ -115,7 +115,7 @@ def test_token_entities_stay_off_newer_boards():
|
||||
token entities would duplicate them (auto clean) or apply a scale
|
||||
calibrated on another board generation (outdoor temperature)."""
|
||||
state = _state('airconditioner_tp1x_rac')
|
||||
for key in ('spi', 'auto_clean_legacy', 'air_monitoring', 'buzzer_volume',
|
||||
for key in ('spi', 'auto_clean_legacy', 'air_monitoring',
|
||||
'good_sleep', 'outdoor_temperature', 'filter_time'):
|
||||
assert key not in state, key
|
||||
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
"""Tests for the TP1X_DA-AC-CAC-01001_0000 cassette AC (issue #191).
|
||||
|
||||
0.16.0's device-type simplification dropped oneUiVersion detection on the
|
||||
assumption every device it typed was already reachable via a modelNum board
|
||||
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.
|
||||
"""
|
||||
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 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',
|
||||
'/settings/sound/optimization/vs/0',
|
||||
'/settings/sound/output/vs/0',
|
||||
'/settings/sound/volume/vs/0',
|
||||
'/smartsensingcooling/vs/0',
|
||||
'/uvled/vs/0',
|
||||
})
|
||||
|
||||
|
||||
def _resources():
|
||||
return _load_device('airconditioner_cac')
|
||||
|
||||
|
||||
def _reg(resources):
|
||||
info = resources['/information/vs/0']
|
||||
return for_device_by_model(
|
||||
info['x.com.samsung.da.modelNum'], info['x.com.samsung.da.description'])
|
||||
|
||||
|
||||
def test_resolves_to_airconditioner_registry():
|
||||
assert _reg(_resources()).name == 'airconditioner'
|
||||
|
||||
|
||||
def test_documented_coverage_gap_is_exactly_this_set():
|
||||
"""Locks in the current, known-incomplete coverage so a future fix to
|
||||
any of these hrefs shows up as a golden-regression diff (extra keys) to
|
||||
update here, rather than silently shrinking this list unnoticed."""
|
||||
resources = _resources()
|
||||
reg = _reg(resources)
|
||||
unbound = []
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities, log=unbound.append)
|
||||
assert set(unbound) == _STILL_UNBOUND
|
||||
|
||||
|
||||
def test_non_legacy_board_uses_the_generic_energy_scale():
|
||||
"""This board reports /wind/strength/vs/0 (not /airflow/vs/0), so
|
||||
is_legacy_board() is False and it must use the plain wh_to_kwh scale,
|
||||
not the /100000 correction added for the unrelated ARTIK051_KRAC-class
|
||||
board in issue #193."""
|
||||
resources = _resources()
|
||||
reg = _reg(resources)
|
||||
bound = discover(resources, reg.capabilities, reg.pattern_capabilities)
|
||||
state = flatten(bound, resources)
|
||||
assert state['energy_kwh'] == round(84044 / 1000.0, 2)
|
||||
@@ -814,13 +814,61 @@ def test_sensor_item_value_picks_first_value():
|
||||
|
||||
def test_beep_and_tropical_night_stay_off_legacy_krac_board():
|
||||
"""ARTIK051_KRAC_18K (issue #136) reports both a Volume_ and a Sleep_
|
||||
option token, but they're already modeled as buzzer_volume/good_sleep
|
||||
(see airconditioner.CLIMATE) -- beep/tropical_night_mode must not also
|
||||
bind there, or the same options[] slot would surface as two entities."""
|
||||
option token. Volume_ is modeled as the shared 'beep' switch (issue #136's
|
||||
buzzer_volume Number never correctly modeled this board -- see
|
||||
test_legacy_krac_board_beep_is_a_switch_not_a_volume_number below);
|
||||
Sleep_ is still good_sleep, not tropical_night_mode, on this board (see
|
||||
airconditioner.CLIMATE)."""
|
||||
reg, resources = _resolve('airconditioner_artik051_krac_18k')
|
||||
state = flatten(
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities), resources)
|
||||
assert 'beep' not in state
|
||||
assert 'buzzer_volume' not in state
|
||||
assert 'tropical_night_mode' not in state
|
||||
assert state['buzzer_volume'] == 100.0
|
||||
assert state['beep'] is True
|
||||
assert state['good_sleep'] == 0.0
|
||||
|
||||
|
||||
def test_legacy_krac_board_beep_is_a_switch_not_a_volume_number():
|
||||
"""Issue #136: three real units across two reporters only ever reported
|
||||
Volume_100 or Volume_Mute -- never an intermediate value -- and the old
|
||||
buzzer_volume Number's write path (a plain integer string) could never
|
||||
produce the literal 'Mute' token needed to turn it off. 'beep' now
|
||||
applies uniformly across board generations instead of being gated off
|
||||
the legacy board."""
|
||||
reg, resources = _resolve('airconditioner_artik051_krac_18k')
|
||||
state = flatten(
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities), resources)
|
||||
assert state['beep'] is True
|
||||
|
||||
resources['/mode/vs/0']['x.com.samsung.da.options'] = [
|
||||
o.replace('Volume_100', 'Volume_Mute')
|
||||
for o in resources['/mode/vs/0']['x.com.samsung.da.options']
|
||||
]
|
||||
state = flatten(
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities), resources)
|
||||
assert state['beep'] is False
|
||||
|
||||
path, body = airconditioner._beep_write('Off', resources['/mode/vs/0'])
|
||||
assert path == ['mode', 'vs', '0']
|
||||
assert body == {'x.com.samsung.da.options': ['Volume_Mute']}
|
||||
|
||||
|
||||
def test_legacy_krac_board_energy_kwh_uses_centiwatt_hour_scale():
|
||||
"""Issue #193: this legacy ARTIK051 board reports cumulativePower in
|
||||
centiwatt-hours (raw '117430000'), not the plain Wh common.wh_to_kwh
|
||||
assumes -- confirmed against the reporter's own SmartThings-app reading
|
||||
of 1,174.30 kWh. ENERGY_METER_LEGACY's /100000 scale must produce that
|
||||
exact value, not the /1000-only 117430.0 the generic capability would."""
|
||||
reg, resources = _resolve('airconditioner_artik051_krac_energy')
|
||||
state = flatten(
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities), resources)
|
||||
assert state['energy_kwh'] == 1174.3
|
||||
|
||||
|
||||
def test_non_legacy_board_energy_kwh_still_uses_plain_wh_scale():
|
||||
"""The ENERGY_METER_GENERIC/LEGACY split must not change behavior for
|
||||
every other AC board generation -- same value as plain wh_to_kwh."""
|
||||
reg, resources = _ac()
|
||||
state = flatten(
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities), resources)
|
||||
assert state['energy_kwh'] == round(1686632 / 1000.0, 2)
|
||||
@@ -238,6 +238,19 @@ class TestForDeviceByModel:
|
||||
assert reg is not None
|
||||
assert reg.name == 'airconditioner'
|
||||
|
||||
def test_airconditioner_via_cac_token(self):
|
||||
"""Issue #191: a cassette AC (TP1X_DA-AC-CAC-01001_0000) regressed to
|
||||
'unknown'/common-caps in 0.16.0 when oneUiVersion detection was
|
||||
dropped -- 'CAC' had never been added to the modelNum board-token
|
||||
table, only reachable before via oneUiVersion's '7.0 Air conditioner'."""
|
||||
from custom_components.localthings.registry.by_type import for_device_by_model
|
||||
reg = for_device_by_model(
|
||||
'TP1X_DA-AC-CAC-01001_0000|10255541|60030748171811DF42005F2A00F2ED00',
|
||||
'TP1X_DA-AC-CAC-01001_0000',
|
||||
)
|
||||
assert reg is not None
|
||||
assert reg.name == 'airconditioner'
|
||||
|
||||
def test_dehumidifier_via_dhm_token(self):
|
||||
"""Issue #88: a dehumidifier (AY18CG7500GED) shares the DA_AC_ board
|
||||
family with the room-AC models but reports no oneUiVersion and
|
||||
|
||||
@@ -152,6 +152,14 @@ class TestPowerFallback:
|
||||
assert switch.exists_fn(resources['/power/0'], resources) is True
|
||||
assert sensor.exists_fn(resources['/power/0'], resources) is False
|
||||
|
||||
def test_polled_warm_so_power_state_reflects_quickly(self):
|
||||
"""issue #56 follow-up: neither href had a poll_tier, so power state
|
||||
only ever refreshed on the once-per-30s summary poll instead of the
|
||||
subscribe/subpoll cadence 'warm'/'hot' hrefs get -- same reasoning
|
||||
as REMOTE_CONTROL_GENERIC/VS_FALLBACK's own 'warm' tier."""
|
||||
assert common.POWER_GENERIC.poll_tier == 'warm'
|
||||
assert common.POWER_VS_FALLBACK.poll_tier == 'warm'
|
||||
|
||||
|
||||
class TestWmSetinfoFlags:
|
||||
def test_washer_fixture_carries_setinfo_from_device0(self):
|
||||
|
||||
@@ -230,6 +230,44 @@ class TestPantryZone:
|
||||
assert body == {'x.com.samsung.da.mode': 'FDR_WINE'}
|
||||
|
||||
|
||||
class TestDefiniteTemperatureCooler:
|
||||
"""Discrete cooler setpoint (RT42DG6630B1FZ, issue #186) -- a single-door
|
||||
fridge whose /temperature/definite/cooler/vs/0 falls outside both
|
||||
TEMP_CURRENT_GENERIC and TEMP_SETPOINT's href prefixes, so temperature
|
||||
control was entirely unbound before this capability was added."""
|
||||
|
||||
def test_href(self):
|
||||
assert fridge.DEFINITE_TEMPERATURE_COOLER.href == '/temperature/definite/cooler/vs/0'
|
||||
|
||||
def test_write(self):
|
||||
desc = fridge.DEFINITE_TEMPERATURE_COOLER.entities[0]
|
||||
path, body = desc.write_fn('3', {})
|
||||
assert path == ['temperature', 'definite', 'cooler', 'vs', '0']
|
||||
assert body == {'x.com.samsung.da.definite.desired': '3'}
|
||||
|
||||
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_definite_cooler')
|
||||
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'] == '2'
|
||||
|
||||
rep = resources['/temperature/definite/cooler/vs/0']
|
||||
assert rep['x.com.samsung.da.definite.supportedList'] == ['1', '2', '3', '4', '7']
|
||||
|
||||
|
||||
class TestKimchiZone:
|
||||
"""Kimchi-refrigerator compartments (TP2X_REF_20K-class, issue #26) --
|
||||
top/middle/bottom each report an identically-shaped currentMode/
|
||||
|
||||
@@ -859,6 +859,103 @@ def test_registry_reproduces_golden_state_keys_for_airconditioner_fac_bora():
|
||||
)
|
||||
|
||||
|
||||
def test_registry_reproduces_golden_state_keys_for_airconditioner_cac():
|
||||
"""TP1X_DA-AC-CAC-01001_0000 (issue #191) -- fell back to 'unknown' in
|
||||
0.16.0 when oneUiVersion detection was dropped, since 'CAC' had never
|
||||
been added to the modelNum board-token table. Resolved via the new 'CAC'
|
||||
token onto the existing airconditioner registry. Not fully covered yet --
|
||||
ten hrefs remain unbound (edge lighting, PM1 filter, stateful light,
|
||||
absence-clean, four sound-settings resources, smart-sensing-cooling, UV
|
||||
LED), all genuinely new to this board generation and out of scope for
|
||||
the routing fix; see test_airconditioner_cac.py for the documented gap."""
|
||||
from tests.conftest import _load_device
|
||||
resources = _load_device('airconditioner_cac')
|
||||
golden = json.loads((GOLDEN / 'airconditioner_cac.json').read_text())
|
||||
state_keys = _new_state_keys('airconditioner_cac', 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_air_purifier_avt_ww():
|
||||
"""AVT-WW-TP1-23-AXX500 (issue #190) -- next-gen BESPOKE Cube Air board;
|
||||
reports device_type 'unknown' with empty oneUiVersion because 'VTWW' as a
|
||||
whole token doesn't match this board's 'AVT'/'WW' split. Resolved via the
|
||||
new 'AVT' modelNum board-token fallback into the existing air_purifier
|
||||
registry. Binds cleanly with zero unbound hrefs."""
|
||||
from tests.conftest import _load_device
|
||||
resources = _load_device('air_purifier_avt_ww')
|
||||
golden = json.loads((GOLDEN / 'air_purifier_avt_ww.json').read_text())
|
||||
state_keys = _new_state_keys('air_purifier_avt_ww', 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_artik051_krac_energy():
|
||||
"""AR12NXWXCWKNEU/ARTIK051_KRAC_18K (issue #193) -- same legacy board
|
||||
generation as the artik051_krac_18k fixture, but this dump has a nonzero
|
||||
cumulativePower. Locks in state_keys; the actual /100000 scale fix is
|
||||
asserted separately in test_airconditioner_capabilities.py since golden
|
||||
only compares key sets, not values."""
|
||||
from tests.conftest import _load_device
|
||||
resources = _load_device('airconditioner_artik051_krac_energy')
|
||||
golden = json.loads(
|
||||
(GOLDEN / 'airconditioner_artik051_krac_energy.json').read_text()
|
||||
)
|
||||
state_keys = _new_state_keys('airconditioner_artik051_krac_energy', 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_definite_cooler():
|
||||
"""RT42DG6630B1FZ (issue #186) -- a single-door "cooler only" fridge whose
|
||||
/temperature/definite/cooler/vs/0 doesn't match either
|
||||
TEMP_CURRENT_GENERIC's '/temperature/current/' or TEMP_SETPOINT's
|
||||
'/temperature/desired/' href prefix, so temperature control was entirely
|
||||
unbound. Resolved via the new DEFINITE_TEMPERATURE_COOLER capability
|
||||
(a select over the device's own discrete supportedList, not a
|
||||
continuous NumberDesc range -- 5 and 6 aren't valid setpoints on this
|
||||
model). Binds cleanly with zero unbound hrefs."""
|
||||
from tests.conftest import _load_device
|
||||
resources = _load_device('refrigerator_definite_cooler')
|
||||
golden = json.loads(
|
||||
(GOLDEN / 'refrigerator_definite_cooler.json').read_text()
|
||||
)
|
||||
state_keys = _new_state_keys('refrigerator_definite_cooler', 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_range_ne6516a():
|
||||
"""NE6516A-class range (issue #183) -- no /information/vs/0, resolved via
|
||||
the same 'Bake'-in-supportedModes + /cooktopmonitoring/vs/0 signature as
|
||||
the other no-info range fixtures. Its /mode/vs/0 options[] carries
|
||||
EnergySaving_On and BurnerOnAlert_Off (previously unbound entirely) but
|
||||
no fastpreheat_*/NaturalSteam_* tokens at all -- locks in that those two
|
||||
switches now correctly stay unbound instead of binding as always-off,
|
||||
does-nothing phantom controls."""
|
||||
from tests.conftest import _load_device
|
||||
resources = _load_device('range_ne6516a')
|
||||
golden = json.loads((GOLDEN / 'range_ne6516a.json').read_text())
|
||||
state_keys = _new_state_keys('range_ne6516a', 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
|
||||
dump = {
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
"""Tests for the NE6516A-class range (issue #183).
|
||||
|
||||
Same no-/information/vs/0, no-burner-status shape as issues #74/#138. Its
|
||||
/mode/vs/0 options[] carries EnergySaving_On and BurnerOnAlert_Off -- both
|
||||
previously unbound entirely -- but no fastpreheat_*/NaturalSteam_* tokens at
|
||||
all, which is what exposed the pre-existing fast_preheat/natural_steam
|
||||
phantom-switch bug (both were shipped with no exists_fn, so they bound
|
||||
unconditionally, always read off, and any write went to a token this
|
||||
firmware never recognized).
|
||||
"""
|
||||
from custom_components.localthings.registry.adapter import flatten
|
||||
from custom_components.localthings.registry.by_type import for_device_by_resources
|
||||
from custom_components.localthings.registry.discovery import discover
|
||||
|
||||
from tests.conftest import _load_device
|
||||
|
||||
|
||||
def _range():
|
||||
resources = _load_device('range_ne6516a')
|
||||
reg = for_device_by_resources(resources)
|
||||
return reg, resources
|
||||
|
||||
|
||||
def _state():
|
||||
reg, resources = _range()
|
||||
bound = discover(resources, reg.capabilities, reg.pattern_capabilities)
|
||||
return flatten(bound, resources)
|
||||
|
||||
|
||||
def test_resolves_to_range_registry():
|
||||
reg, _ = _range()
|
||||
assert reg is not None and reg.name == 'range'
|
||||
|
||||
|
||||
def test_no_unbound_hrefs():
|
||||
reg, resources = _range()
|
||||
unbound = []
|
||||
discover(resources, reg.capabilities, reg.pattern_capabilities, log=unbound.append)
|
||||
assert unbound == []
|
||||
|
||||
|
||||
def test_fast_preheat_and_natural_steam_absent_without_their_tokens():
|
||||
"""Neither token is in this dump's options[] -- both switches must stay
|
||||
unbound rather than silently reading as an always-off phantom control."""
|
||||
state = _state()
|
||||
assert 'fast_preheat' not in state
|
||||
assert 'natural_steam' not in state
|
||||
|
||||
|
||||
def test_energy_saving_and_cooktop_alert_present():
|
||||
state = _state()
|
||||
assert state['energy_saving'] is True
|
||||
assert state['cooktop_on_alert'] is False
|
||||
|
||||
|
||||
def test_child_lock_already_reads_correctly():
|
||||
"""issue #183 also reported child lock as unreadable -- but this dump's
|
||||
/kidslock/vs/0 ('Run') and /doors/vs/0's door lock field ('Lock') already
|
||||
agree the door is locked, and the existing common.KIDS_LOCK_VS_FALLBACK
|
||||
already reads that correctly with no code change needed."""
|
||||
state = _state()
|
||||
assert state['child_lock'] is True
|
||||
Reference in new issue
Block a user