Skip to content

feat: enrich Zigbee sensors with room data from RoomControl#743

Merged
CFenner merged 9 commits intoopenviess:masterfrom
lackas:feature/room-sensor-enrichment
Apr 28, 2026
Merged

feat: enrich Zigbee sensors with room data from RoomControl#743
CFenner merged 9 commits intoopenviess:masterfrom
lackas:feature/room-sensor-enrichment

Conversation

@lackas
Copy link
Copy Markdown
Contributor

@lackas lackas commented Apr 16, 2026

Background

Viessmann has removed device.sensors.temperature and device.sensors.humidity from physical Zigbee room sensors (E3_RoomSensor). Comparing current API responses (Apr 2026) with #557 test data (May 2025), the sensors went from 12 features down to 6 — only battery, zigbee signal, and identification remain.

The temperature and humidity data still exists, but only on the RoomControl virtual device under rooms.N.sensors.*. This means RoomSensor.getTemperature() and getHumidity() silently stopped working for affected installations.

Design

Rather than mapping Viessmann's room abstraction into a new device hierarchy (as #557 proposed), this PR enriches the existing physical Zigbee devices with data from RoomControl — following @CFenner's preferred approach (#557 (comment)).

The cross-referencing works because RoomControl lists "actors" per room — these are the Zigbee device IDs of the physical sensors and floor heating channels in that room. We reverse this mapping: given a Zigbee sensor's device ID, find which room it belongs to, then read that room's sensor data.

How it works

  1. roomControl added to device type filter — PyViCare now discovers RoomControl devices
  2. After device discovery, __enrichZigbeeDevices() builds an actor→room mapping from each RoomControl
  3. For each Zigbee device whose ID appears as an actor, the RoomControl reference and room ID are stored on the PyViCareDeviceConfig
  4. When asRoomSensor() creates a RoomSensor, the enrichment is applied
  5. RoomSensor.getTemperature() transparently reads from RoomControl when enriched, falls back to device-level data for installations without RoomControl (older API or different device models)

What's exposed

Sensors: temperature, humidity, CO2, condensation risk
Operating state: level, demand, reason
Heating programs: normal/reduced/comfort target temperatures with setTemperature commands
Quick mode: manual till next schedule (activate/deactivate/set temperature)
Schedule: read (per room)
Room metadata: name, type

What's NOT in this PR

  • No new HA integration entities — that's a separate HA Core PR once this lands
  • No changes to FloorHeatingChannel enrichment — floor heating channels also appear as actors but don't need sensor data. Could be added later for operating state.
  • Deprecated features (window.openState, operating.programs.active) are excluded

Test data

Depends on #742 for the E3_RoomControl_One_525 test data (contributed by blob810, sanitized).

Breaking changes

None. Existing behavior is preserved — enrichment only activates when a RoomControl device exists. Installations without RoomControl are unaffected.

@lackas
Copy link
Copy Markdown
Contributor Author

lackas commented Apr 17, 2026

HA integration steps

Once this lands and is released, the HA vicare integration needs:

  1. Bump PyViCare version
  2. Filter out roomControl devices from entity creation — RoomControl is an implementation detail for enrichment, users shouldn't see it as an HA device. One-line check: skip device_config.getDeviceType() == "roomControl".

That's enough to restore room_temperature and room_humidity sensors — the existing GLOBAL_SENSORS descriptions already call getTemperature() / getHumidity(), which now work again via enrichment.

For the new features (heating targets, condensation risk, schedules, quick modes), we'd add entity descriptions in a follow-up HA PR.

Impact and risk

For installations with RoomControl + Zigbee sensors (blob810's case): Temperature and humidity are restored on the physical sensor devices. Heating targets, condensation risk, and schedules become available. Confirmed working on a 10-room installation.

For installations without RoomControl (our test case): The enrichment finds RoomControl devices with 0 rooms, builds an empty actor map, and does nothing. No extra API calls, no side effects. Verified on a CU401B_G + VitoCharge setup with two RoomControl devices present but no Zigbee sensors.

For installations without RoomControl at all: The enrichment loop simply finds no roomControl devices and skips entirely. Zero impact.

isSupported handling

Features that only work with enrichment (CO2, room name, heating targets, etc.) now properly integrate with PyViCare's @handleNotSupported decorator. Without enrichment, _getRoomControl() raises KeyError, which the decorator converts to PyViCareNotSupportedFeatureError. This means HA's is_supported() check correctly reports these features as unsupported — no entity is created, no silent None values. Tested with isSupported() assertions and exception checks.

Comment thread PyViCare/PyViCareRoomSensor.py Outdated
Comment on lines +9 to +10
self._room_control = None
self._room_id = None
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This can move to class level, no?

Comment thread PyViCare/PyViCareRoomSensor.py Outdated
(self.asRadiatorActuator, r"E3_RadiatorActuator", ["type:radiator"]),
(self.asFloorHeating, r"Smart_zigbee_fht_main|E3_FloorHeatingCircuitDistributorBox", ["type:fhtMain"]),
(self.asFloorHeatingChannel, r"Smart_zigbee_fht_channel", ["type:fhtChannel"]),
(self.asRoomControl, r"E3_RoomControl|Smart_RoomControl", ["type:virtual;smartRoomControl"]),
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will this class only represent the virtual device that handles the room thermostat mapping or also in-room control real devices?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the virtual device (role type:virtual;smartRoomControl). Physical in-room controllers like Vitotrol 300E are separate zigbee devices with their own device type and class.

@lackas
Copy link
Copy Markdown
Contributor Author

lackas commented Apr 28, 2026

Addressed review comments:

Re: RoomControl scope question - it only represents the virtual device (role type:virtual;smartRoomControl). It holds the room-to-sensor mapping and room-level data (temperature, humidity, CO2, schedules). The physical in-room controllers (Vitotrol 300E etc.) are separate zigbee devices with their own device type.

@lackas lackas requested a review from CFenner April 28, 2026 07:15
Comment thread tests/test_TestForMissingProperties.py Outdated

# RoomControl - room sensor data, used by enrichment (#743)
'rooms',
'rooms.0',
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this limited to 10 rooms?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, it's not limited to 10 rooms. I just realized these ignore entries are actually unnecessary -- find_feature_in_code already replaces single digits with {.*?}, so rooms.5.sensors.temperature in test data matches f"rooms.{room_id}.sensors.temperature" in code. The test passes without them. I'll remove the entire block.

@lackas lackas force-pushed the feature/room-sensor-enrichment branch from c17da01 to 0d6735d Compare April 28, 2026 09:50
lackas and others added 9 commits April 28, 2026 13:11
Adds sanitized RoomControl device data with 10 rooms including
temperature, humidity, and actor mappings to Zigbee room sensors
and floor heating channels.

Data contributed by blob810 from a Vitocal 222-SI installation
with E3_RoomControl_One_525 (RoomControl-1).
Viessmann removed temperature and humidity data from physical Zigbee
room sensors and moved it to the RoomControl virtual device. This
restores the data on the physical sensors by cross-referencing
RoomControl actor mappings with Zigbee device IDs.

Enriched data includes:
- Temperature, humidity, CO2 sensors
- Condensation risk
- Operating state (level, demand, reason)
- Heating programs (normal/reduced/comfort) with set commands
- Quick mode (manual till next schedule) with activate/deactivate
- Schedule (read)
- Room name and type

Changes:
- Add RoomControl device class with full room API
- Add roomControl to device type filter
- Enrich RoomSensor after device discovery via actor cross-reference
- RoomSensor transparently reads from RoomControl when enriched,
  falls back to device-level data for older API versions
- Add auto-detect entries for E3_RoomControl and Smart_RoomControl
RoomControl: concrete return types with float/int/str/bool coercion
at the Any boundary (matching existing PyViCare style).

RoomSensor: _getRoomContext() returns (RoomControl, str) tuple,
eliminating str|None arg-type errors cleanly.
find_feature_in_code already replaces digits with wildcards,
so rooms.N features match rooms.{room_id} in code automatically.
@lackas lackas force-pushed the feature/room-sensor-enrichment branch from 0d6735d to 5ccddfd Compare April 28, 2026 11:14
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The room thermostat can be enhanced the same way no?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, any device that shows up as an actor in a RoomControl room could be enriched the same way. Right now we only do it for RoomSensor, but extending to RadiatorActuator or FloorHeating would be straightforward -- same setRoomControlEnrichment pattern. Happy to add that in a follow-up if there's demand.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, then let's go with this first.

@CFenner CFenner merged commit 953ba71 into openviess:master Apr 28, 2026
9 of 10 checks passed
CFenner added a commit that referenced this pull request May 8, 2026
The RoomControl-driven Zigbee enrichment introduced in #743 does not
work in practice: the rooms.{id}.actors mapping that drives
buildActorRoomMap() is not returned by the API for end users, so the
enrichment is silently no-op and the lib has no reliable path to
associate physical Zigbee devices with rooms.

Removes the enrichment plumbing and reverts RoomSensor to direct
sensor reads (device.sensors.temperature, device.sensors.humidity).
RoomControl itself stays for direct per-room access.

BREAKING CHANGE: RoomSensor no longer exposes hybrid getters that
required RoomControl context (getRoomName, getRoomType,
getCondensationRisk, getOperatingState*, getNormal/Reduced/Comfort
HeatingTemperature, getManualTillNextSchedule*, getSchedule).
Use the corresponding RoomControl methods with a room_id directly.

Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants