Move Fritzbox power, energy and temperature switch attributes to sensors (#52562)

* deprecate switch entity properties

* Add last_reset to FritzBoxEnergySensor

* Remove obsolet temperature attribute
This commit is contained in:
Michael 2021-07-23 13:06:30 +02:00 committed by GitHub
parent dee5d8903c
commit 42e8a7c842
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 82 additions and 40 deletions

View File

@ -13,9 +13,6 @@ ATTR_STATE_WINDOW_OPEN: Final = "window_open"
ATTR_TEMPERATURE_UNIT: Final = "temperature_unit"
ATTR_TOTAL_CONSUMPTION: Final = "total_consumption"
ATTR_TOTAL_CONSUMPTION_UNIT: Final = "total_consumption_unit"
CONF_CONNECTIONS: Final = "connections"
CONF_COORDINATOR: Final = "coordinator"

View File

@ -1,6 +1,8 @@
"""Support for AVM FRITZ!SmartHome temperature sensor only devices."""
from __future__ import annotations
from datetime import datetime
from homeassistant.components.sensor import (
ATTR_STATE_CLASS,
STATE_CLASS_MEASUREMENT,
@ -13,12 +15,17 @@ from homeassistant.const import (
ATTR_NAME,
ATTR_UNIT_OF_MEASUREMENT,
DEVICE_CLASS_BATTERY,
DEVICE_CLASS_ENERGY,
DEVICE_CLASS_POWER,
DEVICE_CLASS_TEMPERATURE,
ENERGY_KILO_WATT_HOUR,
PERCENTAGE,
POWER_WATT,
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.util.dt import utc_from_timestamp
from . import FritzBoxEntity
from .const import (
@ -68,11 +75,39 @@ async def async_setup_entry(
)
)
if device.has_powermeter:
entities.append(
FritzBoxPowerSensor(
{
ATTR_NAME: f"{device.name} Power Consumption",
ATTR_ENTITY_ID: f"{device.ain}_power_consumption",
ATTR_UNIT_OF_MEASUREMENT: POWER_WATT,
ATTR_DEVICE_CLASS: DEVICE_CLASS_POWER,
ATTR_STATE_CLASS: STATE_CLASS_MEASUREMENT,
},
coordinator,
ain,
)
)
entities.append(
FritzBoxEnergySensor(
{
ATTR_NAME: f"{device.name} Total Energy",
ATTR_ENTITY_ID: f"{device.ain}_total_energy",
ATTR_UNIT_OF_MEASUREMENT: ENERGY_KILO_WATT_HOUR,
ATTR_DEVICE_CLASS: DEVICE_CLASS_ENERGY,
ATTR_STATE_CLASS: None,
},
coordinator,
ain,
)
)
async_add_entities(entities)
class FritzBoxBatterySensor(FritzBoxEntity, SensorEntity):
"""The entity class for FRITZ!SmartHome sensors."""
"""The entity class for FRITZ!SmartHome battery sensors."""
@property
def state(self) -> int | None:
@ -80,6 +115,30 @@ class FritzBoxBatterySensor(FritzBoxEntity, SensorEntity):
return self.device.battery_level # type: ignore [no-any-return]
class FritzBoxPowerSensor(FritzBoxEntity, SensorEntity):
"""The entity class for FRITZ!SmartHome power consumption sensors."""
@property
def state(self) -> float | None:
"""Return the state of the sensor."""
return self.device.power / 1000 # type: ignore [no-any-return]
class FritzBoxEnergySensor(FritzBoxEntity, SensorEntity):
"""The entity class for FRITZ!SmartHome total energy sensors."""
@property
def state(self) -> float | None:
"""Return the state of the sensor."""
return (self.device.energy or 0.0) / 1000
@property
def last_reset(self) -> datetime:
"""Return the time when the sensor was last reset, if any."""
# device does not provide timestamp of initialization
return utc_from_timestamp(0)
class FritzBoxTempSensor(FritzBoxEntity, SensorEntity):
"""The entity class for FRITZ!SmartHome temperature sensors."""

View File

@ -10,10 +10,7 @@ from homeassistant.const import (
ATTR_DEVICE_CLASS,
ATTR_ENTITY_ID,
ATTR_NAME,
ATTR_TEMPERATURE,
ATTR_UNIT_OF_MEASUREMENT,
ENERGY_KILO_WATT_HOUR,
TEMP_CELSIUS,
)
from homeassistant.core import HomeAssistant
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -22,16 +19,11 @@ from . import FritzBoxEntity
from .const import (
ATTR_STATE_DEVICE_LOCKED,
ATTR_STATE_LOCKED,
ATTR_TEMPERATURE_UNIT,
ATTR_TOTAL_CONSUMPTION,
ATTR_TOTAL_CONSUMPTION_UNIT,
CONF_COORDINATOR,
DOMAIN as FRITZBOX_DOMAIN,
)
from .model import SwitchExtraAttributes
ATTR_TOTAL_CONSUMPTION_UNIT_VALUE = ENERGY_KILO_WATT_HOUR
async def async_setup_entry(
hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback
@ -91,22 +83,4 @@ class FritzboxSwitch(FritzBoxEntity, SwitchEntity):
ATTR_STATE_DEVICE_LOCKED: self.device.device_lock,
ATTR_STATE_LOCKED: self.device.lock,
}
if self.device.has_powermeter:
attrs[
ATTR_TOTAL_CONSUMPTION
] = f"{((self.device.energy or 0.0) / 1000):.3f}"
attrs[ATTR_TOTAL_CONSUMPTION_UNIT] = ATTR_TOTAL_CONSUMPTION_UNIT_VALUE
if self.device.has_temperature_sensor:
attrs[ATTR_TEMPERATURE] = str(
self.hass.config.units.temperature(
self.device.temperature, TEMP_CELSIUS
)
)
attrs[ATTR_TEMPERATURE_UNIT] = self.hass.config.units.temperature_unit
return attrs
@property
def current_power_w(self) -> float:
"""Return the current power usage in W."""
return self.device.power / 1000 # type: ignore [no-any-return]

View File

@ -55,6 +55,7 @@ class FritzDeviceBinarySensorMock(FritzDeviceBaseMock):
battery_level = 23
fw_version = "1.2.3"
has_alarm = True
has_powermeter = False
has_switch = False
has_temperature_sensor = False
has_thermostat = False
@ -73,6 +74,7 @@ class FritzDeviceClimateMock(FritzDeviceBaseMock):
eco_temperature = 16.0
fw_version = "1.2.3"
has_alarm = False
has_powermeter = False
has_switch = False
has_temperature_sensor = False
has_thermostat = True
@ -91,6 +93,7 @@ class FritzDeviceSensorMock(FritzDeviceBaseMock):
device_lock = "fake_locked_device"
fw_version = "1.2.3"
has_alarm = False
has_powermeter = False
has_switch = False
has_temperature_sensor = True
has_thermostat = False
@ -107,6 +110,7 @@ class FritzDeviceSwitchMock(FritzDeviceBaseMock):
energy = 1234
fw_version = "1.2.3"
has_alarm = False
has_powermeter = True
has_switch = True
has_temperature_sensor = True
has_thermostat = False

View File

@ -7,24 +7,22 @@ from requests.exceptions import HTTPError
from homeassistant.components.fritzbox.const import (
ATTR_STATE_DEVICE_LOCKED,
ATTR_STATE_LOCKED,
ATTR_TEMPERATURE_UNIT,
ATTR_TOTAL_CONSUMPTION,
ATTR_TOTAL_CONSUMPTION_UNIT,
DOMAIN as FB_DOMAIN,
)
from homeassistant.components.sensor import (
ATTR_LAST_RESET,
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 DOMAIN
from homeassistant.const import (
ATTR_ENTITY_ID,
ATTR_FRIENDLY_NAME,
ATTR_TEMPERATURE,
ATTR_UNIT_OF_MEASUREMENT,
CONF_DEVICES,
ENERGY_KILO_WATT_HOUR,
POWER_WATT,
SERVICE_TURN_OFF,
SERVICE_TURN_ON,
STATE_ON,
@ -51,14 +49,9 @@ 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_CURRENT_POWER_W] == 5.678
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] == "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")
@ -70,6 +63,21 @@ async def test_setup(hass: HomeAssistant, fritz: Mock):
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == TEMP_CELSIUS
assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT
state = hass.states.get(f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_power_consumption")
assert state
assert state.state == "5.678"
assert state.attributes[ATTR_FRIENDLY_NAME] == f"{CONF_FAKE_NAME} Power Consumption"
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == POWER_WATT
assert state.attributes[ATTR_STATE_CLASS] == STATE_CLASS_MEASUREMENT
state = hass.states.get(f"{SENSOR_DOMAIN}.{CONF_FAKE_NAME}_total_energy")
assert state
assert state.state == "1.234"
assert state.attributes[ATTR_LAST_RESET] == "1970-01-01T00:00:00+00:00"
assert state.attributes[ATTR_FRIENDLY_NAME] == f"{CONF_FAKE_NAME} Total Energy"
assert state.attributes[ATTR_UNIT_OF_MEASUREMENT] == ENERGY_KILO_WATT_HOUR
assert ATTR_STATE_CLASS not in state.attributes
async def test_turn_on(hass: HomeAssistant, fritz: Mock):
"""Test turn device on."""