Support the HUB Navizone gateway, and only wire climate features the device reports - #160
Support the HUB Navizone gateway, and only wire climate features the device reports#160mathieuletyrant wants to merge 7 commits into
Conversation
My installation exposes a device with modelId 1758 that is missing from model.py, so it falls through to the else branch and shows up as "Unknown product (1758)" in the device panel. setupviewv2 reports it with longName "HUB Navizone", modelFamily "Air_Conditioning". It is the gateway for the air conditioners, which on my setup are modelId 557-559 -- the same range the 556 Naviclim hub drives, so the two look like sibling gateway generations. Display only: CozytouchDeviceType.HUB is set but never read, since capability.py only branches on GAZ_BOILER, TOWEL_RACK, AC and HEAT_PUMP. Entities for the device were already being created correctly. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
18aff8b to
7acc0ed
Compare
|
Correction after dumping the raw
The dump also settles what sits behind it: the three AC units are modelId 557, 558 and 559, with Worth noting for anyone reading the table later: since the AC modelId does not change across hub generations, it cannot be used on its own to infer what a unit supports. I hit that concretely — see the separate report I am filing about |
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
fanModes, swingModes and quietModeAvailable are declared per model, and capability.py turned them into capability ids 100801-100804 unconditionally. climate.py then enables FAN_MODE and SWING_MODE purely on the presence of those keys, so the controls appeared whether or not the hardware backed them. Same for the AC presets, wired to 100505-100507 with no check. The model id cannot answer this on its own. On my setup a 1758 gateway drives modelId 557-559 units -- the same range the 556 Naviclim hub drives -- and those units report none of 100801, 100802, 100803, 100804, 100505 or 100506. Only 100507 (eco) exists. So the same model id spans hardware with different feature sets. The symptom was silent rather than a crash: get_capability_value falls back to "0" for a capability the device does not have, so the fan and swing selectors showed a fixed bogus value and writes went to an id the device ignores. get_capability_infos now takes the set of capability ids the device reports and only wires each optional feature when it is backed. Devices that do report them are unaffected. The gating in climate.py already keyed on these keys being present, so it needed no change. Also drops the unused Hub.get_capability_infos, which passed a modelId int where get_capability_infos expects a modelInfos dict and would have raised on any call. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Cross-referencing: this covers two open reports of the same device.
Worth noting on naming, since the two issues call it Shogun and this PR names it The 1734 half of #143 is already mapped on |
…temperature The 557-561 and 1734 branch set currentTemperatureAvailable = False, so currentValueCapabilityId was never wired and those climate entities had no ambient reading at all -- only a setpoint. Capability 117 is mapped as its own sensor either way, so the temperature was visible in HA while the climate entity itself reported nothing, leaving thermostat cards, current_temperature consumers and Matter bridges without it. My units do report 117, with a distinct value per room, so the flag was wrong for this hardware. Flipping it for the whole range would repeat the mistake in the other direction: get_capability_value falls back to "0" for a capability the device lacks, so a unit in that range without 117 would show a confident 0 degrees, which is worse than showing nothing. So the model flag stays as an explicit opt-out, but the device now has the final say -- the same rule this branch already applies to the fan, swing and preset ids. The AC branch no longer forces the flag off, and units that do not report 117 simply get no current temperature. Applied to the heat pump z1/z2 overrides too, for 117 and 118, so every path that wires a current temperature checks the device first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Added a fourth commit extending the same rule to the current temperature, which also gives an answer to #138. The 557-561 / 1734 branch sets My three units do report 117, with a distinct value per room (24.14 / 24.95 / 24.83), so the flag is wrong for this hardware — same conclusion #138 reaches. Where I would differ from #138 is the remedy. Flipping the flag to So the model flag stays as an explicit opt-out and the device gets the final say, exactly as this PR already does for the fan, swing and preset ids: if (
modelInfos.get("currentTemperatureAvailable", True)
and 117 in availableCapabilityIds
):
capability["currentValueCapabilityId"] = 117Replayed both ways: Applied to the heat pump z1/z2 overrides too (117 and 118), so every path that wires a current temperature checks the device first. Credit to @rafal83 for spotting the underlying problem in #138 — this is the same fix with a guard against the range being wrong for someone else.
|
On a zoned install only the master room picks the operating mode. A slave accepts a mode write and stores it, but keeps running whatever the master imposes, so capability 7 is a request rather than a state. Capability 181 carries the effective mode. The integration only ever read 7, so HA showed the request as if it were reality: setting a slave to heat while the system cooled left the card claiming heat with nothing to contradict it. Reproduced on my install -- capability 7 = 4 on a slave, 181 = 3, and the room blowing cold. The official app has the same blind spot, colouring the room warm. 181 uses the same value scale as 7, so it is read through the model's HVACModes and translated to HVACAction. That sidesteps having to identify the master at all: every room reports what it is doing, so no guessing which one commands, which is what blocked this until now. HVACMode.AUTO is deliberately left unmapped -- a system in auto is really heating, cooling or idle, and there is no HVACAction for it, so returning nothing beats guessing. Gated on 181 being reported, like the other optional features, so devices that do not expose it are unaffected. Only 0 and 3 were observed on my hardware; 4, 7 and 8 are extrapolated from the capability 7 scale. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Fifth commit, and this one explains a user-visible confusion I could not account for before. On a zoned install only the master room picks the operating mode. A slave accepts a mode write and stores it, but keeps running whatever the master imposes. So capability 7 is a request, not a state — and the integration only ever read 7. Reproduced on my install. I set a slave room to heat from HA: The write was not rejected — no Capability 181 carries the effective mode, on the same value scale as 7, so it is read through the model's What makes this workable is that it removes the need to identify the master. I had parked this problem precisely because nothing in the payload reliably designates the master room, and guessing would have broken installs whose master is not the first unit. With 181 the question disappears — every room reports what it is doing. Result on the same slave: Two caveats stated plainly:
Gated on 181 being reported, like everything else here, so devices that do not expose it are unaffected. |
|
The capability list in #86 confirms what capability 181 is:
The caveat about values 4, 7 and 8 being extrapolated from the capability 7 scale still stands — the list gives names, not value tables. It also settles a red herring I chased on the way. |
Capability 172 has been mapped for every device since the gas boiler days, so an air conditioner gets a writable "Away Mode Temperature" number. The hardware does not honour it: a Navizone setup captured mid-absence has 172 sitting at the value Home Assistant wrote days earlier, while the weekly program keeps driving the setpoints hour by hour -- 177 moved to 26 at 03:00 against the cooling slot [180, 26], and 40 moved to 21 at 07:00 against the heating slot [420, 21], both well inside the absence window. Absence on this family stops the units until the return date, which is why the Cozytouch app offers a return date and no temperature at all. Gate it behind awayModeTemperatureAvailable and clear the flag on the air conditioners and on the two hubs that drive them, leaving the heating products untouched. Map 100261 while here, the per-room mirror of the hub's away mode flag. Its neighbour 100260 carries the absence window per room and stays unmapped: the window is written for the whole setup, not room by room. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The room units behind a Naviclim or Navizone hub report capability 100507, so they get an eco_mode switch and PRESET_ECO on the climate. The Cozytouch app offers no eco mode for them anywhere, neither on the home screen nor in a room's own screen, and 100507 has sat at 0 since provisioning on the setup we have a capture of. Gate both entry points behind ecoModeAvailable, scoped to 557-561: those are the units a hub drives, which is what the report covers. 1734 shares the AC branch but is a separate product with nothing reported either way, so it keeps its eco mode. With activity and boost already absent from these units, dropping eco leaves the climate without PRESET_NONE, so its presets become basic, prog and override -- which is what actually drives them. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>


