Deduplicate ISO-timestamp parsing and document the new device type (review follow-up, issue #131)

- vacuum_station._parse_iso_utc was a verbatim copy of
  water_purifier._parse_iso_utc; promoted to common.parse_iso_utc and
  pointed both families at it. Also made it tzinfo-aware rather than
  unconditionally overwriting with UTC -- harmless today since every
  dump seen is a bare or Z-suffixed UTC timestamp, but a board that
  ever emits a real offset would otherwise have it silently clobbered.
- Added the new vacuum_station type to the README's supported-appliance
  table, and noted that combi microwaves route through the oven
  registry.
This commit is contained in:
Marc Billow
2026-07-27 14:43:02 +00:00
parent f37c9ec4ef
commit e9eb38740d
4 changed files with 22 additions and 31 deletions
+2 -1
View File
@@ -25,7 +25,7 @@ Your state stays on your LAN: HA talks to the appliance over a direct DTLS sessi
| Air purifier | `by_type/air_purifier.py` |
| Dehumidifier | `by_type/dehumidifier.py` |
| Dryer | `by_type/dryer.py` |
| Oven | `by_type/oven.py` |
| Oven (including combi microwaves) | `by_type/oven.py` |
| Gas cooktop (read-only burner status) | `by_type/cooktop.py` |
| Range hood | `by_type/range_hood.py` |
| Range | `by_type/range.py` |
@@ -33,6 +33,7 @@ Your state stays on your LAN: HA talks to the appliance over a direct DTLS sessi
| Refrigerator | `by_type/refrigerator.py` |
| Washer | `by_type/washer.py` |
| Water purifier | `by_type/water_purifier.py` |
| Vacuum clean/auto-empty station | `by_type/vacuum_station.py` |
Each registry composes shared and family-specific `Capability` objects from `registry/capabilities/`; those modules document the individual resources/entities in more depth than a README table can stay current with.
@@ -10,6 +10,8 @@ against live device dumps:
/water/consumption/vs/0 -> x.com.samsung.da.cumulativeWater
/filter/waterfilter/vs/0 -> x.com.samsung.da.filterUsage / filterStatus
"""
from datetime import datetime, timezone
from ..capability import Capability
from ..entities import (
BinarySensorDesc, ButtonDesc, SelectDesc, SensorDesc, SwitchDesc,
@@ -40,6 +42,22 @@ def wh_to_kwh(v):
return round(n / 1000.0, 2) if n is not None else None
def parse_iso_utc(raw):
"""ISO datetime defaulting to UTC when the string carries no timezone
of its own (this integration's convention for other bare ISO datetime
fields -- see washer.py's drum-clean-log comment). A few boards do
ship a 'Z'/offset suffix (fromisoformat parses that natively since
Python 3.11) -- only fill in UTC when parsing left the result naive,
rather than unconditionally overwriting whatever offset was parsed."""
if not raw:
return None
try:
dt = datetime.fromisoformat(raw)
except ValueError:
return None
return dt if dt.tzinfo is not None else dt.replace(tzinfo=timezone.utc)
def filter_usage_percent(rep):
"""Filter usage as a percentage of rated capacity. Several families
(AC, air purifier) report `filterUsage` as a raw count in
@@ -15,23 +15,9 @@ docstring for that rule).
Resources verified against the issue #131 diagnostics dump.
"""
from datetime import datetime, timezone
from ..capability import Capability
from ..entities import BinarySensorDesc, SelectDesc, SensorDesc, SwitchDesc
from .common import int_or_none
def _parse_iso_utc(raw):
"""Bare ISO datetime with no timezone field alongside it -- treated as
UTC, matching this integration's convention for other bare ISO datetime
fields (see water_purifier.py's own _parse_iso_utc)."""
if not raw:
return None
try:
return datetime.fromisoformat(raw).replace(tzinfo=timezone.utc)
except ValueError:
return None
from .common import int_or_none, parse_iso_utc as _parse_iso_utc
DUSTBAG = Capability(
@@ -3,23 +3,9 @@ issue #90, model TP2X_WATERPURIFIER_20K).
Resources verified against the issue #90 diagnostics dump.
"""
from datetime import datetime, timezone
from ..capability import Capability
from ..entities import BinarySensorDesc, NumberDesc, SelectDesc, SensorDesc, SwitchDesc
from .common import int_or_none
def _parse_iso_utc(raw):
"""Bare ISO datetime with no timezone field alongside it -- treated as
UTC, matching this integration's convention for other bare ISO datetime
fields (see washer.py's drum-clean-log comment)."""
if not raw:
return None
try:
return datetime.fromisoformat(raw).replace(tzinfo=timezone.utc)
except ValueError:
return None
from .common import int_or_none, parse_iso_utc as _parse_iso_utc
DISPENSE = Capability(