Skip to content

vNext: group VRF sub-units under a gateway device - #529

Merged
RobHofmann merged 2 commits into
5.0-devfrom
fix/vrf-controller-device
Sep 24, 2026
Merged

RobHofmann merged 2 commits into
5.0-devfrom
fix/vrf-controller-device

Conversation

@RobHofmann

@RobHofmann RobHofmann commented Sep 24, 2026 •

Copy link
Copy Markdown
Owner

Groups the indoor units of a local VRF gateway under a gateway device, as Pedro proposed on Discord.

1. Gateway device with Connected devices

Change. Every local gateway MAC (connection.local.mac_controller_local) with at least one sub-unit gets a controller device: identifier (gree_custom, "controller_<mac>"), model VRF gateway, translated name VRF gateway <last 5 of mac>, no entities. Each sub-unit gets via_device_id to it, so the gateway page shows the units under Connected devices. A gateway with one sub-unit gets one too.

Design points.

  • DeviceInfo does not create a missing via device: HA logs non existing via_device and drops the link. So the controllers are created in async_setup_entry before the platforms load.
  • The link is set with async_update_device(via_device_id=...) after the platforms load, not through DeviceInfo. HA 2026.3 (our minimum in hacs.json) only has via_device in DeviceInfo, and 2026.9 only has via_device_id. async_update_device has via_device_id in both.
  • Setup reconciles instead of deleting and recreating all controllers. A wanted controller keeps its device id, user name and area, so device based automations and dashboards keep working. Only controllers without sub-units are removed.
  • Grouping uses the saved mac_controller_local, not device.mac_address_controller. The runtime value follows the bound transport (for MQTT it is the first 12 chars of the cloud MAC), so the parent could flip after a fallback.
  • The controller has the gateway MAC as connections. Discovery never returns the gateway itself as a device, so no other device of this integration has that MAC.
  • Its sw_version and hw_version come from the first bound sub-unit, because the firmware belongs to the WiFi module of the gateway. Without a bound sub-unit the registry keeps the last known values. This assumes all sub-units of a gateway report the same firmware; a full status of a real sub-unit would confirm it.
  • One DeviceInfo for every unit. The VRF branch in entity.py only left out hw_version and model_id, and the link no longer needs it. Sub-units now show both.

2. Delete and diagnostics

  • Deleting the controller raises HomeAssistantError with remove_vrf_controller: "This is a VRF controller. Delete its sub-units first, and the controller is deleted automatically." Returning False would only show HA's generic "rejected by integration".
  • Deleting the last sub-unit removes the controller in the same call. The entry has no update listener, so otherwise it would stay until the next start.
  • Controller diagnostics return controller_mac and sub_units: the diagnostics of each sub-unit, "" for one that is not bound.

3. Cloud VRF: data first

Cloud-only VRF units get no controller yet, because we do not know what pmac holds. get_all_devices() now logs Raw cloud device list at debug level, before the duplicate filter, with key redacted. docs/troubleshooting.md asks cloud VRF users to share that line.

Security fix in the same file. get_devices() logged the decrypted GetDevsInRoomsOfHomeV2 reply with _LOGGER.debug(data), which holds every device key in clear text. That line is removed, because the new troubleshooting text asks users to post exactly this debug log.

Testing

Dev instance (HA 2026.9) with two fake gateways from tests/fakes/vrf.py inside the container: gateway A with 2 units, gateway B with 1 unit, added as a local YAML entry.

  • Both controllers created (VRF-gateway d5ba3, VRF-gateway d7c11, Dutch instance), all 3 sub-units have via_device_id to their gateway.
  • Delete of controller A: refused with the message above.
  • Delete of B0: controller B removed with it.
  • Delete of A0, then reload: controller A kept with the same device id, A1 still linked.
  • After the review changes: gateway has connections 94:24:b8:fd:5b:a3 and the firmware of its sub-unit; sub-units show hw_version.
  • The real unit (non-VRF) binds as before: 29 columns, no via device, zero ERROR lines.