Adds support for my
HUB Navizoneair conditioning gateway, and fixes a related issue it exposed.1.
modelId1758 is missing from the model tableIt falls through to the
elsebranch and shows up as "Unknown product (1758)" in the device panel.setupviewv2reports it as:(
name/customNamereadHUB SHOGUN - PRT pileon my install, but that is the user-editable label from the Cozytouch app, not the product designation.)It is the gateway for the air conditioners, which on my setup are modelId 557, 558 and 559 with
masterDeviceIdpointing at it — the same 557-561 range the 556Naviclim Hubdrives. So 556 and 1758 look like two gateway generations for the same units.Added to the tested devices list in the README too.
2. Optional climate features were wired regardless of hardware support
That last point has a consequence.
fanModes,swingModesandquietModeAvailableare declared per model, andcapability.pyturned them into capability ids 100801-100804 unconditionally.climate.pythen enablesFAN_MODEandSWING_MODEpurely on those keys being present, so the controls appeared whether or not the hardware backed them. Same for the AC presets, wired to 100505-100507 with no check.My 557-559 units report none of 100801, 100802, 100803, 100804, 100505 or 100506. Only 100507 (eco) exists. So the model id alone cannot answer what a unit supports — the same id spans hardware with different feature sets.
The failure was silent rather than a crash:
get_capability_valuefalls back to"0"for a capability the device does not have, so the fan and swing selectors showed a fixed bogus value and writes went to an id the device ignores.get_capability_infosnow takes the set of capability ids the device actually reports and only wires each optional feature when it is backed. Replaying my real capability list through it:Right-hand column is the regression check: a device that does report them keeps everything. The gating in
climate.pyalready keyed on these keys being present, so it needed no change.Also drops the unused
Hub.get_capability_infos, which passed amodelIdint whereget_capability_infosexpects amodelInfosdict and would have raised on any call. Happy to keep it if you would rather.Note this touches
hub.py, as does #161 — different functions, and they cherry-picked onto each other cleanly, but flagging it.🤖 Generated with Claude Code