From 24e07bc1545ac69c23e93b164fc6be0e0d1a681b Mon Sep 17 00:00:00 2001 From: Michael <35783820+mib1185@users.noreply.github.com> Date: Thu, 22 Jul 2021 18:19:39 +0200 Subject: [PATCH] Fritzbox enable temp sensor (#52558) --- homeassistant/components/fritzbox/__init__.py | 19 ++++++ .../components/fritzbox/binary_sensor.py | 2 + homeassistant/components/fritzbox/climate.py | 2 + homeassistant/components/fritzbox/model.py | 1 + homeassistant/components/fritzbox/sensor.py | 18 +++--- homeassistant/components/fritzbox/switch.py | 2 + tests/components/fritzbox/__init__.py | 57 +++++++----------- tests/components/fritzbox/const.py | 20 +++++++ .../components/fritzbox/test_binary_sensor.py | 18 +++++- tests/components/fritzbox/test_climate.py | 18 +++++- tests/components/fritzbox/test_config_flow.py | 6 +- tests/components/fritzbox/test_init.py | 60 ++++++++++++++++++- tests/components/fritzbox/test_sensor.py | 20 +++++-- tests/components/fritzbox/test_switch.py | 25 ++++++-- 14 files changed, 205 insertions(+), 63 deletions(-) create mode 100644 tests/components/fritzbox/const.py diff --git a/homeassistant/components/fritzbox/__init__.py b/homeassistant/components/fritzbox/__init__.py index 124719b93c1..087faeb2be9 100644 --- a/homeassistant/components/fritzbox/__init__.py +++ b/homeassistant/components/fritzbox/__init__.py @@ -6,6 +6,7 @@ from datetime import timedelta from pyfritzhome import Fritzhome, FritzhomeDevice, LoginError import requests +from homeassistant.components.sensor import ATTR_STATE_CLASS from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_DEVICE_CLASS, @@ -16,10 +17,12 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_USERNAME, EVENT_HOMEASSISTANT_STOP, + TEMP_CELSIUS, ) from homeassistant.core import Event, HomeAssistant from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.helpers.entity import DeviceInfo +from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries from homeassistant.helpers.update_coordinator import ( CoordinatorEntity, DataUpdateCoordinator, @@ -81,6 +84,21 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: await coordinator.async_config_entry_first_refresh() + def _update_unique_id(entry: RegistryEntry) -> dict[str, str] | None: + """Update unique ID of entity entry.""" + if ( + entry.unit_of_measurement == TEMP_CELSIUS + and "_temperature" not in entry.unique_id + ): + new_unique_id = f"{entry.unique_id}_temperature" + LOGGER.info( + "Migrating unique_id [%s] to [%s]", entry.unique_id, new_unique_id + ) + return {"new_unique_id": new_unique_id} + return None + + await async_migrate_entries(hass, entry.entry_id, _update_unique_id) + hass.config_entries.async_setup_platforms(entry, PLATFORMS) def logout_fritzbox(event: Event) -> None: @@ -123,6 +141,7 @@ class FritzBoxEntity(CoordinatorEntity): self._unique_id = entity_info[ATTR_ENTITY_ID] self._unit_of_measurement = entity_info[ATTR_UNIT_OF_MEASUREMENT] self._device_class = entity_info[ATTR_DEVICE_CLASS] + self._attr_state_class = entity_info[ATTR_STATE_CLASS] @property def device(self) -> FritzhomeDevice: diff --git a/homeassistant/components/fritzbox/binary_sensor.py b/homeassistant/components/fritzbox/binary_sensor.py index 242e3d6e644..f6dbaed97cf 100644 --- a/homeassistant/components/fritzbox/binary_sensor.py +++ b/homeassistant/components/fritzbox/binary_sensor.py @@ -5,6 +5,7 @@ from homeassistant.components.binary_sensor import ( DEVICE_CLASS_WINDOW, BinarySensorEntity, ) +from homeassistant.components.sensor import ATTR_STATE_CLASS from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_DEVICE_CLASS, @@ -37,6 +38,7 @@ async def async_setup_entry( ATTR_ENTITY_ID: f"{device.ain}", ATTR_UNIT_OF_MEASUREMENT: None, ATTR_DEVICE_CLASS: DEVICE_CLASS_WINDOW, + ATTR_STATE_CLASS: None, }, coordinator, ain, diff --git a/homeassistant/components/fritzbox/climate.py b/homeassistant/components/fritzbox/climate.py index c50e0d4f270..0551c5e0455 100644 --- a/homeassistant/components/fritzbox/climate.py +++ b/homeassistant/components/fritzbox/climate.py @@ -13,6 +13,7 @@ from homeassistant.components.climate.const import ( SUPPORT_PRESET_MODE, SUPPORT_TARGET_TEMPERATURE, ) +from homeassistant.components.sensor import ATTR_STATE_CLASS from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_BATTERY_LEVEL, @@ -74,6 +75,7 @@ async def async_setup_entry( ATTR_ENTITY_ID: f"{device.ain}", ATTR_UNIT_OF_MEASUREMENT: None, ATTR_DEVICE_CLASS: None, + ATTR_STATE_CLASS: None, }, coordinator, ain, diff --git a/homeassistant/components/fritzbox/model.py b/homeassistant/components/fritzbox/model.py index 1cde7b9ca70..0e401a75be3 100644 --- a/homeassistant/components/fritzbox/model.py +++ b/homeassistant/components/fritzbox/model.py @@ -11,6 +11,7 @@ class EntityInfo(TypedDict): entity_id: str unit_of_measurement: str | None device_class: str | None + state_class: str | None class ClimateExtraAttributes(TypedDict, total=False): diff --git a/homeassistant/components/fritzbox/sensor.py b/homeassistant/components/fritzbox/sensor.py index db50776d69c..0a83e3ba60c 100644 --- a/homeassistant/components/fritzbox/sensor.py +++ b/homeassistant/components/fritzbox/sensor.py @@ -1,7 +1,11 @@ """Support for AVM FRITZ!SmartHome temperature sensor only devices.""" from __future__ import annotations -from homeassistant.components.sensor import SensorEntity +from homeassistant.components.sensor import ( + ATTR_STATE_CLASS, + STATE_CLASS_MEASUREMENT, + SensorEntity, +) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( ATTR_DEVICE_CLASS, @@ -34,18 +38,15 @@ async def async_setup_entry( coordinator = hass.data[FRITZBOX_DOMAIN][entry.entry_id][CONF_COORDINATOR] for ain, device in coordinator.data.items(): - if ( - device.has_temperature_sensor - and not device.has_switch - and not device.has_thermostat - ): + if device.has_temperature_sensor and not device.has_thermostat: entities.append( FritzBoxTempSensor( { - ATTR_NAME: f"{device.name}", - ATTR_ENTITY_ID: f"{device.ain}", + ATTR_NAME: f"{device.name} Temperature", + ATTR_ENTITY_ID: f"{device.ain}_temperature", ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, + ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT, }, coordinator, ain, @@ -60,6 +61,7 @@ async def async_setup_entry( ATTR_ENTITY_ID: f"{device.ain}_battery", ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY, + ATTR_STATE_CLASS: None, }, coordinator, ain, diff --git a/homeassistant/components/fritzbox/switch.py b/homeassistant/components/fritzbox/switch.py index 82581473714..22b2adf5800 100644 --- a/homeassistant/components/fritzbox/switch.py +++ b/homeassistant/components/fritzbox/switch.py @@ -3,6 +3,7 @@ from __future__ import annotations from typing import Any +from homeassistant.components.sensor import ATTR_STATE_CLASS from homeassistant.components.switch import SwitchEntity from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( @@ -50,6 +51,7 @@ async def async_setup_entry( ATTR_ENTITY_ID: f"{device.ain}", ATTR_UNIT_OF_MEASUREMENT: None, ATTR_DEVICE_CLASS: None, + ATTR_STATE_CLASS: None, }, coordinator, ain, diff --git a/tests/components/fritzbox/__init__.py b/tests/components/fritzbox/__init__.py index ee5d15bd1b8..3ff4b71364e 100644 --- a/tests/components/fritzbox/__init__.py +++ b/tests/components/fritzbox/__init__.py @@ -5,22 +5,16 @@ from typing import Any from unittest.mock import Mock from homeassistant.components.fritzbox.const import DOMAIN -from homeassistant.const import CONF_DEVICES, CONF_HOST, CONF_PASSWORD, CONF_USERNAME from homeassistant.core import HomeAssistant -from tests.common import MockConfigEntry +from .const import ( + CONF_FAKE_AIN, + CONF_FAKE_MANUFACTURER, + CONF_FAKE_NAME, + CONF_FAKE_PRODUCTNAME, +) -MOCK_CONFIG = { - DOMAIN: { - CONF_DEVICES: [ - { - CONF_HOST: "fake_host", - CONF_PASSWORD: "fake_pass", - CONF_USERNAME: "fake_user", - } - ] - } -} +from tests.common import MockConfigEntry async def setup_config_entry( @@ -45,27 +39,32 @@ async def setup_config_entry( return result -class FritzDeviceBinarySensorMock(Mock): +class FritzDeviceBaseMock(Mock): + """base mock of a AVM Fritz!Box binary sensor device.""" + + ain = CONF_FAKE_AIN + manufacturer = CONF_FAKE_MANUFACTURER + name = CONF_FAKE_NAME + productname = CONF_FAKE_PRODUCTNAME + + +class FritzDeviceBinarySensorMock(FritzDeviceBaseMock): """Mock of a AVM Fritz!Box binary sensor device.""" - ain = "fake_ain" alert_state = "fake_state" + battery_level = 23 fw_version = "1.2.3" has_alarm = True has_switch = False has_temperature_sensor = False has_thermostat = False - manufacturer = "fake_manufacturer" - name = "fake_name" present = True - productname = "fake_productname" -class FritzDeviceClimateMock(Mock): +class FritzDeviceClimateMock(FritzDeviceBaseMock): """Mock of a AVM Fritz!Box climate device.""" actual_temperature = 18.0 - ain = "fake_ain" alert_state = "fake_state" battery_level = 23 battery_low = True @@ -79,19 +78,15 @@ class FritzDeviceClimateMock(Mock): has_thermostat = True holiday_active = "fake_holiday" lock = "fake_locked" - manufacturer = "fake_manufacturer" - name = "fake_name" present = True - productname = "fake_productname" summer_active = "fake_summer" target_temperature = 19.5 window_open = "fake_window" -class FritzDeviceSensorMock(Mock): +class FritzDeviceSensorMock(FritzDeviceBaseMock): """Mock of a AVM Fritz!Box sensor device.""" - ain = "fake_ain" battery_level = 23 device_lock = "fake_locked_device" fw_version = "1.2.3" @@ -100,17 +95,14 @@ class FritzDeviceSensorMock(Mock): has_temperature_sensor = True has_thermostat = False lock = "fake_locked" - manufacturer = "fake_manufacturer" - name = "fake_name" present = True - productname = "fake_productname" temperature = 1.23 -class FritzDeviceSwitchMock(Mock): +class FritzDeviceSwitchMock(FritzDeviceBaseMock): """Mock of a AVM Fritz!Box switch device.""" - ain = "fake_ain" + battery_level = None device_lock = "fake_locked_device" energy = 1234 fw_version = "1.2.3" @@ -120,9 +112,6 @@ class FritzDeviceSwitchMock(Mock): has_thermostat = False switch_state = "fake_state" lock = "fake_locked" - manufacturer = "fake_manufacturer" - name = "fake_name" power = 5678 present = True - productname = "fake_productname" - temperature = 135 + temperature = 1.23 diff --git a/tests/components/fritzbox/const.py b/tests/components/fritzbox/const.py new file mode 100644 index 00000000000..1b8bc927800 --- /dev/null +++ b/tests/components/fritzbox/const.py @@ -0,0 +1,20 @@ +"""Constants for fritzbox tests.""" +from homeassistant.components.fritzbox.const import DOMAIN +from homeassistant.const import CONF_DEVICES, CONF_HOST, CONF_PASSWORD, CONF_USERNAME + +MOCK_CONFIG = { + DOMAIN: { + CONF_DEVICES: [ + { + CONF_HOST: "fake_host", + CONF_PASSWORD: "fake_pass", + CONF_USERNAME: "fake_user", + } + ] + } +} + +CONF_FAKE_NAME = "fake_name" +CONF_FAKE_AIN = "fake_ain" +CONF_FAKE_MANUFACTURER = "fake_manufacturer" +CONF_FAKE_PRODUCTNAME = "fake_productname" diff --git a/tests/components/fritzbox/test_binary_sensor.py b/tests/components/fritzbox/test_binary_sensor.py index 7a2d2347004..f4e32fbe3df 100644 --- a/tests/components/fritzbox/test_binary_sensor.py +++ b/tests/components/fritzbox/test_binary_sensor.py @@ -7,21 +7,25 @@ from requests.exceptions import HTTPError from homeassistant.components.binary_sensor import DOMAIN from homeassistant.components.fritzbox.const import DOMAIN as FB_DOMAIN +from homeassistant.components.sensor import ATTR_STATE_CLASS, DOMAIN as SENSOR_DOMAIN from homeassistant.const import ( ATTR_DEVICE_CLASS, ATTR_FRIENDLY_NAME, + ATTR_UNIT_OF_MEASUREMENT, CONF_DEVICES, + PERCENTAGE, STATE_OFF, STATE_ON, ) from homeassistant.core import HomeAssistant import homeassistant.util.dt as dt_util -from . import MOCK_CONFIG, FritzDeviceBinarySensorMock, setup_config_entry +from . import FritzDeviceBinarySensorMock, setup_config_entry +from .const import CONF_FAKE_NAME, MOCK_CONFIG from tests.common import async_fire_time_changed -ENTITY_ID = f"{DOMAIN}.fake_name" +ENTITY_ID = f"{DOMAIN}.{CONF_FAKE_NAME}" async def test_setup(hass: HomeAssistant, fritz: Mock): @@ -34,8 +38,16 @@ async def test_setup(hass: HomeAssistant, fritz: Mock): state = hass.states.get(ENTITY_ID) assert state assert state.state == STATE_ON - assert state.attributes[ATTR_FRIENDLY_NAME] == "fake_name" + assert state.attributes[ATTR_FRIENDLY_NAME] == CONF_FAKE_NAME assert state.attributes[ATTR_DEVICE_CLASS] == "window" + assert ATTR_STATE_CLASS not in state.attributes + + state = hass.states.get(f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_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 async def test_is_off(hass: HomeAssistant, fritz: Mock): diff --git a/tests/components/fritzbox/test_climate.py b/tests/components/fritzbox/test_climate.py index 59d32e18c34..30ee7130fea 100644 --- a/tests/components/fritzbox/test_climate.py +++ b/tests/components/fritzbox/test_climate.py @@ -30,21 +30,25 @@ from homeassistant.components.fritzbox.const import ( ATTR_STATE_WINDOW_OPEN, DOMAIN as FB_DOMAIN, ) +from homeassistant.components.sensor import ATTR_STATE_CLASS, DOMAIN as SENSOR_DOMAIN from homeassistant.const import ( ATTR_BATTERY_LEVEL, ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_TEMPERATURE, + ATTR_UNIT_OF_MEASUREMENT, CONF_DEVICES, + PERCENTAGE, ) from homeassistant.core import HomeAssistant import homeassistant.util.dt as dt_util -from . import MOCK_CONFIG, FritzDeviceClimateMock, setup_config_entry +from . import FritzDeviceClimateMock, setup_config_entry +from .const import CONF_FAKE_NAME, MOCK_CONFIG from tests.common import async_fire_time_changed -ENTITY_ID = f"{DOMAIN}.fake_name" +ENTITY_ID = f"{DOMAIN}.{CONF_FAKE_NAME}" async def test_setup(hass: HomeAssistant, fritz: Mock): @@ -58,7 +62,7 @@ async def test_setup(hass: HomeAssistant, fritz: Mock): assert state assert state.attributes[ATTR_BATTERY_LEVEL] == 23 assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 18 - assert state.attributes[ATTR_FRIENDLY_NAME] == "fake_name" + assert state.attributes[ATTR_FRIENDLY_NAME] == CONF_FAKE_NAME assert state.attributes[ATTR_HVAC_MODES] == [HVAC_MODE_HEAT, HVAC_MODE_OFF] assert state.attributes[ATTR_MAX_TEMP] == 28 assert state.attributes[ATTR_MIN_TEMP] == 8 @@ -71,8 +75,16 @@ async def test_setup(hass: HomeAssistant, fritz: Mock): assert state.attributes[ATTR_STATE_SUMMER_MODE] == "fake_summer" assert state.attributes[ATTR_STATE_WINDOW_OPEN] == "fake_window" assert state.attributes[ATTR_TEMPERATURE] == 19.5 + assert ATTR_STATE_CLASS not in state.attributes assert state.state == HVAC_MODE_HEAT + state = hass.states.get(f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_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 + async def test_target_temperature_on(hass: HomeAssistant, fritz: Mock): """Test turn device on.""" diff --git a/tests/components/fritzbox/test_config_flow.py b/tests/components/fritzbox/test_config_flow.py index a9de92060ec..6d62122a871 100644 --- a/tests/components/fritzbox/test_config_flow.py +++ b/tests/components/fritzbox/test_config_flow.py @@ -21,14 +21,14 @@ from homeassistant.data_entry_flow import ( RESULT_TYPE_FORM, ) -from . import MOCK_CONFIG +from .const import CONF_FAKE_NAME, MOCK_CONFIG from tests.common import MockConfigEntry MOCK_USER_DATA = MOCK_CONFIG[DOMAIN][CONF_DEVICES][0] MOCK_SSDP_DATA = { ATTR_SSDP_LOCATION: "https://fake_host:12345/test", - ATTR_UPNP_FRIENDLY_NAME: "fake_name", + ATTR_UPNP_FRIENDLY_NAME: CONF_FAKE_NAME, ATTR_UPNP_UDN: "uuid:only-a-test", } @@ -192,7 +192,7 @@ async def test_ssdp(hass: HomeAssistant, fritz: Mock): user_input={CONF_PASSWORD: "fake_pass", CONF_USERNAME: "fake_user"}, ) assert result["type"] == RESULT_TYPE_CREATE_ENTRY - assert result["title"] == "fake_name" + assert result["title"] == CONF_FAKE_NAME assert result["data"][CONF_HOST] == "fake_host" assert result["data"][CONF_PASSWORD] == "fake_pass" assert result["data"][CONF_USERNAME] == "fake_user" diff --git a/tests/components/fritzbox/test_init.py b/tests/components/fritzbox/test_init.py index 438335868cd..ea0356c6af1 100644 --- a/tests/components/fritzbox/test_init.py +++ b/tests/components/fritzbox/test_init.py @@ -7,6 +7,7 @@ from pyfritzhome import LoginError from requests.exceptions import HTTPError from homeassistant.components.fritzbox.const import DOMAIN as FB_DOMAIN +from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN from homeassistant.components.switch import DOMAIN as SWITCH_DOMAIN from homeassistant.config_entries import ConfigEntryState from homeassistant.const import ( @@ -15,10 +16,13 @@ from homeassistant.const import ( CONF_PASSWORD, CONF_USERNAME, STATE_UNAVAILABLE, + TEMP_CELSIUS, ) from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er -from . import MOCK_CONFIG, FritzDeviceSwitchMock, setup_config_entry +from . import FritzDeviceSwitchMock, setup_config_entry +from .const import CONF_FAKE_AIN, CONF_FAKE_NAME, MOCK_CONFIG from tests.common import MockConfigEntry @@ -38,6 +42,58 @@ async def test_setup(hass: HomeAssistant, fritz: Mock): ] +async def test_update_unique_id(hass: HomeAssistant, fritz: Mock): + """Test unique_id update of integration.""" + entry = MockConfigEntry( + domain=FB_DOMAIN, + data=MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], + unique_id="any", + ) + entry.add_to_hass(hass) + + entity_registry = er.async_get(hass) + entity = entity_registry.async_get_or_create( + SENSOR_DOMAIN, + FB_DOMAIN, + CONF_FAKE_AIN, + unit_of_measurement=TEMP_CELSIUS, + config_entry=entry, + ) + assert entity.unique_id == CONF_FAKE_AIN + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_migrated = entity_registry.async_get(entity.entity_id) + assert entity_migrated + assert entity_migrated.unique_id == f"{CONF_FAKE_AIN}_temperature" + + +async def test_update_unique_id_no_change(hass: HomeAssistant, fritz: Mock): + """Test unique_id is not updated of integration.""" + entry = MockConfigEntry( + domain=FB_DOMAIN, + data=MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], + unique_id="any", + ) + entry.add_to_hass(hass) + + entity_registry = er.async_get(hass) + entity = entity_registry.async_get_or_create( + SENSOR_DOMAIN, + FB_DOMAIN, + f"{CONF_FAKE_AIN}_temperature", + unit_of_measurement=TEMP_CELSIUS, + config_entry=entry, + ) + assert entity.unique_id == f"{CONF_FAKE_AIN}_temperature" + assert await hass.config_entries.async_setup(entry.entry_id) + await hass.async_block_till_done() + + entity_migrated = entity_registry.async_get(entity.entity_id) + assert entity_migrated + assert entity_migrated.unique_id == f"{CONF_FAKE_AIN}_temperature" + + async def test_coordinator_update_after_reboot(hass: HomeAssistant, fritz: Mock): """Test coordinator after reboot.""" entry = MockConfigEntry( @@ -74,7 +130,7 @@ async def test_coordinator_update_after_password_change( async def test_unload_remove(hass: HomeAssistant, fritz: Mock): """Test unload and remove of integration.""" fritz().get_devices.return_value = [FritzDeviceSwitchMock()] - entity_id = f"{SWITCH_DOMAIN}.fake_name" + entity_id = f"{SWITCH_DOMAIN}.{CONF_FAKE_NAME}" entry = MockConfigEntry( domain=FB_DOMAIN, diff --git a/tests/components/fritzbox/test_sensor.py b/tests/components/fritzbox/test_sensor.py index c1d82a93189..664b6765c03 100644 --- a/tests/components/fritzbox/test_sensor.py +++ b/tests/components/fritzbox/test_sensor.py @@ -9,7 +9,11 @@ from homeassistant.components.fritzbox.const import ( ATTR_STATE_LOCKED, DOMAIN as FB_DOMAIN, ) -from homeassistant.components.sensor import DOMAIN +from homeassistant.components.sensor import ( + ATTR_STATE_CLASS, + DOMAIN, + STATE_CLASS_MEASUREMENT, +) from homeassistant.const import ( ATTR_FRIENDLY_NAME, ATTR_UNIT_OF_MEASUREMENT, @@ -20,11 +24,12 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant import homeassistant.util.dt as dt_util -from . import MOCK_CONFIG, FritzDeviceSensorMock, setup_config_entry +from . import FritzDeviceSensorMock, setup_config_entry +from .const import CONF_FAKE_NAME, MOCK_CONFIG from tests.common import async_fire_time_changed -ENTITY_ID = f"{DOMAIN}.fake_name" +ENTITY_ID = f"{DOMAIN}.{CONF_FAKE_NAME}" async def test_setup(hass: HomeAssistant, fritz: Mock): @@ -33,20 +38,23 @@ async def test_setup(hass: HomeAssistant, fritz: Mock): assert await setup_config_entry( hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz ) + await hass.async_block_till_done() - state = hass.states.get(ENTITY_ID) + state = hass.states.get(f"{ENTITY_ID}_temperature") assert state assert state.state == "1.23" - assert state.attributes[ATTR_FRIENDLY_NAME] == "fake_name" + assert state.attributes[ATTR_FRIENDLY_NAME] == f"{CONF_FAKE_NAME} Temperature" assert state.attributes[ATTR_STATE_DEVICE_LOCKED] == "fake_locked_device" assert state.attributes[ATTR_STATE_LOCKED] == "fake_locked" assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS + assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT state = hass.states.get(f"{ENTITY_ID}_battery") assert state assert state.state == "23" - assert state.attributes[ATTR_FRIENDLY_NAME] == "fake_name Battery" + 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 async def test_update(hass: HomeAssistant, fritz: Mock): diff --git a/tests/components/fritzbox/test_switch.py b/tests/components/fritzbox/test_switch.py index cc0caeafa69..4bace3834fb 100644 --- a/tests/components/fritzbox/test_switch.py +++ b/tests/components/fritzbox/test_switch.py @@ -12,11 +12,17 @@ from homeassistant.components.fritzbox.const import ( ATTR_TOTAL_CONSUMPTION_UNIT, DOMAIN as FB_DOMAIN, ) +from homeassistant.components.sensor import ( + ATTR_STATE_CLASS, + DOMAIN as SENSOR_DOMAIN, + STATE_CLASS_MEASUREMENT, +) from homeassistant.components.switch import ATTR_CURRENT_POWER_W, DOMAIN from homeassistant.const import ( ATTR_ENTITY_ID, ATTR_FRIENDLY_NAME, ATTR_TEMPERATURE, + ATTR_UNIT_OF_MEASUREMENT, CONF_DEVICES, ENERGY_KILO_WATT_HOUR, SERVICE_TURN_OFF, @@ -27,11 +33,12 @@ from homeassistant.const import ( from homeassistant.core import HomeAssistant import homeassistant.util.dt as dt_util -from . import MOCK_CONFIG, FritzDeviceSwitchMock, setup_config_entry +from . import FritzDeviceSwitchMock, setup_config_entry +from .const import CONF_FAKE_NAME, MOCK_CONFIG from tests.common import async_fire_time_changed -ENTITY_ID = f"{DOMAIN}.fake_name" +ENTITY_ID = f"{DOMAIN}.{CONF_FAKE_NAME}" async def test_setup(hass: HomeAssistant, fritz: Mock): @@ -45,13 +52,23 @@ async def test_setup(hass: HomeAssistant, fritz: Mock): assert state assert state.state == STATE_ON assert state.attributes[ATTR_CURRENT_POWER_W] == 5.678 - assert state.attributes[ATTR_FRIENDLY_NAME] == "fake_name" + assert state.attributes[ATTR_FRIENDLY_NAME] == CONF_FAKE_NAME assert state.attributes[ATTR_STATE_DEVICE_LOCKED] == "fake_locked_device" assert state.attributes[ATTR_STATE_LOCKED] == "fake_locked" - assert state.attributes[ATTR_TEMPERATURE] == "135" + assert state.attributes[ATTR_TEMPERATURE] == "1.23" assert state.attributes[ATTR_TEMPERATURE_UNIT] == TEMP_CELSIUS assert state.attributes[ATTR_TOTAL_CONSUMPTION] == "1.234" assert state.attributes[ATTR_TOTAL_CONSUMPTION_UNIT] == ENERGY_KILO_WATT_HOUR + assert ATTR_STATE_CLASS not in state.attributes + + state = hass.states.get(f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_temperature") + assert state + assert state.state == "1.23" + assert state.attributes[ATTR_FRIENDLY_NAME] == f"{CONF_FAKE_NAME} Temperature" + assert state.attributes[ATTR_STATE_DEVICE_LOCKED] == "fake_locked_device" + assert state.attributes[ATTR_STATE_LOCKED] == "fake_locked" + assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS + assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT async def test_turn_on(hass: HomeAssistant, fritz: Mock):