Commit Graph
2 Commits
Author SHA1 Message Date
Marc Billow daf7e3787f Add ruff (lint + format) and ty (type checking) to the project
Adds [tool.ruff] and [tool.ty] config to pyproject.toml with a curated
ruff rule set (E, F, W, I, UP, B, C4, SIM, RUF, ASYNC, LOG, G, PIE, RET,
PERF, N), pins ruff/ty in requirements-dev.txt, reformats the whole tree
with `ruff format`, and fixes the pre-existing lint and type-check debt
those tools surfaced so both run clean.

Production-code type fixes include: HA's ConfigFlowResult vs. the
generic FlowResult in config_flow.py, narrowing BoundEntity.desc to its
platform-specific subclass (SelectDesc/NumberDesc/SensorDesc/etc.) via
cast() instead of an unchecked annotation, converting HA device_class
strings to their proper enum types, a resolve_registry callback typed
as `object` instead of `DeviceRegistry | None`, and a couple of other
narrow correctness fixes (CA key type validation, an index-out-of-bounds
false positive from an empty-tuple fallback, a bool/dict argument swap).

Test-file fixes are mechanical: narrowing SamsungEntityDescription to
the correct subclass via isinstance()/cast() before accessing
subclass-only fields, and asserting Optional write_fn/unit_fn fields
are set before calling them.
2026-08-02 23:56:38 +00:00
Marc Billow a7d57086e9 feat: add Samsung Air Monitor Plus support (#210)
New device family: a standalone, battery-powered air-quality sensor
puck (ASM-KR-TP1-22-* board) with no controllable-appliance state at
all -- no /power/*, only /energy/battery/vs/0. Routes via both /oic/d
('x.com.st.d.airqualitysensor', confirmed against the real dump) and
the 'ASM' modelNum board token as a fallback.

/sensors/vs/0 reuses air_purifier.AIR_QUALITY's existing {type, value}
items-list decode (common.sensor_item_value) for dust/fine_dust/
super_fine_dust/odor/clean_level, sharing those capabilities' catalog
entries, and adds a CO2 reading those families don't report. The
particulate sensors deliberately get no pm10/pm25/pm1 device_class:
the values read as physically consistent (coarser >= finer) but
Samsung's own two-tier dust naming doesn't confirm where this board's
three-tier split actually maps, and mislabeling a read-side unit is a
standing, not one-shot, kind of wrong -- exposed as plain named
sensors instead. Humidity, battery/charging, and the informational air
quality standard are otherwise straightforward field reads.

/dnd/vs/0 (do-not-disturb window) is a flagged educated guess: the
write contract mirrors the read side's own string/time-format shape
(the safest kind of guess) but has no idle-vs-active dump to confirm
it end-to-end, so it's called out as such in code and will need a
reporter to verify on real hardware. /keepnormalstate/vs/0 and
/sensordatasinks/vs/0 are genuinely opaque (single unexplained value,
no supported-values list) and are ignored rather than guessed at.

Locked in with a scrubbed fixture, golden, and capability tests.
2026-07-31 02:40:02 +00:00