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:
Marc Billow authored and GitHub committed 2026-07-29 13:14:35 -05:00
commit 3437addc46
37 files changed
+2963 -105

No files matched your search

+18 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
]
}
+1 -3
View File
@@ -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"
]
}
}
+2 -3
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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"
]
}
}
]
}
+401
View File
@@ -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
}
}
}
]
}
+41
View File
@@ -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
+62
View File
@@ -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'
+2 -2
View File
@@ -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
+70
View File
@@ -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)
+53 -5
View File
@@ -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)
+13
View File
@@ -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
+8
View File
@@ -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):
+38
View File
@@ -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/
+97
View File
@@ -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 = {
+62
View File
@@ -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