From d10f5cc9ea2e6bef7c2ecd39da6237563c29646a Mon Sep 17 00:00:00 2001 From: Jon <127239833+jronnols@users.noreply.github.com> Date: Thu, 12 Feb 2026 23:56:35 +0100 Subject: [PATCH] Expose power and energy sensors for vera metered switches (#161028) --- homeassistant/components/vera/sensor.py | 64 +++++++++++++++-- tests/components/vera/test_sensor.py | 95 +++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 7 deletions(-) diff --git a/homeassistant/components/vera/sensor.py b/homeassistant/components/vera/sensor.py index d778b4c2e5d..f69025d3ec6 100644 --- a/homeassistant/components/vera/sensor.py +++ b/homeassistant/components/vera/sensor.py @@ -11,12 +11,14 @@ from homeassistant.components.sensor import ( ENTITY_ID_FORMAT, SensorDeviceClass, SensorEntity, + SensorStateClass, ) from homeassistant.config_entries import ConfigEntry from homeassistant.const import ( LIGHT_LUX, PERCENTAGE, Platform, + UnitOfEnergy, UnitOfPower, UnitOfTemperature, ) @@ -36,13 +38,19 @@ async def async_setup_entry( ) -> None: """Set up the sensor config entry.""" controller_data = get_controller_data(hass, entry) - async_add_entities( - [ - VeraSensor(device, controller_data) - for device in controller_data.devices[Platform.SENSOR] - ], - True, - ) + + entities: list[SensorEntity] = [ + VeraSensor(device, controller_data) + for device in controller_data.devices[Platform.SENSOR] + ] + + for device in controller_data.devices[Platform.SWITCH]: + if device.power is not None: + entities.append(VeraPowerSensor(device, controller_data)) + if device.energy is not None: + entities.append(VeraEnergySensor(device, controller_data)) + + async_add_entities(entities, True) class VeraSensor(VeraEntity[veraApi.VeraSensor], SensorEntity): @@ -109,3 +117,45 @@ class VeraSensor(VeraEntity[veraApi.VeraSensor], SensorEntity): self._attr_native_value = "Tripped" if tripped else "Not Tripped" else: self._attr_native_value = "Unknown" + + +class VeraPowerSensor(VeraEntity[veraApi.VeraSwitch], SensorEntity): + """Power sensor derived from a Vera switch with metering.""" + + _attr_device_class = SensorDeviceClass.POWER + _attr_has_entity_name = True + _attr_state_class = SensorStateClass.MEASUREMENT + _attr_native_unit_of_measurement = UnitOfPower.WATT + + def __init__( + self, vera_device: veraApi.VeraSwitch, controller_data: ControllerData + ) -> None: + """Initialize the power sensor.""" + VeraEntity.__init__(self, vera_device, controller_data) + self._unique_id = f"{self._unique_id}_power" + + def update(self) -> None: + """Update the sensor state.""" + super().update() + self._attr_native_value = self.vera_device.power + + +class VeraEnergySensor(VeraEntity[veraApi.VeraSwitch], SensorEntity): + """Energy sensor derived from a Vera switch with metering.""" + + _attr_device_class = SensorDeviceClass.ENERGY + _attr_has_entity_name = True + _attr_state_class = SensorStateClass.TOTAL_INCREASING + _attr_native_unit_of_measurement = UnitOfEnergy.KILO_WATT_HOUR + + def __init__( + self, vera_device: veraApi.VeraSwitch, controller_data: ControllerData + ) -> None: + """Initialize the energy sensor.""" + VeraEntity.__init__(self, vera_device, controller_data) + self._unique_id = f"{self._unique_id}_energy" + + def update(self) -> None: + """Update the sensor state.""" + super().update() + self._attr_native_value = self.vera_device.energy diff --git a/tests/components/vera/test_sensor.py b/tests/components/vera/test_sensor.py index 64873000c7b..86eff4fcfcb 100644 --- a/tests/components/vera/test_sensor.py +++ b/tests/components/vera/test_sensor.py @@ -11,6 +11,7 @@ import pyvera as pv from homeassistant.components.sensor import async_rounded_state from homeassistant.const import ATTR_UNIT_OF_MEASUREMENT, LIGHT_LUX, PERCENTAGE from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity_registry as er from .common import ComponentFactory, new_simple_controller_config @@ -201,3 +202,97 @@ async def test_scene_controller_sensor( update_callback(vera_device) await hass.async_block_till_done() assert hass.states.get(entity_id).state == "id0" + + +async def test_switch_power_and_energy_sensors_created( + hass: HomeAssistant, + vera_component_factory: ComponentFactory, + entity_registry: er.EntityRegistry, +) -> None: + """Test that switches with metering expose power and energy sensors.""" + vera_switch: pv.VeraSwitch = MagicMock(spec=pv.VeraSwitch) + vera_switch.device_id = 1 + vera_switch.vera_device_id = vera_switch.device_id + vera_switch.comm_failure = False + vera_switch.name = "metered_switch" + vera_switch.category = 0 + vera_switch.power = 12 + vera_switch.energy = 3 + + vera_sensor: pv.VeraSensor = MagicMock(spec=pv.VeraSensor) + vera_sensor.device_id = 2 + vera_sensor.vera_device_id = vera_sensor.device_id + vera_sensor.comm_failure = False + vera_sensor.name = "dummy_sensor" + vera_sensor.category = pv.CATEGORY_TEMPERATURE_SENSOR + vera_sensor.temperature = "20" + + await vera_component_factory.configure_component( + hass=hass, + controller_config=new_simple_controller_config( + devices=(vera_switch, vera_sensor) + ), + ) + await hass.async_block_till_done() + + power_entity_id = entity_registry.async_get_entity_id( + "sensor", "vera", "vera_1111_1_power" + ) + energy_entity_id = entity_registry.async_get_entity_id( + "sensor", "vera", "vera_1111_1_energy" + ) + + assert power_entity_id is not None + assert energy_entity_id is not None + + power_state = hass.states.get(power_entity_id) + assert power_state is not None + assert power_state.state == "12" + assert power_state.attributes[ATTR_UNIT_OF_MEASUREMENT] == "W" + + energy_state = hass.states.get(energy_entity_id) + assert energy_state is not None + assert energy_state.state == "3" + assert energy_state.attributes[ATTR_UNIT_OF_MEASUREMENT] == "kWh" + + +async def test_switch_without_metering_does_not_create_power_energy_sensors( + hass: HomeAssistant, + vera_component_factory: ComponentFactory, + entity_registry: er.EntityRegistry, +) -> None: + """Test that non-metered switches do not create power/energy sensors.""" + vera_switch: pv.VeraSwitch = MagicMock(spec=pv.VeraSwitch) + vera_switch.device_id = 1 + vera_switch.vera_device_id = vera_switch.device_id + vera_switch.comm_failure = False + vera_switch.name = "plain_switch" + vera_switch.category = 0 + vera_switch.power = None + vera_switch.energy = None + + vera_sensor: pv.VeraSensor = MagicMock(spec=pv.VeraSensor) + vera_sensor.device_id = 2 + vera_sensor.vera_device_id = vera_sensor.device_id + vera_sensor.comm_failure = False + vera_sensor.name = "dummy_sensor" + vera_sensor.category = pv.CATEGORY_TEMPERATURE_SENSOR + vera_sensor.temperature = "20" + + await vera_component_factory.configure_component( + hass=hass, + controller_config=new_simple_controller_config( + devices=(vera_switch, vera_sensor) + ), + ) + await hass.async_block_till_done() + + power_entity_id = entity_registry.async_get_entity_id( + "sensor", "vera", "vera_1111_1_power" + ) + energy_entity_id = entity_registry.async_get_entity_id( + "sensor", "vera", "vera_1111_1_energy" + ) + + assert power_entity_id is None + assert energy_entity_id is None