Address Opus review findings on the device-support commits above
- Fix a real bug: airconditioner.SOUND_MODE had no exists_fn, so on boards (issue #319's FAC) that never report a live 'mode' value, entity.py's default field-presence gate silently kept the select from ever registering in HA -- while adapter.flatten() (what the golden/tests read) has no such gate, so the tests passed while documenting behavior the opposite of what shipped. Gate on supportedModes' presence instead. - Add airconditioner.MDS_ABSENCE_CLEAN for the CAC-class board's /mds/absenceclean/vs/0 -- byte-identical shape to issue #319's /csi/absenceclean/vs/0, confirmed rather than guessed, closing one more of that board's documented coverage-gap hrefs. - Add missing translation state labels (all 6 languages) for edge_lighting_mode/edge_lighting_color/indicator_light_mode's raw device codes, so they render as real words instead of a raw '3000K' -> '3000 K' fallback. - Fix an orphaned comment above SOUND_MODE that actually described the unrelated DISPLAY reuse, and correct two inaccurate rationale comments: the sound/voice ignore reason claimed a distinction from SOUND_MODE that this same dump contradicts, and the /csi/* ignore block's 'same reasoning as air_purifier.COVERAGE' precedent only actually covers 1 of its 5 hrefs. - Correct the false 'no board-token match' claim in the FAC test file and golden-regression docstring -- 'FAC' is a real _BOARD_TOKEN_TO_KEY entry (for_device_by_model alone already resolves this board); add a test that actually exercises that path, which nothing previously did despite the docstring's claim. - Drop a tautological burner-slot test that only re-asserted what the golden regression test already covers via the same code path.
This commit is contained in:
@@ -54,6 +54,7 @@ REGISTRY = DeviceRegistry(
|
||||
air_purifier.SOUND_VOLUME,
|
||||
airconditioner.SOUND_MODE,
|
||||
airconditioner.ABSENCE_CLEAN,
|
||||
airconditioner.MDS_ABSENCE_CLEAN,
|
||||
airconditioner.ENERGY_SAVING,
|
||||
airconditioner.EDGE_LIGHTING,
|
||||
airconditioner.LIGHT_STATEFUL,
|
||||
|
||||
@@ -1167,13 +1167,11 @@ HUMIDITY = Capability(
|
||||
),
|
||||
)
|
||||
|
||||
# TP1X_DA-AC-FAC-class additions (issue #319): resources the CAC-class board
|
||||
# (issue #191) also reports but left as a documented gap -- this dump gives
|
||||
# the live supportedModes/mode shapes those needed.
|
||||
# TP1X_DA-AC-FAC-class additions (issue #319): most of these hrefs are the
|
||||
# same shapes air_purifier.py already models on the sibling TP1X_DA-AC-AIR
|
||||
# board (DISPLAY/SOUND_OUTPUT/SOUND_VOLUME, reused directly in the
|
||||
# registry); SOUND_MODE and the two below are genuinely new.
|
||||
|
||||
# Same {mode, supportedModes: [On, Off]} shape as air_purifier.DISPLAY on the
|
||||
# sibling TP1X_DA-AC-AIR board; shares that capability rather than
|
||||
# duplicating it.
|
||||
SOUND_MODE = Capability(
|
||||
href="/settings/sound/mode/vs/0",
|
||||
poll_tier="cold",
|
||||
@@ -1182,12 +1180,22 @@ SOUND_MODE = Capability(
|
||||
# vocabulary, so this shares that catalog entry -- but reads the
|
||||
# live supportedModes field rather than laundry's static tuple,
|
||||
# since this resource carries one (issue #319).
|
||||
#
|
||||
# exists_fn is required, not optional here: this board's rep never
|
||||
# reports a live 'mode' value ({"supportedModes": [...]} only), and
|
||||
# entity.py's default field-presence gate would otherwise keep the
|
||||
# select from ever registering -- adapter.flatten() (what the
|
||||
# golden/tests read) has no such gate, so it would look bound while
|
||||
# silently absent from HA. Register on supportedModes' presence
|
||||
# instead; current_option reads unknown until the device reports
|
||||
# 'mode' live.
|
||||
SelectDesc(
|
||||
key="sound_mode",
|
||||
field="mode",
|
||||
icon="mdi:volume-high",
|
||||
entity_category="config",
|
||||
options_field="supportedModes",
|
||||
exists_fn=lambda rep, resources: bool(rep.get("supportedModes")),
|
||||
write_fn=lambda p, rep, href=None: (
|
||||
["settings", "sound", "mode", "vs", "0"],
|
||||
{"mode": p},
|
||||
@@ -1216,6 +1224,30 @@ ABSENCE_CLEAN = Capability(
|
||||
),
|
||||
)
|
||||
|
||||
# The CAC-class board (issue #191) reports the identical {mode,
|
||||
# supportedModes: [On, Off]} shape under /mds/absenceclean/vs/0 instead --
|
||||
# confirmed against that board's own fixture, not guessed. Shares
|
||||
# ABSENCE_CLEAN's key/translation: no dump has ever reported both hrefs
|
||||
# together, so there's nothing for the two to collide over in
|
||||
# adapter.flatten().
|
||||
MDS_ABSENCE_CLEAN = Capability(
|
||||
href="/mds/absenceclean/vs/0",
|
||||
poll_tier="cold",
|
||||
entities=(
|
||||
SwitchDesc(
|
||||
key="absence_clean",
|
||||
field="mode",
|
||||
icon="mdi:broom",
|
||||
entity_category="config",
|
||||
value_fn=lambda v: v == "On",
|
||||
write_fn=lambda p, rep, href=None: (
|
||||
["mds", "absenceclean", "vs", "0"],
|
||||
{"mode": "On" if p == "On" else "Off"},
|
||||
),
|
||||
),
|
||||
),
|
||||
)
|
||||
|
||||
# Energy-saving schedule (issue #319). `mode` is a device-chosen preset
|
||||
# (e.g. Cooling_60/Off_180) with no confirmed unit for the trailing number
|
||||
# (minutes seen elsewhere on this board are unprefixed ints, not
|
||||
@@ -1415,19 +1447,23 @@ _AC_IGNORED = [
|
||||
# registry.subdevices.enumerate_subdevices, hence the entry here rather
|
||||
# than a coverage gap.
|
||||
"/multidevice/vs/0",
|
||||
# TP1X_DA-AC-FAC-class-only (issue #319), same reasoning as
|
||||
# air_purifier.COVERAGE's duplicate of these hrefs -- scoped here rather
|
||||
# than promoted to the global ignore list since it'd collide with
|
||||
# families that do bind some of these.
|
||||
# TP1X_DA-AC-FAC-class-only (issue #319) -- scoped here rather than
|
||||
# promoted to the global ignore list since it'd collide with families
|
||||
# that do bind some of these. Only /dnd/autosleep/vs/0 has a precedent
|
||||
# (air_purifier.COVERAGE ignores the same href for the same reason);
|
||||
# the rest are new, each with its own reason below.
|
||||
"/dnd/autosleep/vs/0", # every field its inert default; needs a schedule editor
|
||||
"/outdoorsharing/vs/0", # empty on this dump -- outdoor-unit sharing plumbing
|
||||
"/lifestyle/survey/vs/0", # {list: [""]} placeholder, nothing to expose
|
||||
# supportedVoices list only -- no live selection field to read a current
|
||||
# value from, unlike SOUND_MODE/SOUND_OUTPUT above.
|
||||
# supportedVoices carries opaque numeric voice-pack IDs ("100"/"101")
|
||||
# with no live current-selection field and, unlike SOUND_MODE's
|
||||
# self-descriptive mute/tone/voice codes, no confirmed human-readable
|
||||
# meaning to expose them under -- don't guess.
|
||||
"/settings/sound/voice/vs/0",
|
||||
# rssi/wifiFrequency (network housekeeping) plus an unconfirmed
|
||||
# 48-slot absenceInfo P/A history blob with no documented meaning --
|
||||
# don't guess what it encodes.
|
||||
# rssi/wifiFrequency (network housekeeping); lastEnergySavingTime and
|
||||
# cleaningStartTime are inert '1900-01-00' placeholders on this dump;
|
||||
# absenceInfo is an unconfirmed 48-slot P/A history blob with no
|
||||
# documented meaning -- don't guess what it encodes.
|
||||
"/csi/information/vs/0",
|
||||
]
|
||||
|
||||
|
||||
@@ -670,13 +670,28 @@
|
||||
"name": "Teplota mrazicí zóny"
|
||||
},
|
||||
"edge_lighting_mode": {
|
||||
"name": "Režim okrajového osvětlení"
|
||||
"name": "Režim okrajového osvětlení",
|
||||
"state": {
|
||||
"smart": "Chytrý",
|
||||
"high": "Vysoký",
|
||||
"low": "Nízký"
|
||||
}
|
||||
},
|
||||
"edge_lighting_color": {
|
||||
"name": "Barva okrajového osvětlení"
|
||||
"name": "Barva okrajového osvětlení",
|
||||
"state": {
|
||||
"3000k": "3000 K",
|
||||
"4000k": "4000 K",
|
||||
"6500k": "6500 K"
|
||||
}
|
||||
},
|
||||
"indicator_light_mode": {
|
||||
"name": "Režim kontrolky"
|
||||
"name": "Režim kontrolky",
|
||||
"state": {
|
||||
"smart": "Chytrý",
|
||||
"high": "Vysoký",
|
||||
"low": "Nízký"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
|
||||
@@ -670,13 +670,28 @@
|
||||
"name": "Freezer temperature"
|
||||
},
|
||||
"edge_lighting_mode": {
|
||||
"name": "Edge lighting mode"
|
||||
"name": "Edge lighting mode",
|
||||
"state": {
|
||||
"smart": "Smart",
|
||||
"high": "High",
|
||||
"low": "Low"
|
||||
}
|
||||
},
|
||||
"edge_lighting_color": {
|
||||
"name": "Edge lighting color"
|
||||
"name": "Edge lighting color",
|
||||
"state": {
|
||||
"3000k": "3000 K",
|
||||
"4000k": "4000 K",
|
||||
"6500k": "6500 K"
|
||||
}
|
||||
},
|
||||
"indicator_light_mode": {
|
||||
"name": "Indicator light mode"
|
||||
"name": "Indicator light mode",
|
||||
"state": {
|
||||
"smart": "Smart",
|
||||
"high": "High",
|
||||
"low": "Low"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
|
||||
@@ -795,13 +795,28 @@
|
||||
"name": "Temperatura del congelador"
|
||||
},
|
||||
"edge_lighting_mode": {
|
||||
"name": "Modo de iluminación perimetral"
|
||||
"name": "Modo de iluminación perimetral",
|
||||
"state": {
|
||||
"smart": "Inteligente",
|
||||
"high": "Alto",
|
||||
"low": "Bajo"
|
||||
}
|
||||
},
|
||||
"edge_lighting_color": {
|
||||
"name": "Color de iluminación perimetral"
|
||||
"name": "Color de iluminación perimetral",
|
||||
"state": {
|
||||
"3000k": "3000 K",
|
||||
"4000k": "4000 K",
|
||||
"6500k": "6500 K"
|
||||
}
|
||||
},
|
||||
"indicator_light_mode": {
|
||||
"name": "Modo de luz indicadora"
|
||||
"name": "Modo de luz indicadora",
|
||||
"state": {
|
||||
"smart": "Inteligente",
|
||||
"high": "Alto",
|
||||
"low": "Bajo"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
|
||||
@@ -670,13 +670,28 @@
|
||||
"name": "Temperatura freezer"
|
||||
},
|
||||
"edge_lighting_mode": {
|
||||
"name": "Modalità illuminazione perimetrale"
|
||||
"name": "Modalità illuminazione perimetrale",
|
||||
"state": {
|
||||
"smart": "Smart",
|
||||
"high": "Alta",
|
||||
"low": "Bassa"
|
||||
}
|
||||
},
|
||||
"edge_lighting_color": {
|
||||
"name": "Colore illuminazione perimetrale"
|
||||
"name": "Colore illuminazione perimetrale",
|
||||
"state": {
|
||||
"3000k": "3000 K",
|
||||
"4000k": "4000 K",
|
||||
"6500k": "6500 K"
|
||||
}
|
||||
},
|
||||
"indicator_light_mode": {
|
||||
"name": "Modalità spia luminosa"
|
||||
"name": "Modalità spia luminosa",
|
||||
"state": {
|
||||
"smart": "Smart",
|
||||
"high": "Alta",
|
||||
"low": "Bassa"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
|
||||
@@ -670,13 +670,28 @@
|
||||
"name": "냉동실 온도"
|
||||
},
|
||||
"edge_lighting_mode": {
|
||||
"name": "엣지 라이팅 모드"
|
||||
"name": "엣지 라이팅 모드",
|
||||
"state": {
|
||||
"smart": "스마트",
|
||||
"high": "높음",
|
||||
"low": "낮음"
|
||||
}
|
||||
},
|
||||
"edge_lighting_color": {
|
||||
"name": "엣지 라이팅 색상"
|
||||
"name": "엣지 라이팅 색상",
|
||||
"state": {
|
||||
"3000k": "3000 K",
|
||||
"4000k": "4000 K",
|
||||
"6500k": "6500 K"
|
||||
}
|
||||
},
|
||||
"indicator_light_mode": {
|
||||
"name": "표시등 모드"
|
||||
"name": "표시등 모드",
|
||||
"state": {
|
||||
"smart": "스마트",
|
||||
"high": "높음",
|
||||
"low": "낮음"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
|
||||
@@ -670,13 +670,28 @@
|
||||
"name": "Temperatuur vriesgedeelte"
|
||||
},
|
||||
"edge_lighting_mode": {
|
||||
"name": "Randverlichtingsmodus"
|
||||
"name": "Randverlichtingsmodus",
|
||||
"state": {
|
||||
"smart": "Slim",
|
||||
"high": "Hoog",
|
||||
"low": "Laag"
|
||||
}
|
||||
},
|
||||
"edge_lighting_color": {
|
||||
"name": "Randverlichtingskleur"
|
||||
"name": "Randverlichtingskleur",
|
||||
"state": {
|
||||
"3000k": "3000 K",
|
||||
"4000k": "4000 K",
|
||||
"6500k": "6500 K"
|
||||
}
|
||||
},
|
||||
"indicator_light_mode": {
|
||||
"name": "Indicatorlampjemodus"
|
||||
"name": "Indicatorlampjemodus",
|
||||
"state": {
|
||||
"smart": "Slim",
|
||||
"high": "Hoog",
|
||||
"low": "Laag"
|
||||
}
|
||||
}
|
||||
},
|
||||
"sensor": {
|
||||
|
||||
Reference in New Issue
Block a user