diff --git a/tests/test_gateway.py b/tests/test_gateway.py index 8b404e79c..5a7b8c34d 100644 --- a/tests/test_gateway.py +++ b/tests/test_gateway.py @@ -1080,13 +1080,14 @@ async def test_reinterview_replaces_device_when_quirk_changes( assert new_zha_device.model == "Quirk B" -async def test_reinterview_swap_emits_full_init_configured( +async def test_reinterview_swap_emits_full_init_events( zha_gateway: Gateway, ) -> None: - """A re-interview that replaces the device emits a CONFIGURED full-init event. + """A re-interview that replaces the device emits CONFIGURED, then INITIALIZED. - HA repoints its (IEEE-keyed) device proxy off this event, so the swap must - still surface it with `CONFIGURED` status and `new_join=False`. + HA repoints its (IEEE-keyed) device proxy off the first event, so the swap + must still surface it with `new_join=False`. The pairing UI only completes + on `INITIALIZED`. """ registry = DeviceRegistry() ( @@ -1125,9 +1126,11 @@ async def test_reinterview_swap_emits_full_init_configured( assert zha_gateway.get_device(zigpy_device.ieee) is not zha_device full_inits = [e for e in events if isinstance(e, DeviceFullInitEvent)] - assert len(full_inits) == 1 - assert full_inits[0].device_info.pairing_status is DevicePairingStatus.CONFIGURED - assert full_inits[0].new_join is False + assert [e.device_info.pairing_status for e in full_inits] == [ + DevicePairingStatus.CONFIGURED, + DevicePairingStatus.INITIALIZED, + ] + assert all(e.new_join is False for e in full_inits) async def test_reinterview_rebuilds_in_place_when_quirk_unchanged( diff --git a/tests/test_green_power_device.py b/tests/test_green_power_device.py index 7808277b0..84ca82b08 100644 --- a/tests/test_green_power_device.py +++ b/tests/test_green_power_device.py @@ -700,7 +700,8 @@ async def test_green_power_recommissioned_factory_change(zha_gateway: Gateway) - assert new_zha_device.on_network is True assert len(new_zha_device.platform_entities) == 1 assert [e.device_info.pairing_status for e in full] == [ - DevicePairingStatus.CONFIGURED + DevicePairingStatus.CONFIGURED, + DevicePairingStatus.INITIALIZED, ] # The same entry on both sides is rebuilt in place @@ -711,6 +712,10 @@ async def test_green_power_recommissioned_factory_change(zha_gateway: Gateway) - await zha_gateway.async_block_till_done() assert zha_gateway.devices[newer_zigpy_gpd.ieee] is new_zha_device assert new_zha_device.device is newer_zigpy_gpd + assert [e.device_info.pairing_status for e in full[2:]] == [ + DevicePairingStatus.CONFIGURED, + DevicePairingStatus.INITIALIZED, + ] async def test_bindable_target_source_without_clusters(zha_gateway: Gateway) -> None: diff --git a/zha/application/gateway.py b/zha/application/gateway.py index e8d3784f3..2145e5141 100644 --- a/zha/application/gateway.py +++ b/zha/application/gateway.py @@ -609,19 +609,25 @@ async def _async_device_reinterviewed( zha_device.emit_reconfigure_done() if not all_succeeded: - # Don't emit `DeviceFullInitEvent(CONFIGURED)` — entities are - # partial after a failed rebuild. + # Don't emit `DeviceFullInitEvent` — entities are partial after a + # failed rebuild. return - self.emit( - ZHA_GW_MSG_DEVICE_FULL_INIT, - DeviceFullInitEvent( - device_info=ExtendedDeviceInfoWithPairingStatus( - pairing_status=DevicePairingStatus.CONFIGURED, - **zha_device.extended_device_info.__dict__, + # Like a join, end with `INITIALIZED`. Besides Reconfigure, re-commissioning a + # GPD from the pairing UI lands here, which would otherwise stay on `CONFIGURED` + for pairing_status in ( + DevicePairingStatus.CONFIGURED, + DevicePairingStatus.INITIALIZED, + ): + self.emit( + ZHA_GW_MSG_DEVICE_FULL_INIT, + DeviceFullInitEvent( + device_info=ExtendedDeviceInfoWithPairingStatus( + pairing_status=pairing_status, + **zha_device.extended_device_info.__dict__, + ), ), - ), - ) + ) async def async_reinterview_device(self, ieee: EUI64) -> None: """Re-interview a device.