Fritzbox enable temp sensor (#52558)

This commit is contained in:
Michael 2021-07-22 18:19:39 +02:00 committed by GitHub
parent 258162d933
commit 24e07bc154
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 205 additions and 63 deletions

View file

@ -6,6 +6,7 @@ from datetime import timedelta
from pyfritzhome import Fritzhome, FritzhomeDevice, LoginError from pyfritzhome import Fritzhome, FritzhomeDevice, LoginError
import requests import requests
from homeassistant.components.sensor import ATTR_STATE_CLASS
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
@ -16,10 +17,12 @@ from homeassistant.const import (
CONF_PASSWORD, CONF_PASSWORD,
CONF_USERNAME, CONF_USERNAME,
EVENT_HOMEASSISTANT_STOP, EVENT_HOMEASSISTANT_STOP,
TEMP_CELSIUS,
) )
from homeassistant.core import Event, HomeAssistant from homeassistant.core import Event, HomeAssistant
from homeassistant.exceptions import ConfigEntryAuthFailed from homeassistant.exceptions import ConfigEntryAuthFailed
from homeassistant.helpers.entity import DeviceInfo from homeassistant.helpers.entity import DeviceInfo
from homeassistant.helpers.entity_registry import RegistryEntry, async_migrate_entries
from homeassistant.helpers.update_coordinator import ( from homeassistant.helpers.update_coordinator import (
CoordinatorEntity, CoordinatorEntity,
DataUpdateCoordinator, DataUpdateCoordinator,
@ -81,6 +84,21 @@ async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool:
await coordinator.async_config_entry_first_refresh() 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) hass.config_entries.async_setup_platforms(entry, PLATFORMS)
def logout_fritzbox(event: Event) -> None: def logout_fritzbox(event: Event) -> None:
@ -123,6 +141,7 @@ class FritzBoxEntity(CoordinatorEntity):
self._unique_id = entity_info[ATTR_ENTITY_ID] self._unique_id = entity_info[ATTR_ENTITY_ID]
self._unit_of_measurement = entity_info[ATTR_UNIT_OF_MEASUREMENT] self._unit_of_measurement = entity_info[ATTR_UNIT_OF_MEASUREMENT]
self._device_class = entity_info[ATTR_DEVICE_CLASS] self._device_class = entity_info[ATTR_DEVICE_CLASS]
self._attr_state_class = entity_info[ATTR_STATE_CLASS]
@property @property
def device(self) -> FritzhomeDevice: def device(self) -> FritzhomeDevice:

View file

@ -5,6 +5,7 @@ from homeassistant.components.binary_sensor import (
DEVICE_CLASS_WINDOW, DEVICE_CLASS_WINDOW,
BinarySensorEntity, BinarySensorEntity,
) )
from homeassistant.components.sensor import ATTR_STATE_CLASS
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
@ -37,6 +38,7 @@ async def async_setup_entry(
ATTR_ENTITY_ID: f"{device.ain}", ATTR_ENTITY_ID: f"{device.ain}",
ATTR_UNIT_OF_MEASUREMENT: None, ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_DEVICE_CLASS: DEVICE_CLASS_WINDOW, ATTR_DEVICE_CLASS: DEVICE_CLASS_WINDOW,
ATTR_STATE_CLASS: None,
}, },
coordinator, coordinator,
ain, ain,

View file

@ -13,6 +13,7 @@ from homeassistant.components.climate.const import (
SUPPORT_PRESET_MODE, SUPPORT_PRESET_MODE,
SUPPORT_TARGET_TEMPERATURE, SUPPORT_TARGET_TEMPERATURE,
) )
from homeassistant.components.sensor import ATTR_STATE_CLASS
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_BATTERY_LEVEL, ATTR_BATTERY_LEVEL,
@ -74,6 +75,7 @@ async def async_setup_entry(
ATTR_ENTITY_ID: f"{device.ain}", ATTR_ENTITY_ID: f"{device.ain}",
ATTR_UNIT_OF_MEASUREMENT: None, ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_DEVICE_CLASS: None, ATTR_DEVICE_CLASS: None,
ATTR_STATE_CLASS: None,
}, },
coordinator, coordinator,
ain, ain,

