What's Changed
Added
-
A guard keeps the prek hook revisions and the pinned tool versions from
drifting apart..pre-commit-config.yamlpins five tools inrev:, and
requirements_test_pre_commit.txtpins the very same five for the test
environment. Nothing linked the two files, so they were kept in sync by hand —
and at the previous commit they were not:codespellran atv2.4.2from the
hook while the requirements installed2.4.3,yamllintatv1.37.1against
1.38.0,python-typing-updateatv0.7.3againstv0.8.1. A hook that
lints with a different release than CI installs reports different findings in
the two places, which is exactly the kind of difference nobody looks for.script/check_pre_commit_pins.pycloses that gap as thecheck-pre-commit-pins
hook. The link it checks is declared in the two files, never inferred: no
rule mapscharliermarsh/ruff-pre-committo the packageruff, so each pin
now names the hook repo it mirrors in a trailing# pre-commit: <repo-url>
comment (or# pre-commit: localfor a tool behind arepo: localhook), and
each remote repo that deliberately carries no pin is marked# no-pin: <reason>
on the line above its- repo:entry. Guessing the mapping from names would
have produced a check that looks right and silently mismatches the day a repo
and its package stop sharing a name.That marker sits on its own line for a reason worth recording: prettier
rewrites a YAML trailing comment down to a single leading space, and yamllint
then rejects it for having fewer than two — no trailing form passes both hooks.Beyond version drift the guard also catches a hook repo added without a
matching pin, a pin naming a repo the config no longer has, a pin with no
mapping comment at all, and a repo that is both mapped and marked# no-pin:.
Twenty tests cover the parsers and each failure class, including a check that
the repository's own two files agree. -
The bulk device-data fetch reports how many values it returned.
get_all_device_datalogged only the name of the ReGa script it invoked, never
anything about the response. That made the single most useful fact about a start
invisible from the outside: whether the fetch returned values at all. When a data
point stays unset after a restart, the size of that result is what separates "the
backend holds no timestamped value for it" from "the value arrived and was not
applied" — two causes with opposite fixes, previously indistinguishable without a
session recording. ADEBUGline now states the count per interface, and it is
emitted outside the result branch so an empty result — the interesting case — is
logged too. The count is deliberately all it carries: it answers the question,
while the keys themselves would add device addresses to the log for no further
diagnostic value.
Fixed
-
HmIP-HEATINGgroups no longer hang at the restored Home Assistant state when
the operating mode stays untouched (#3376).CustomDpIpThermostatgated its
validity onSET_POINT_MODE, which the CCU reports only when the operating mode
actually changes — unlikeACTUAL_TEMPERATUREandSET_POINT_TEMPERATURE, which
keep arriving.Heating groups on the
VirtualDevicesinterface have no second source to fall back
on. After a CCU restart the mode data point carries aTimestamp()but no
LastTimestamp(), so the ReGa bulk fetch skips it (that gate is deliberate, #3228),
andVirtualDeviceshas no per-parametergetValuefallback either — for a virtual
groupgetValuecan only return the CCU-internal placeholder. A group whose mode had
not changed since the restart therefore stayed atvalue_state=restoredwith frozen
current_temperature/target_temperaturefor as long as the mode stayed put, while
the siblingsensor.*entities kept updating from the very same events.Validity now follows
TEMPERATUREandSETPOINT; untilSET_POINT_MODEarrives,
modereports its existingAUTOfallback. Same failure class and same remedy as
the classic RF thermostats in2026.8.5and the earlier heating-group fixes (#3255,
#3279). A regression test covers a group that reports temperature and setpoint but
neverSET_POINT_MODE, and the validity contract test is updated.This does not cover a group whose
ACTUAL_TEMPERATUREis missing from the bulk
result as well — such a group has no value at all and still waits for the first
event. -
A system variable whose declared type does not match its value is kept as text
instead of being dropped (#3377).SysVar.getAllreports a type per variable,
and_build_sysvar_recordtrusted it:LISTandINTEGERwent throughint(),
and aNUMBERwithout a decimal point was treated asINTEGERfirst.The reported variable is a value list holding a single entry — the way to park a
string on a CCU that would not take it as a plain string variable. For that
constellation the backend returns the entry itself as the value, not its index,
soint()raised, the record was discarded, and no data point ever appeared.
TheERRORwas logged on every scan: 4075 times in the submitted log, at a 60 s
scan interval, for one variable namedV.Pushover.UserKey. Disabling it in the
integration does not help —enabled_defaultis resolved before the value is
parsed.The record now survives: on a conversion failure the variable falls back to
STRING, keeps the raw value, and dropsminValue/maxValue. It also drops
extended_sysvar, so a declared type we could not verify never yields a writable
data point — a select whose only option is the payload, or a string written back
to a variable the backend holds as a float, would both be wrong. The log moves to
WARNING, is emitted once per variable id per client, and names the type the
backend declared.
Changed
- Routine tooling bumps:
prek0.5.2,pylint4.0.8,uv0.12.9, and
codespell2.4.3,yamllint1.38.0 andpython-typing-update0.8.1 in both
the pinned requirements and the pre-commit revisions.
Full Changelog: 2026.8.8...2026.9.1