Fix POINTTAPI services and beta-2 thermostat regressions - #25
Conversation
- Bind dynamic thermostat-valve child lock switches to per-device info instead of gateway fallback - Support thermostat-style device paths (deviceN/thermostat/*) alongside etrv paths for valve fields - Enforce strict child-lock switch creation on concrete /childLock/enabled leaves only - Add/update regression tests for enabled-leaf discovery and thermostat path variants
…val (63b80d9): unittests/test_pointtapi_setup.py:62 and :95 still define async_load_persistent_cache on the fake coordinators — the real method is gone, so the stubs are dead. Delete both when next in that file." On issue CaseyRo#19
- Update childLock/enabled test payloads to stringValue with string true/false and metadata fields\n- Add explicit childLock false->off mapping assertion\n- Keep strict enabled-leaf discovery behavior for child lock switches
|
@CaseyRo ... i'm waaaay too enthusiastic ... sorry :D 🙈 |
|
This PR fixes the original POINTTAPI service bug from issue #24: generic Bosch calls were still hitting the XMPP/raw gateway path, which breaks cloud devices. The fix routes |
|
A second regression was introduced in the beta-2 cleanup: thermostat child-lock and offset paths could be attached to a fake |
|
This PR fixes the original POINTTAPI service bug from issue #24 and the beta-2 regressions introduced during the cleanup pass.
The patch keeps the old service names working as deprecated aliases, adds the clearer |
|
@CaseyRo I found and fixed one more issue related to the beta-2 child-lock regression, and pushed the fix in commit The previous fix correctly identified the This update makes the coordinator follow the additional reference level required by the real device structure:
I also added a regression test based on that structure. The focused coordinator and entity tests now pass (152 tests). Sorry for multiplying the fixes, but I keep finding these beta-2 regressions while testing with a real multi-zone setup. I wanted to report and correct them rather than leave the PR with partially working child-lock entities. |
|
@CaseyRo I found one more cleanup issue related to the beta-2 thermostat-valve regression and pushed the fix in commit Home Assistant keeps devices in its device registry even after the integration stops creating them. As a result, the old erroneous The integration now performs a targeted cleanup after the first successful POINTTAPI refresh. It checks the currently reported I also added a regression test for this exact case. The focused setup and cleanup tests pass, and Ruff reports no issues for the changed files. |
CaseyRo
left a comment
There was a problem hiding this comment.
@jfhautenauven Verified on my side: on current master, ruff clean, 557 green, CI green. The #24 fix is exactly right — the protocol branch in custom_get / custom_put, and thermostat_refresh becoming a coordinator refresh on cloud entries closes the question I'd left open. The dedupe and the thermostat-vs-thermostat_valve routing fix are the two things beta.2 actually needs, and the extra reference level explains the unavailable switch cleanly. Nice detective work for one evening. 🙏
One change request, one nudge, then I merge and tag beta.3.
The change: _remove_stale_pointtapi_valve_devices → async_remove_config_entry_device
The 45 lines in __init__.py exist because HA shows no delete button on our devices — we never implemented async_remove_config_entry_device. That hook is the idiomatic answer and it's a few lines:
async def async_remove_config_entry_device(hass, entry, device_entry) -> bool:
"""Allow deleting devices the gateway no longer reports."""
... # True when none of device_entry.identifiers is still backed by coordinator.dataWith it, the fake "Thermostat valve #1" gets a Delete button in the device page, and so does every other stale device we've ever left behind (the orphaned firmware-update-state sensor from 1.2.0 included). Without it, we run registry deletions on every boot, forever, for a device that existed for about three hours in a pre-release — and any future mismatch between /devices/deviceN/type and our identifiers deletes real entities. Registry writes on the startup path are the one place I'd rather be boring.
So: drop _remove_stale_pointtapi_valve_devices and its test, add the hook (a test that it returns True for a _trv_ identifier absent from data and False for a present one is plenty), and the release note tells beta.2 users to delete the ghost device once.
The nudge: you don't need my tag to test
"Change → wait for beta → test → repeat" is costing you more than me. Your HA can run your branch directly: copy custom_components/bosch/ from your checkout over the installed folder and restart, or add jfhautenauven/ha_bosch as a second HACS custom repository and pick the branch. Then the child-lock write — which 403'd through HA on beta.1 and is still only proven via your Jeedom tooling — gets a real end-to-end check before it ships a third time, and I tag when you say "confirmed" instead of the other way round.
Everything else stays as is, refresh_gateway alias included. 🚀
|
Thanks @CaseyRo, I’ve addressed the requested change in commit I removed Regarding the nudge: I’ll experiment with that next month, running my branch directly in my Home Assistant setup and do a real end-to-end check. I’m still discovering how to develop properly for Home Assistant, so this is a useful next step for me. I’ll report back once I’ve tested it. For the time being, given the time I got left in my hands, well, i'll try it later :) Child lock is not a feature that is specially demanded anyways, so it's not vital it works immediately. In this beta 3 I will get back the custom get and put, and those will help me a lot to explore the missings paths in my dumps :) |
|
Quick follow-up: I was able to test the child-lock write on my local Home Assistant setup, and it works perfectly. The child lock is confirmed working end to end. I’m still having difficulties with the stale devices, though: they are not being removed as expected. I’m continuing to investigate that part and will report back once I understand what is blocking it. |
|
One more small addition is now pushed in commit POINTTAPI devices created by the integration now expose The focused tests pass ( |
|
Another small metadata update is now pushed in commit The POINTTAPI device information now shows:
I also added regression assertions for the model values. The focused tests pass and Ruff is clean. |
CaseyRo
left a comment
There was a problem hiding this comment.
@jfhautenauven 72592b9 is exactly the shape I was hoping for — the hook is thirty lines, answers one question, and never touches the registry on its own. And the child-lock write confirmed end-to-end from your own HA within the hour: that's the whole argument for running the branch locally, made in one afternoon. 🎉 Head verified here: on current master, ruff clean, 561 green, CI green.
Two small things before I tag beta.3, both quick:
1. model="ETRV RT10-RF" on every valve
That's your hardware's name applied to everyone's. Your own fixtures carry protocol: homematicip, and @LukyHurdy1's 12-zone install confirmed homematicip on real valves on #16 — those aren't RT10-RF. If your dump has a real product/model field under /devices/deviceN (the way /gateway/productId gave you the CT200/TC100 map), read it from there. If it doesn't, drop the model= line: HA showing nothing beats HA showing a wrong part number on someone else's device. One line either way.
Same thought, lower priority: the seven manufacturer="Bosch" literals could reuse gateway_manufacturer — a Buderus TC100 owner otherwise gets a Buderus gateway with Bosch zones.
2. The stale device that "won't remove"
It isn't broken — it's just not automatic anymore. async_remove_config_entry_device doesn't delete anything by itself; it makes the Delete action appear in the device page's ⋮ menu, and HA only picks up the new hook after a restart with this __init__.py loaded. Restart, open the ghost "Thermostat valve #1", ⋮ → Delete. If the button is there and refuses, then the ghost's id is still in /devices/list as thermostat_valve and the hook is correctly saying "still present" — post the row and we'll look.
Push the model fix (or "no such field, dropped it") and I merge and tag 1.5.0-beta.3 — beta.2 still has the duplicate-unique_id errors, so this one doesn't wait for the weekly slot. 🚀
|
New feature added: the gateway For example, my thermostat is not a Bosch CT200. It is a Buderus TC100.2. They are identical or nearly identical functionally, but the hardware design differs slightly. The integration now reports the correct values based on the gateway product ID instead of always showing the generic Bosch/EasyControl fallback. |
|
I confirm that I tested all the new features with my own installation, and everything is working as expected and according to what I wanted. I’m still looking into adding a few extra goodies, but after that we should be ready to move on to beta.3. |
|
After reviewing the data available in my installation dump and querying the BOSCH servers directly, I don't see any remaining information from my setup that would require adding new data sources to the integration. ✅ From my side, the current coverage looks complete for this installation. 🚀 GO for Beta 3! 🎉 I’m going to close this work for the |
…ssions, device removal hook PR #25 (jfhautenauven). Also drops the hardcoded thermostat-valve model "ETRV RT10-RF": the API exposes no product id for radiator thermostats and real installs run homematicip valves, so no model beats a wrong one.
|
Merged and out as v1.5.0-beta.3 — 563 green on master. 🚀 One thing I did on master rather than bounce it back to you, since you'd already called GO: I dropped And on #22: thanks for digging through the old dumps — "no multi-circuit setup ever seen, live and let live" is the answer I needed. The installation device stays singular. 🙏 |
|
Thanks for the clarification and for the change. 👍 Thermostatic valve compatibilityAs far as I know, the only thermostatic valves that were ever officially compatible with EasyControl were the Bosch-branded RT10-RF valves. Their development was outsourced to Homematic IP, which likely explains the related naming and protocol details. Bosch internal release notes announced direct support for non-Bosch-branded Homematic EQ3 valves with firmware 5.4.0. However, I have never found public documentation that explicitly mentioned this support. The Bosch ETRV v2 valves were never compatible with EasyControl; they are supported only by the newer HomeSmart controller. That said, I agree with the modification: I may have assumed too quickly that everyone uses RT10-RF valves, while POINTTAPI does not actually expose enough data to identify the hardware reliably. Keeping the routing conservative is therefore the right call. ✅ Beta feedbackI am currently testing version 1.5.0 beta 3. So far, I have not observed any bugs or defects in normal use. 🎉 Release reminderWhen we publish the stable release, please remember to update the release notes and the repository README as well. 📝 |
…fast/slow polling Promotes the 1.5.0 beta line to stable. @jfhautenauven ran beta.3 on his 12-valve production install and reported no defects in normal use (#25). README refreshed for the stable cut, as he asked on #25: - entity matrix relabelled v1.5.0; adds the zone average temperature sensor that shipped in #20 but never reached the table - section headings translated to English (Chaudiere, Vanne thermostatique, Efficacite energetique, Eau chaude sanitaire, Solaire) - "Under the hood" polling bullet now describes the real fast/slow cadence instead of claiming a flat 60 seconds - new Services section documenting bosch.refresh_gateway, the deprecated update_thermostat alias, and debug_scan being XMPP-only 563 tests, ruff clean.
|
v1.5.0 is out as stable. 🎉 https://github.com/CaseyRo/ha_bosch/releases/tag/v1.5.0 Your beta.3 report was the last thing it was waiting on — thank you for running it in production the whole way through, and for confirming the child-lock write on real hardware rather than taking my word for the code path. Thanks also for the valve-compatibility history. That's the clearest account of it I've seen anywhere, so I put it in the release notes under "A note on valve models" — RT10-RF as the only officially compatible one, the Homematic IP outsourcing behind the naming, EQ3 from firmware 5.4.0 per internal notes, ETRV v2 never on EasyControl. If someone later asks why their valve device has no model, the answer is now findable instead of living in a merged PR thread. Release notes and README both updated, as you asked. The README needed more than a version bump:
One thing I found and did not fix, so it doesn't get lost: Next up is #22 for 1.6.0 whenever you have time. No rush, and enjoy having your month back. 🙂 |
Summary
This PR addresses the original bug from #24 and the regressions introduced in the beta-2 cleanup for POINTTAPI devices.
send_custom_get and send_custom_put_* were still routing through the legacy XMPP/raw gateway methods even when the entry was using the POINTTAPI cloud protocol. That made cloud-based calls fail at runtime.
This change:
routes POINTTAPI custom get/put calls through the cloud client
keeps the local XMPP/HTTP path unchanged
adds bosch.refresh_gateway as the clearer service name
preserves bosch.update_thermostat as a deprecated compatibility alias
2) Fix the beta-2 regressions
The beta-2 valve/device cleanup introduced a second issue: thermostat child-lock and related paths could be assigned to a fake thermostat_valve device even when the underlying device type was just thermostat.
This caused orphan devices such as a dedicated Thermostat valve entity group with only the child-lock switch, and it also increased the chance of duplicate or mismatched registrations.
This change:
only creates dedicated thermostat-valve devices for actual thermostat_valve rows
falls back to the generic device routing for thermostat-only nodes
keeps the child-lock/offset entities attached to the correct gateway/device tree
Testing
Added/updated regression tests for POINTTAPI service routing and thermostat valve discovery
Verified the targeted suite passes
Verified the repo lint/test checks remain green for the relevant scope
Fixes #24