diff --git a/homeassistant/components/unifi/sensor.py b/homeassistant/components/unifi/sensor.py index 7a161a9d7c2..4f3e8528256 100644 --- a/homeassistant/components/unifi/sensor.py +++ b/homeassistant/components/unifi/sensor.py @@ -300,13 +300,22 @@ def make_wan_latency_sensors() -> tuple[UnifiSensorEntityDescription, ...]: @callback def async_device_temperatures_value_fn( temperature_name: str, hub: UnifiHub, device: Device -) -> float: +) -> float | None: """Retrieve the temperature of the device.""" - return_value: float = 0 if device.temperatures: - temperature = _device_temperature(temperature_name, device.temperatures) - return_value = temperature if temperature is not None else 0 - return return_value + return _device_temperature(temperature_name, device.temperatures) + return None + + +@callback +def async_device_temperatures_available_fn( + temperature_name: str, hub: UnifiHub, obj_id: str +) -> bool: + """Determine if a device temperature has a value.""" + device = hub.api.devices[obj_id] + if not async_device_available_fn(hub, obj_id): + return False + return _device_temperature(temperature_name, device.temperatures or []) is not None @callback @@ -315,7 +324,11 @@ def async_device_temperatures_supported_fn( ) -> bool: """Determine if an device have a temperatures.""" if (device := hub.api.devices[obj_id]) and device.temperatures: - return _device_temperature(temperature_name, device.temperatures) is not None + return any( + temperature_name in temperature["name"] + for temperature in device.temperatures + ) + return False @@ -326,7 +339,8 @@ def _device_temperature( """Return the temperature of the device.""" for temperature in temperatures: if temperature_name in temperature["name"]: - return temperature["value"] + if (value := temperature.get("value")) is not None: + return value return None @@ -344,7 +358,7 @@ def make_device_temperatur_sensors() -> tuple[UnifiSensorEntityDescription, ...] native_unit_of_measurement=UnitOfTemperature.CELSIUS, entity_registry_enabled_default=False, api_handler_fn=lambda api: api.devices, - available_fn=async_device_available_fn, + available_fn=partial(async_device_temperatures_available_fn, name), device_info_fn=async_device_device_info_fn, name_fn=lambda device: f"{device.name} {name} Temperature", object_fn=lambda api, obj_id: api.devices[obj_id], diff --git a/tests/components/unifi/test_sensor.py b/tests/components/unifi/test_sensor.py index 4aef840982f..0788f32dd63 100644 --- a/tests/components/unifi/test_sensor.py +++ b/tests/components/unifi/test_sensor.py @@ -1774,6 +1774,75 @@ async def test_device_temperatures( assert hass.states.get(entity_id).state == updated_state +@pytest.mark.parametrize( + "device_payload", + [ + [ + { + "board_rev": 3, + "device_id": "mock-id", + "has_fan": True, + "fan_level": 0, + "ip": "10.0.1.1", + "last_seen": 1562600145, + "mac": "00:00:00:00:01:01", + "model": "US16P150", + "name": "Device", + "next_interval": 20, + "overheating": True, + "state": 1, + "type": "usw", + "upgradable": True, + "uptime": 60, + "version": "4.0.42.10433", + "temperatures": [ + {"name": "CPU", "type": "cpu", "value": 66.0}, + ], + } + ] + ], +) +@pytest.mark.usefixtures("config_entry_setup") +async def test_device_temperature_with_missing_value( + hass: HomeAssistant, + entity_registry: er.EntityRegistry, + mock_websocket_message, + device_payload: list[dict[str, Any]], +) -> None: + """Verify that device temperatures sensors are working as expected.""" + entity_id = "sensor.device_device_cpu_temperature" + + temperature_entity = entity_registry.async_get(entity_id) + assert temperature_entity.disabled_by == RegistryEntryDisabler.INTEGRATION + + # Enable entity + entity_registry.async_update_entity(entity_id=entity_id, 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() + + # Verify sensor state + assert hass.states.get(entity_id).state == "66.0" + + # Remove temperature value from payload + device = deepcopy(device_payload[0]) + device["temperatures"][0].pop("value") + + mock_websocket_message(message=MessageKey.DEVICE, data=device) + + assert hass.states.get(entity_id).state == STATE_UNAVAILABLE + + # Send original payload again to verify sensor recovers + mock_websocket_message(message=MessageKey.DEVICE, data=device_payload[0]) + + assert hass.states.get(entity_id).state == "66.0" + + @pytest.mark.parametrize( "device_payload", [