Offline harness (real helpers and diagnostics against a stub registry): 20 passed, 0 failed. Covers stale controller removal, the MAC connection, firmware from the first bound sub-unit, a controller of another entry left alone, no writes on a second setup, cloud-only unit not linked, controller and normal diagnostics.

pytest 249 passed. ruff check and format pass. mypy on the changed files: no new errors (the 5 remaining are old, in select.py, config_schema.py, services.py).

Notes

  • I could not see the device page itself: the UI needs a login. The registry state was read through the API.
  • The delete error came back in English on a Dutch instance through the websocket. The frontend should translate it with the translation key; not checked.
  • A device that stops being a sub-unit keeps its old via_device_id while its old gateway still has other units. Rare, left out.

Every local VRF gateway MAC with at least one sub-unit now gets a
controller device without entities, identifier controller_<mac>. The
sub-units point to it with via_device_id, so the device page shows the
gateway with its indoor units under Connected devices.

- The link is set from setup code with async_update_device, not through
  DeviceInfo: HA 2026.3 only has via_device, 2026.9 only via_device_id.
- Setup reconciles instead of recreating: wanted controllers keep their
  device id, name and area; controllers without sub-units are removed.
- Grouping uses the saved mac_controller_local, not the runtime
  controller MAC, which follows the bound transport.
- Deleting a controller raises remove_vrf_controller. Deleting its last
  sub-unit removes the controller at once.
- Controller diagnostics hold the diagnostics of each sub-unit.
- Cloud-only VRF gets no controller yet. The raw cloud device list is
  logged at debug level with the keys redacted, so users can share pmac.
  The old raw log of GetDevsInRoomsOfHomeV2 is removed: it held every
  device key in clear text.

Tested in the dev instance against two fake gateways (2 units and
1 unit): links set, delete of the controller refused, controller gone
with its last unit, device id kept over a reload. Offline harness
17/17, pytest 249 passed.
Review points from Pedro:
- The gateway device has the gateway MAC as connection. Discovery never
  returns the gateway itself as a device, so nothing else has that MAC.
- Its sw_version and hw_version come from the first bound sub-unit,
  because the firmware belongs to the WiFi module of the gateway.
- One DeviceInfo for all units: the VRF branch in entity.py only left
  out hw_version and model_id, and the link is set from setup now.
@RobHofmann

Copy link
Copy Markdown
Owner Author

Review points from Pedro are in (bcd3c82):

  1. MAC connection on the gateway. The gateway device now has the gateway MAC as connections. Discovery never returns the gateway itself as a device, so no other device of this integration has that MAC.
  2. One DeviceInfo in entity.py. The VRF branch only left out hw_version and model_id, and the link is set from setup now, so the branch is gone. Sub-units now show both fields.
  3. Gateway firmware from a sub-unit. sw_version and hw_version of the gateway come from the first bound sub-unit. Without a bound sub-unit the registry keeps the last known values, so an offline unit does not clear them.
  4. Full status of a real sub-unit. Still needed, to confirm that all sub-units of one gateway report the same firmware (point 3 assumes that). A VRF user can send a device diagnostics download of a sub-unit (it holds state_info) or the output of the gree_custom.get_prop_values_all action.

Testing after these changes:

  • Dev instance with two fake gateways: the gateway has connection 94:24:b8:fd:5b:a3 and the firmware of its sub-unit, sub-units show hw_version, the real (non-VRF) unit is unchanged, zero ERROR lines.
  • Offline harness 20/20, pytest 249 passed, ruff passes, no new mypy errors. CI is green.

The PR description is updated to match.

@RobHofmann
RobHofmann merged commit ecb1248 into 5.0-dev Sep 24, 2026
4 checks passed
@RobHofmann
RobHofmann deleted the fix/vrf-controller-device branch September 24, 2026 19:33
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant