diff --git a/homeassistant/components/unifi/sensor.py b/homeassistant/components/unifi/sensor.py index efb3eed4de4..54ecc2ea763 100644 --- a/homeassistant/components/unifi/sensor.py +++ b/homeassistant/components/unifi/sensor.py @@ -339,6 +339,19 @@ ENTITY_DESCRIPTIONS: tuple[UnifiSensorEntityDescription, ...] = ( value_fn=async_device_state_value_fn, options=list(DEVICE_STATES.values()), ), + UnifiSensorEntityDescription[Wlans, Wlan]( + key="WLAN password", + entity_category=EntityCategory.DIAGNOSTIC, + entity_registry_enabled_default=False, + api_handler_fn=lambda api: api.wlans, + available_fn=async_wlan_available_fn, + device_info_fn=async_wlan_device_info_fn, + name_fn=lambda wlan: "Password", + object_fn=lambda api, obj_id: api.wlans[obj_id], + supported_fn=lambda hub, obj_id: hub.api.wlans[obj_id].x_passphrase is not None, + unique_id_fn=lambda hub, obj_id: f"password-{obj_id}", + value_fn=lambda hub, obj: obj.x_passphrase, + ), ) diff --git a/tests/components/unifi/test_sensor.py b/tests/components/unifi/test_sensor.py index 7a58252a6bd..239707aa4c9 100644 --- a/tests/components/unifi/test_sensor.py +++ b/tests/components/unifi/test_sensor.py @@ -998,3 +998,74 @@ async def test_device_state( device["state"] = i mock_unifi_websocket(message=MessageKey.DEVICE, data=device) assert hass.states.get("sensor.device_state").state == DEVICE_STATES[i] + + +async def test_wlan_password( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + aioclient_mock: AiohttpClientMocker, + mock_unifi_websocket, + websocket_mock, +) -> None: + """Test the WLAN password sensor behavior.""" + await setup_unifi_integration(hass, aioclient_mock, wlans_response=[WLAN]) + + sensor_password = "sensor.ssid_1_password" + password = "password" + new_password = "new_password" + + ent_reg_entry = entity_registry.async_get(sensor_password) + assert ent_reg_entry.unique_id == "password-012345678910111213141516" + assert ent_reg_entry.disabled_by == RegistryEntryDisabler.INTEGRATION + assert ent_reg_entry.entity_category is EntityCategory.DIAGNOSTIC + + # Enable entity + entity_registry.async_update_entity(entity_id=sensor_password, disabled_by=None) + await hass.async_block_till_done() + + async_fire_time_changed( + hass, + dt_util.utcnow() + timedelta(seconds=RELOAD_AFTER_UPDATE_DELAY + 1), + ) + await hass.async_block_till_done() + + # Validate state object + wlan_password_sensor_1 = hass.states.get(sensor_password) + assert wlan_password_sensor_1.state == password + + # Update state object - same password - no change to state + mock_unifi_websocket(message=MessageKey.WLAN_CONF_UPDATED, data=WLAN) + await hass.async_block_till_done() + wlan_password_sensor_2 = hass.states.get(sensor_password) + assert wlan_password_sensor_1.state == wlan_password_sensor_2.state + + # Update state object - changed password - new state + data = deepcopy(WLAN) + data["x_passphrase"] = new_password + mock_unifi_websocket(message=MessageKey.WLAN_CONF_UPDATED, data=data) + await hass.async_block_till_done() + wlan_password_sensor_3 = hass.states.get(sensor_password) + assert wlan_password_sensor_1.state != wlan_password_sensor_3.state + + # Availability signaling + + # Controller disconnects + await websocket_mock.disconnect() + assert hass.states.get(sensor_password).state == STATE_UNAVAILABLE + + # Controller reconnects + await websocket_mock.reconnect() + assert hass.states.get(sensor_password).state == new_password + + # WLAN gets disabled + wlan_1 = deepcopy(WLAN) + wlan_1["enabled"] = False + mock_unifi_websocket(message=MessageKey.WLAN_CONF_UPDATED, data=wlan_1) + await hass.async_block_till_done() + assert hass.states.get(sensor_password).state == STATE_UNAVAILABLE + + # WLAN gets re-enabled + wlan_1["enabled"] = True + mock_unifi_websocket(message=MessageKey.WLAN_CONF_UPDATED, data=wlan_1) + await hass.async_block_till_done() + assert hass.states.get(sensor_password).state == password