docs(ac-filter-reset): record a board family with no local reset (#354)
The investigation is written around the FilterTime_<N> option token on /mode/vs/0, and its conclusion holds for the ARTIK051_KRAC_18K it was measured on. An ARTIK051_PRAC_20K has no such token: no FilterTime, no FilterAlarmTime, no FilterCleanAlarm anywhere in its options blob. It keeps the counter in /filter/airdustfilter/vs/0 as a percentage of a 500-hour interval instead. Neither route resets it. FilterCleanAlarm_Clear to /mode/vs/0 returns 4.00 with the options blob byte-identical; writing filterUsage as the string "0" returns 4.00; writing it as an integer returns 5.00. That last difference is the useful part — two payloads differing only in JSON type returning different codes rules out an unresolved href or an unrecognised field name, leaving read-only as the reading. Adds a scope line to the intro and a section documenting the board, its two resource dumps, the attempt table, and an observation-only workaround for percentage-counter boards.
This commit is contained in:
@@ -15,6 +15,12 @@ that follows them explains why the reset looked cloud-only for as long as it
|
||||
did — a genuine trap worth knowing about before the next reset-adjacent
|
||||
mystery on this board family.
|
||||
|
||||
Scope: all of the above applies to boards that carry the counter as a
|
||||
`FilterTime_<N>` option token on `/mode/vs/0`. Not every AC does. See
|
||||
"Boards with no `FilterTime` token" at the end for an `ARTIK051_PRAC_20K`
|
||||
that keeps the counter in its own resource, rejects both the token and a
|
||||
direct write, and has no local reset at all.
|
||||
|
||||
## What the reset actually is
|
||||
|
||||
A **command**, not a value write. Samsung's cloud models it as capability
|
||||
@@ -92,3 +98,72 @@ on every unit on record).
|
||||
The entity key stays `filter_time` rather than `filter_time_elapsed`:
|
||||
renaming it would change every existing unit's `entity_id`/`unique_id` for a
|
||||
wording improvement only.
|
||||
|
||||
## Boards with no `FilterTime` token (`ARTIK051_PRAC_20K`)
|
||||
|
||||
Negative result, measured 2026-08-11 on integration v0.21.0 / HA 2026.8.1,
|
||||
against one head of a three-head multi-split (`OptionCode_35880`,
|
||||
`ExtendOptionCode_199181`). **There is no local reset on this board**, by
|
||||
either route. Reset appears to be panel-only.
|
||||
|
||||
This generation does not put the counter in `/mode/vs/0` at all. Its
|
||||
options blob carries no `FilterTime`, no `FilterAlarmTime` and no
|
||||
`FilterCleanAlarm`:
|
||||
|
||||
```json
|
||||
["Sleep_0", "ArtificialWorking_Off", "ComfortAICooling_Off",
|
||||
"AiTempChanged_Off", "AiTemp_240", "OutdoorTemp_77", "CoolCapa_25",
|
||||
"WarmCapa_32", "Light_Off", "Volume_100", "OptionCode_35880",
|
||||
"ExtendOptionCode_199181", "RacInfo_None", "UpdateAllow_NotAllowed",
|
||||
"DurationOn_0", "WelcomeCoolingState_Off"]
|
||||
```
|
||||
|
||||
The counter lives in its own resource instead, as a **percentage** of a
|
||||
500-hour interval rather than tenths of an hour —
|
||||
`/filter/airdustfilter/vs/0`:
|
||||
|
||||
```json
|
||||
{
|
||||
"x.com.samsung.da.filterUsage": "96",
|
||||
"x.com.samsung.da.filterUsageResolution": "1",
|
||||
"x.com.samsung.da.filterDesiredUsage": "500",
|
||||
"x.com.samsung.da.filterStatus": "normal",
|
||||
"x.com.samsung.da.filterCapacity": "500",
|
||||
"x.com.samsung.da.filterCapacityUnit": "Hour",
|
||||
"x.com.samsung.da.filterResetType": ["replaceable", "washable"]
|
||||
}
|
||||
```
|
||||
|
||||
Three attempts, all against a live unit deliberately put in `fan_only`
|
||||
first — writes to a powered-off head on this board are dropped silently
|
||||
with no error, which would otherwise be indistinguishable from a rejected
|
||||
write:
|
||||
|
||||
| Target | Payload | Result |
|
||||
|---|---|---|
|
||||
| `/mode/vs/0` | `{"x.com.samsung.da.options": ["FilterCleanAlarm_Clear"]}` | 4.00, options blob byte-identical |
|
||||
| `/filter/airdustfilter/vs/0` | `{"x.com.samsung.da.filterUsage": "0"}` | 4.00 |
|
||||
| `/filter/airdustfilter/vs/0` | `{"x.com.samsung.da.filterUsage": 0}` (integer) | 5.00 |
|
||||
|
||||
`filterUsage` stayed at `96` throughout, verified by a live re-read after
|
||||
each write rather than by the integration's optimistic state.
|
||||
|
||||
The last two rows are the informative pair. They differ only in JSON type
|
||||
and return *different* codes, which rules out both boring explanations: an
|
||||
unresolved href or an unrecognised field name would fail identically. The
|
||||
board parses the field, faults on the wrong type, and still refuses the
|
||||
value when typed as the string its own rep uses. The resource is
|
||||
**read-only**, not mis-addressed.
|
||||
|
||||
One trap worth stating plainly: `filterResetType:
|
||||
["replaceable","washable"]` describes what the filter *is*, not a reset
|
||||
command that exists. It reads like a hint that a reset write is available
|
||||
somewhere. It is not.
|
||||
|
||||
Since the integration cannot perform the reset here, it can still observe
|
||||
it. The counter only climbs in normal use, so a downward crossing is
|
||||
unambiguous: a `numeric_state` trigger with `below: 10` on
|
||||
`sensor.<name>_filter_usage`, stamping an `input_datetime`, keeps an
|
||||
honest "last cleaned" date without pretending a reset entity exists. The
|
||||
blind spot is a reset performed while HA is down or the entry is
|
||||
unloaded — no state transition, so that stamp has to be set by hand.
|
||||
|
||||
Reference in New Issue
Block a user