View file

@ -11,6 +11,7 @@ class EntityInfo(TypedDict):
entity_id: str entity_id: str
unit_of_measurement: str | None unit_of_measurement: str | None
device_class: str | None device_class: str | None
state_class: str | None
class ClimateExtraAttributes(TypedDict, total=False): class ClimateExtraAttributes(TypedDict, total=False):

View file

@ -1,7 +1,11 @@
"""Support for AVM FRITZ!SmartHome temperature sensor only devices.""" """Support for AVM FRITZ!SmartHome temperature sensor only devices."""
from __future__ import annotations 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.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
@ -34,18 +38,15 @@ async def async_setup_entry(
coordinator = hass.data[FRITZBOX_DOMAIN][entry.entry_id][CONF_COORDINATOR] coordinator = hass.data[FRITZBOX_DOMAIN][entry.entry_id][CONF_COORDINATOR]
for ain, device in coordinator.data.items(): for ain, device in coordinator.data.items():
if ( if device.has_temperature_sensor and not device.has_thermostat:
device.has_temperature_sensor
and not device.has_switch
and not device.has_thermostat
):
entities.append( entities.append(
FritzBoxTempSensor( FritzBoxTempSensor(
{ {
ATTR_NAME: f"{device.name}", ATTR_NAME: f"{device.name} Temperature",
ATTR_ENTITY_ID: f"{device.ain}", ATTR_ENTITY_ID: f"{device.ain}_temperature",
ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS, ATTR_UNIT_OF_MEASUREMENT: TEMP_CELSIUS,
ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE, ATTR_DEVICE_CLASS: DEVICE_CLASS_TEMPERATURE,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
}, },
coordinator, coordinator,
ain, ain,
@ -60,6 +61,7 @@ async def async_setup_entry(
ATTR_ENTITY_ID: f"{device.ain}_battery", ATTR_ENTITY_ID: f"{device.ain}_battery",
ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE, ATTR_UNIT_OF_MEASUREMENT: PERCENTAGE,
ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY, ATTR_DEVICE_CLASS: DEVICE_CLASS_BATTERY,
ATTR_STATE_CLASS: None,
}, },
coordinator, coordinator,
ain, ain,

View file

@ -3,6 +3,7 @@ from __future__ import annotations
from typing import Any from typing import Any
from homeassistant.components.sensor import ATTR_STATE_CLASS
from homeassistant.components.switch import SwitchEntity from homeassistant.components.switch import SwitchEntity
from homeassistant.config_entries import ConfigEntry from homeassistant.config_entries import ConfigEntry
from homeassistant.const import ( from homeassistant.const import (
@ -50,6 +51,7 @@ async def async_setup_entry(
ATTR_ENTITY_ID: f"{device.ain}", ATTR_ENTITY_ID: f"{device.ain}",
ATTR_UNIT_OF_MEASUREMENT: None, ATTR_UNIT_OF_MEASUREMENT: None,
ATTR_DEVICE_CLASS: None, ATTR_DEVICE_CLASS: None,
ATTR_STATE_CLASS: None,
}, },
coordinator, coordinator,
ain, ain,

View file

@ -5,22 +5,16 @@ from typing import Any
from unittest.mock import Mock from unittest.mock import Mock
from homeassistant.components.fritzbox.const import DOMAIN 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 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 = { from tests.common import MockConfigEntry
DOMAIN: {
CONF_DEVICES: [
{
CONF_HOST: "fake_host",
CONF_PASSWORD: "fake_pass",
CONF_USERNAME: "fake_user",
}
]
}
}
async def setup_config_entry( async def setup_config_entry(
@ -45,27 +39,32 @@ async def setup_config_entry(
return result 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.""" """Mock of a AVM Fritz!Box binary sensor device."""
ain = "fake_ain"
alert_state = "fake_state" alert_state = "fake_state"
battery_level = 23
fw_version = "1.2.3" fw_version = "1.2.3"
has_alarm = True has_alarm = True
has_switch = False has_switch = False
has_temperature_sensor = False has_temperature_sensor = False
has_thermostat = False has_thermostat = False
manufacturer = "fake_manufacturer"
name = "fake_name"
present = True present = True
productname = "fake_productname"
class FritzDeviceClimateMock(Mock): class FritzDeviceClimateMock(FritzDeviceBaseMock):
"""Mock of a AVM Fritz!Box climate device.""" """Mock of a AVM Fritz!Box climate device."""
actual_temperature = 18.0 actual_temperature = 18.0
ain = "fake_ain"
alert_state = "fake_state" alert_state = "fake_state"
battery_level = 23 battery_level = 23
battery_low = True battery_low = True
@ -79,19 +78,15 @@ class FritzDeviceClimateMock(Mock):
has_thermostat = True has_thermostat = True
holiday_active = "fake_holiday" holiday_active = "fake_holiday"
lock = "fake_locked" lock = "fake_locked"
manufacturer = "fake_manufacturer"
name = "fake_name"
present = True present = True
productname = "fake_productname"
summer_active = "fake_summer" summer_active = "fake_summer"
target_temperature = 19.5 target_temperature = 19.5
window_open = "fake_window" window_open = "fake_window"
class FritzDeviceSensorMock(Mock): class FritzDeviceSensorMock(FritzDeviceBaseMock):
"""Mock of a AVM Fritz!Box sensor device.""" """Mock of a AVM Fritz!Box sensor device."""
ain = "fake_ain"
battery_level = 23 battery_level = 23
device_lock = "fake_locked_device" device_lock = "fake_locked_device"
fw_version = "1.2.3" fw_version = "1.2.3"
@ -100,17 +95,14 @@ class FritzDeviceSensorMock(Mock):
has_temperature_sensor = True has_temperature_sensor = True
has_thermostat = False has_thermostat = False
lock = "fake_locked" lock = "fake_locked"
manufacturer = "fake_manufacturer"
name = "fake_name"
present = True present = True
productname = "fake_productname"
temperature = 1.23 temperature = 1.23
class FritzDeviceSwitchMock(Mock): class FritzDeviceSwitchMock(FritzDeviceBaseMock):
"""Mock of a AVM Fritz!Box switch device.""" """Mock of a AVM Fritz!Box switch device."""
ain = "fake_ain" battery_level = None
device_lock = "fake_locked_device" device_lock = "fake_locked_device"
energy = 1234 energy = 1234
fw_version = "1.2.3" fw_version = "1.2.3"
@ -120,9 +112,6 @@ class FritzDeviceSwitchMock(Mock):
has_thermostat = False has_thermostat = False
switch_state = "fake_state" switch_state = "fake_state"
lock = "fake_locked" lock = "fake_locked"
manufacturer = "fake_manufacturer"
name = "fake_name"
power = 5678 power = 5678
present = True present = True
productname = "fake_productname" temperature = 1.23
temperature = 135

View file

@ -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"

View file

@ -7,21 +7,25 @@ from requests.exceptions import HTTPError
from homeassistant.components.binary_sensor import DOMAIN from homeassistant.components.binary_sensor import DOMAIN
from homeassistant.components.fritzbox.const import DOMAIN as FB_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 ( from homeassistant.const import (
ATTR_DEVICE_CLASS, ATTR_DEVICE_CLASS,
ATTR_FRIENDLY_NAME, ATTR_FRIENDLY_NAME,
ATTR_UNIT_OF_MEASUREMENT,
CONF_DEVICES, CONF_DEVICES,
PERCENTAGE,
STATE_OFF, STATE_OFF,
STATE_ON, STATE_ON,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
import homeassistant.util.dt as dt_util 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 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): 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) state = hass.states.get(ENTITY_ID)
assert state assert state
assert state.state == STATE_ON 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 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): async def test_is_off(hass: HomeAssistant, fritz: Mock):

View file

@ -30,21 +30,25 @@ from homeassistant.components.fritzbox.const import (
ATTR_STATE_WINDOW_OPEN, ATTR_STATE_WINDOW_OPEN,
DOMAIN as FB_DOMAIN, DOMAIN as FB_DOMAIN,
) )
from homeassistant.components.sensor import ATTR_STATE_CLASS, DOMAIN as SENSOR_DOMAIN
from homeassistant.const import ( from homeassistant.const import (
ATTR_BATTERY_LEVEL, ATTR_BATTERY_LEVEL,
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME, ATTR_FRIENDLY_NAME,
ATTR_TEMPERATURE, ATTR_TEMPERATURE,
ATTR_UNIT_OF_MEASUREMENT,
CONF_DEVICES, CONF_DEVICES,
PERCENTAGE,
) )
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
import homeassistant.util.dt as dt_util 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 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): async def test_setup(hass: HomeAssistant, fritz: Mock):
@ -58,7 +62,7 @@ async def test_setup(hass: HomeAssistant, fritz: Mock):
assert state assert state
assert state.attributes[ATTR_BATTERY_LEVEL] == 23 assert state.attributes[ATTR_BATTERY_LEVEL] == 23
assert state.attributes[ATTR_CURRENT_TEMPERATURE] == 18 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_HVAC_MODES] == [HVAC_MODE_HEAT, HVAC_MODE_OFF]
assert state.attributes[ATTR_MAX_TEMP] == 28 assert state.attributes[ATTR_MAX_TEMP] == 28
assert state.attributes[ATTR_MIN_TEMP] == 8 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_SUMMER_MODE] == "fake_summer"
assert state.attributes[ATTR_STATE_WINDOW_OPEN] == "fake_window" assert state.attributes[ATTR_STATE_WINDOW_OPEN] == "fake_window"
assert state.attributes[ATTR_TEMPERATURE] == 19.5 assert state.attributes[ATTR_TEMPERATURE] == 19.5
assert ATTR_STATE_CLASS not in state.attributes
assert state.state == HVAC_MODE_HEAT 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): async def test_target_temperature_on(hass: HomeAssistant, fritz: Mock):
"""Test turn device on.""" """Test turn device on."""

View file

@ -21,14 +21,14 @@ from homeassistant.data_entry_flow import (
RESULT_TYPE_FORM, RESULT_TYPE_FORM,
) )
from . import MOCK_CONFIG from .const import CONF_FAKE_NAME, MOCK_CONFIG
from tests.common import MockConfigEntry from tests.common import MockConfigEntry
MOCK_USER_DATA = MOCK_CONFIG[DOMAIN][CONF_DEVICES][0] MOCK_USER_DATA = MOCK_CONFIG[DOMAIN][CONF_DEVICES][0]
MOCK_SSDP_DATA = { MOCK_SSDP_DATA = {
ATTR_SSDP_LOCATION: "https://fake_host:12345/test", 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", 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"}, user_input={CONF_PASSWORD: "fake_pass", CONF_USERNAME: "fake_user"},
) )
assert result["type"] == RESULT_TYPE_CREATE_ENTRY 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_HOST] == "fake_host"
assert result["data"][CONF_PASSWORD] == "fake_pass" assert result["data"][CONF_PASSWORD] == "fake_pass"
assert result["data"][CONF_USERNAME] == "fake_user" assert result["data"][CONF_USERNAME] == "fake_user"

View file

@ -7,6 +7,7 @@ from pyfritzhome import LoginError
from requests.exceptions import HTTPError from requests.exceptions import HTTPError
from homeassistant.components.fritzbox.const import DOMAIN as FB_DOMAIN 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.components.switch import DOMAIN as SWITCH_DOMAIN
from homeassistant.config_entries import ConfigEntryState from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import ( from homeassistant.const import (
@ -15,10 +16,13 @@ from homeassistant.const import (
CONF_PASSWORD, CONF_PASSWORD,
CONF_USERNAME, CONF_USERNAME,
STATE_UNAVAILABLE, STATE_UNAVAILABLE,
TEMP_CELSIUS,
) )
from homeassistant.core import HomeAssistant 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 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): async def test_coordinator_update_after_reboot(hass: HomeAssistant, fritz: Mock):
"""Test coordinator after reboot.""" """Test coordinator after reboot."""
entry = MockConfigEntry( entry = MockConfigEntry(
@ -74,7 +130,7 @@ async def test_coordinator_update_after_password_change(
async def test_unload_remove(hass: HomeAssistant, fritz: Mock): async def test_unload_remove(hass: HomeAssistant, fritz: Mock):
"""Test unload and remove of integration.""" """Test unload and remove of integration."""
fritz().get_devices.return_value = [FritzDeviceSwitchMock()] fritz().get_devices.return_value = [FritzDeviceSwitchMock()]
entity_id = f"{SWITCH_DOMAIN}.fake_name" entity_id = f"{SWITCH_DOMAIN}.{CONF_FAKE_NAME}"
entry = MockConfigEntry( entry = MockConfigEntry(
domain=FB_DOMAIN, domain=FB_DOMAIN,

View file

@ -9,7 +9,11 @@ from homeassistant.components.fritzbox.const import (
ATTR_STATE_LOCKED, ATTR_STATE_LOCKED,
DOMAIN as FB_DOMAIN, 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 ( from homeassistant.const import (
ATTR_FRIENDLY_NAME, ATTR_FRIENDLY_NAME,
ATTR_UNIT_OF_MEASUREMENT, ATTR_UNIT_OF_MEASUREMENT,
@ -20,11 +24,12 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
import homeassistant.util.dt as dt_util 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 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): 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( assert await setup_config_entry(
hass, MOCK_CONFIG[FB_DOMAIN][CONF_DEVICES][0], ENTITY_ID, device, fritz 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
assert state.state == "1.23" 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_DEVICE_LOCKED] == "fake_locked_device"
assert state.attributes[ATTR_STATE_LOCKED] == "fake_locked" assert state.attributes[ATTR_STATE_LOCKED] == "fake_locked"
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS 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") state = hass.states.get(f"{ENTITY_ID}_battery")
assert state assert state
assert state.state == "23" 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 state.attributes[ATTR_UNIT_OF_MEASUREMENT] == PERCENTAGE
assert ATTR_STATE_CLASS not in state.attributes
async def test_update(hass: HomeAssistant, fritz: Mock): async def test_update(hass: HomeAssistant, fritz: Mock):

View file

@ -12,11 +12,17 @@ from homeassistant.components.fritzbox.const import (
ATTR_TOTAL_CONSUMPTION_UNIT, ATTR_TOTAL_CONSUMPTION_UNIT,
DOMAIN as FB_DOMAIN, 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.components.switch import ATTR_CURRENT_POWER_W, DOMAIN
from homeassistant.const import ( from homeassistant.const import (
ATTR_ENTITY_ID, ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME, ATTR_FRIENDLY_NAME,
ATTR_TEMPERATURE, ATTR_TEMPERATURE,
ATTR_UNIT_OF_MEASUREMENT,
CONF_DEVICES, CONF_DEVICES,
ENERGY_KILO_WATT_HOUR, ENERGY_KILO_WATT_HOUR,
SERVICE_TURN_OFF, SERVICE_TURN_OFF,
@ -27,11 +33,12 @@ from homeassistant.const import (
from homeassistant.core import HomeAssistant from homeassistant.core import HomeAssistant
import homeassistant.util.dt as dt_util 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 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): async def test_setup(hass: HomeAssistant, fritz: Mock):
@ -45,13 +52,23 @@ async def test_setup(hass: HomeAssistant, fritz: Mock):
assert state assert state
assert state.state == STATE_ON assert state.state == STATE_ON
assert state.attributes[ATTR_CURRENT_POWER_W] == 5.678 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_DEVICE_LOCKED] == "fake_locked_device"
assert state.attributes[ATTR_STATE_LOCKED] == "fake_locked" 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_TEMPERATURE_UNIT] == TEMP_CELSIUS
assert state.attributes[ATTR_TOTAL_CONSUMPTION] == "1.234" assert state.attributes[ATTR_TOTAL_CONSUMPTION] == "1.234"
assert state.attributes[ATTR_TOTAL_CONSUMPTION_UNIT] == ENERGY_KILO_WATT_HOUR 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): async def test_turn_on(hass: HomeAssistant, fritz: Mock):