Per mbillow's review on PR #129 (CHANGES_REQUESTED). Items 1-7 + smaller.
1. INFO: expose each /information/vs/0 version item per (type, ordinal) instead
of collapsing to a single first-Firmware value. Boards carry 1-3 Firmware
items (separate MCUs) plus an Outdoor unit and (window AC) a Touch IC item;
each is a distinct version string. _info_version(items, type_, ordinal)
+ _has_info_version exists_fn gate, so an item with no number (tp2x_rac_20k's
second Firmware) suppresses the entity rather than binding unknown.
2. air_filter_threshold is locally writable, not cloud-only -- confirmed live
on ARTIK051_PRAC: POST filterDesiredUsage=700 to /filter/airdustfilter/vs/0
-> 2.04, read-back 700, persists; restored to 500. Converted from a
read-only sensor to a SelectDesc keyed to the device's
supportedFilterDesiredUsage enum (options_field), with a write_fn that
POSTs the scalar field. Only binds where the enum is advertised; boards
without it leave this writable field unexposed rather than guess the valid
set (don't-guess).
3. air_filter_usage_hours uses unit_fn reading filterCapacityUnit ('Hour'->'h')
instead of a hardcoded unit, so a board advertising a different unit doesn't
mislabel a duration statistic.
4. air_filter_usage_hours state_class is total_increasing, not measurement --
filterUsage is a lifetime hour counter that resets on filter replacement.
5. INFO and air_filter_threshold now carry exists_fn (AIR_QUALITY already did),
so they don't bind a permanently-unknown entity when their item/field is
absent. Also fixes the caww_tp2 golden nuance (filterDesiredUsage absent
-> no threshold key, matching what HA would actually create).
6. AIR_QUALITY: CleanLevel is corroborated as numeric by a top-level
x.com.samsung.da.cleanLevel scalar (tp1x_da_ac_rac_01011 reports both as
'1'), so clean_level is now an int measurement; odor/dust/fine_dust stay
string diagnostics. Reinstated the 2-element-array ambiguity note (Dust/
FineDust/SuperFineDust report ['0','0']; v[1] meaning unconfirmed, v[0]
taken as the reading). SuperFineDust is now modeled for consistency with
Dust/FineDust (same shape), rather than skipped without reason.
7. _beep_write restores the last non-Mute Volume level on 'On' instead of
forcing Volume_100, so an intermediate setting (e.g. Volume_50 set via
the cloud) survives an off/on cycle; falls back to 100 when no prior level.
Smaller: test_air_quality now asserts the tp1x_da_ac_rac_01011 clean_level==1
non-zero reading (the one value_fn-regression catch in the corpus); renamed
by_type's _AC_IGNORED -> _IGNORED_LESS_INFO to resolve the two-meaning
collision with the capabilities module's _AC_IGNORED (href strings); golden
regenerated for the 8 AC fixtures + dehumidifier.
612 tests pass.