diff --git a/homeassistant/components/fritzbox/sensor.py b/homeassistant/components/fritzbox/sensor.py index 46fa1a26561..013c1dfc7b5 100644 --- a/homeassistant/components/fritzbox/sensor.py +++ b/homeassistant/components/fritzbox/sensor.py @@ -48,6 +48,8 @@ class FritzSensorEntityDescription( ): """Description for Fritz!Smarthome sensor entities.""" + entity_category_fn: Callable[[FritzhomeDevice], EntityCategory | None] | None = None + def suitable_eco_temperature(device: FritzhomeDevice) -> bool: """Check suitablity for eco temperature sensor.""" @@ -74,6 +76,13 @@ def suitable_temperature(device: FritzhomeDevice) -> bool: return device.has_temperature_sensor and not device.has_thermostat +def entity_category_temperature(device: FritzhomeDevice) -> EntityCategory | None: + """Determine proper entity category for temperature sensor.""" + if device.has_switch or device.has_lightbulb: + return EntityCategory.DIAGNOSTIC + return None + + def value_nextchange_preset(device: FritzhomeDevice) -> str: """Return native value for next scheduled preset sensor.""" if device.nextchange_temperature == device.eco_temperature: @@ -94,7 +103,7 @@ SENSOR_TYPES: Final[tuple[FritzSensorEntityDescription, ...]] = ( native_unit_of_measurement=UnitOfTemperature.CELSIUS, device_class=SensorDeviceClass.TEMPERATURE, state_class=SensorStateClass.MEASUREMENT, - entity_category=EntityCategory.DIAGNOSTIC, + entity_category_fn=entity_category_temperature, suitable=suitable_temperature, native_value=lambda device: device.temperature, ), @@ -224,3 +233,10 @@ class FritzBoxSensor(FritzBoxDeviceEntity, SensorEntity): def native_value(self) -> StateType | datetime: """Return the state of the sensor.""" return self.entity_description.native_value(self.data) + + @property + def entity_category(self) -> EntityCategory | None: + """Return the category of the entity, if any.""" + if self.entity_description.entity_category_fn is not None: + return self.entity_description.entity_category_fn(self.data) + return super().entity_category diff --git a/tests/components/fritzbox/test_sensor.py b/tests/components/fritzbox/test_sensor.py index 8a01665134b..b4c0209e9af 100644 --- a/tests/components/fritzbox/test_sensor.py +++ b/tests/components/fritzbox/test_sensor.py @@ -11,9 +11,11 @@ from homeassistant.const import ( ATTR_UNIT_OF_MEASUREMENT, CONF_DEVICES, PERCENTAGE, + EntityCategory, UnitOfTemperature, ) from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er import homeassistant.util.dt as dt_util from . import FritzDeviceSensorMock, setup_config_entry @@ -32,26 +34,44 @@ async def test_setup(hass: HomeAssistant, fritz: Mock) -> None: ) await hass.async_block_till_done() - state = hass.states.get(f"{ENTITY_ID}_temperature") - assert state - assert state.state == "1.23" - assert state.attributes[ATTR_FRIENDLY_NAME] == f"{CONF_FAKE_NAME} Temperature" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == UnitOfTemperature.CELSIUS - assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT + sensors = ( + [ + f"{ENTITY_ID}_temperature", + "1.23", + f"{CONF_FAKE_NAME} Temperature", + UnitOfTemperature.CELSIUS, + SensorStateClass.MEASUREMENT, + None, + ], + [ + f"{ENTITY_ID}_humidity", + "42", + f"{CONF_FAKE_NAME} Humidity", + PERCENTAGE, + SensorStateClass.MEASUREMENT, + None, + ], + [ + f"{ENTITY_ID}_battery", + "23", + f"{CONF_FAKE_NAME} Battery", + PERCENTAGE, + None, + EntityCategory.DIAGNOSTIC, + ], + ) - state = hass.states.get(f"{ENTITY_ID}_humidity") - assert state - assert state.state == "42" - assert state.attributes[ATTR_FRIENDLY_NAME] == f"{CONF_FAKE_NAME} Humidity" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE - assert state.attributes[ATTR_STATE_CLASS] == SensorStateClass.MEASUREMENT - - state = hass.states.get(f"{ENTITY_ID}_battery") - assert state - assert state.state == "23" - assert state.attributes[ATTR_FRIENDLY_NAME] == f"{CONF_FAKE_NAME} Battery" - assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE - assert ATTR_STATE_CLASS not in state.attributes + entity_registry = er.async_get(hass) + for sensor in sensors: + state = hass.states.get(sensor[0]) + assert state + assert state.state == sensor[1] + assert state.attributes[ATTR_FRIENDLY_NAME] == sensor[2] + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == sensor[3] + assert state.attributes.get(ATTR_STATE_CLASS) == sensor[4] + entry = entity_registry.async_get(sensor[0]) + assert entry + assert entry.entity_category is sensor[5] async def test_update(hass: HomeAssistant, fritz: Mock) -> None: diff --git a/tests/components/fritzbox/test_switch.py b/tests/components/fritzbox/test_switch.py index 4ac36a13284..53cdf5147fc 100644 --- a/tests/components/fritzbox/test_switch.py +++ b/tests/components/fritzbox/test_switch.py @@ -20,6 +20,7 @@ from homeassistant.const import ( SERVICE_TURN_ON, STATE_ON, STATE_UNAVAILABLE, + EntityCategory, UnitOfElectricCurrent, UnitOfElectricPotential, UnitOfEnergy, @@ -27,6 +28,7 @@ from homeassistant.const import ( UnitOfTemperature, ) from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er import homeassistant.util.dt as dt_util from . import FritzDeviceSwitchMock, setup_config_entry @@ -60,6 +62,7 @@ async def test_setup(hass: HomeAssistant, fritz: Mock) -> None: f"{CONF_FAKE_NAME} Temperature", UnitOfTemperature.CELSIUS, SensorStateClass.MEASUREMENT, + EntityCategory.DIAGNOSTIC, ], [ f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_power", @@ -67,6 +70,7 @@ async def test_setup(hass: HomeAssistant, fritz: Mock) -> None: f"{CONF_FAKE_NAME} Power", UnitOfPower.WATT, SensorStateClass.MEASUREMENT, + None, ], [ f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_energy", @@ -74,6 +78,7 @@ async def test_setup(hass: HomeAssistant, fritz: Mock) -> None: f"{CONF_FAKE_NAME} Energy", UnitOfEnergy.KILO_WATT_HOUR, SensorStateClass.TOTAL_INCREASING, + None, ], [ f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_voltage", @@ -81,6 +86,7 @@ async def test_setup(hass: HomeAssistant, fritz: Mock) -> None: f"{CONF_FAKE_NAME} Voltage", UnitOfElectricPotential.VOLT, SensorStateClass.MEASUREMENT, + None, ], [ f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_current", @@ -88,9 +94,11 @@ async def test_setup(hass: HomeAssistant, fritz: Mock) -> None: f"{CONF_FAKE_NAME} Current", UnitOfElectricCurrent.AMPERE, SensorStateClass.MEASUREMENT, + None, ], ) + entity_registry = er.async_get(hass) for sensor in sensors: state = hass.states.get(sensor[0]) assert state @@ -98,6 +106,10 @@ async def test_setup(hass: HomeAssistant, fritz: Mock) -> None: assert state.attributes[ATTR_FRIENDLY_NAME] == sensor[2] assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == sensor[3] assert state.attributes[ATTR_STATE_CLASS] == sensor[4] + assert state.attributes[ATTR_STATE_CLASS] == sensor[4] + entry = entity_registry.async_get(sensor[0]) + assert entry + assert entry.entity_category is sensor[5] async def test_turn_on(hass: HomeAssistant, fritz: Mock) -> None: