Add sensors for energy trends for devices (#129439)

Co-authored-by: Joost Lekkerkerker <joostlek@outlook.com>
This commit is contained in:
Keilin Bickar 2024-10-29 15:02:08 -04:00 committed by GitHub
parent ec19712388
commit 3adc3d7732
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 957 additions and 291 deletions

View File

@ -79,10 +79,16 @@ async def async_setup_entry(
sense_monitor_id = data.sense_monitor_id
entities: list[SensorEntity] = [
SenseDevicePowerSensor(device, sense_monitor_id, realtime_coordinator)
for device in config_entry.runtime_data.data.devices
]
entities: list[SensorEntity] = []
for device in config_entry.runtime_data.data.devices:
entities.append(
SenseDevicePowerSensor(device, sense_monitor_id, realtime_coordinator)
)
entities.extend(
SenseDeviceEnergySensor(device, scale, trends_coordinator, sense_monitor_id)
for scale in Scale
)
for variant_id, variant_name in SENSOR_VARIANTS:
entities.append(
@ -242,3 +248,35 @@ class SenseDevicePowerSensor(SenseDeviceEntity, SensorEntity):
def native_value(self) -> float:
"""Return the state of the sensor."""
return self._device.power_w
class SenseDeviceEnergySensor(SenseDeviceEntity, SensorEntity):
"""Implementation of a Sense device energy sensor."""
_attr_native_unit_of_measurement = UnitOfEnergy.KILO_WATT_HOUR
_attr_state_class = SensorStateClass.TOTAL_INCREASING
_attr_device_class = SensorDeviceClass.ENERGY
def __init__(
self,
device: SenseDevice,
scale: Scale,
coordinator: SenseTrendCoordinator,
sense_monitor_id: str,
) -> None:
"""Initialize the Sense device sensor."""
super().__init__(
device,
coordinator,
sense_monitor_id,
f"{device.id}-{TRENDS_SENSOR_TYPES[scale].lower()}-energy",
)
self._attr_translation_key = f"{TRENDS_SENSOR_TYPES[scale].lower()}_energy"
self._attr_suggested_display_precision = 2
self._scale = scale
self._device = device
@property
def native_value(self) -> float:
"""Return the state of the sensor."""
return self._device.energy_kwh[self._scale]

View File

@ -32,5 +32,24 @@
"already_configured": "[%key:common::config_flow::abort::already_configured_device%]",
"reauth_successful": "[%key:common::config_flow::abort::reauth_successful%]"
}
},
"entity": {
"sensor": {
"daily_energy": {
"name": "Daily energy"
},
"weekly_energy": {
"name": "Weekly energy"
},
"monthly_energy": {
"name": "Monthly energy"
},
"yearly_energy": {
"name": "Yearly energy"
},
"bill_energy": {
"name": "Bill energy"
}
}
}
}

File diff suppressed because it is too large Load Diff

View File

@ -3,11 +3,12 @@
from datetime import timedelta
from unittest.mock import MagicMock, PropertyMock
from freezegun.api import FrozenDateTimeFactory
import pytest
from sense_energy import Scale
from syrupy.assertion import SnapshotAssertion
from homeassistant.components.sense.const import ACTIVE_UPDATE_RATE
from homeassistant.components.sense.const import ACTIVE_UPDATE_RATE, TREND_UPDATE_RATE
from homeassistant.components.sensor import DOMAIN as SENSOR_DOMAIN
from homeassistant.const import Platform
from homeassistant.core import HomeAssistant
@ -15,7 +16,14 @@ from homeassistant.helpers import entity_registry as er
from homeassistant.util.dt import utcnow
from . import setup_platform
from .const import DEVICE_1_NAME, DEVICE_2_NAME, DEVICE_2_POWER, MONITOR_ID
from .const import (
DEVICE_1_DAY_ENERGY,
DEVICE_1_NAME,
DEVICE_2_DAY_ENERGY,
DEVICE_2_NAME,
DEVICE_2_POWER,
MONITOR_ID,
)
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
@ -63,6 +71,47 @@ async def test_device_power_sensors(
assert state.state == f"{DEVICE_2_POWER:.1f}"
async def test_device_energy_sensors(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,
mock_sense: MagicMock,
config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test the Sense device power sensors."""
await setup_platform(hass, config_entry, SENSOR_DOMAIN)
device_1, device_2 = mock_sense.devices
state = hass.states.get(f"sensor.{DEVICE_1_NAME.lower()}_daily_energy")
assert state.state == f"{DEVICE_1_DAY_ENERGY:.0f}"
state = hass.states.get(f"sensor.{DEVICE_2_NAME.lower()}_daily_energy")
assert state.state == f"{DEVICE_2_DAY_ENERGY:.0f}"
device_1.energy_kwh[Scale.DAY] = 0
device_2.energy_kwh[Scale.DAY] = 0
freezer.tick(timedelta(seconds=TREND_UPDATE_RATE))
async_fire_time_changed(hass)
await hass.async_block_till_done()
state = hass.states.get(f"sensor.{DEVICE_1_NAME.lower()}_daily_energy")
assert state.state == "0"
state = hass.states.get(f"sensor.{DEVICE_2_NAME.lower()}_daily_energy")
assert state.state == "0"
device_2.energy_kwh[Scale.DAY] = DEVICE_1_DAY_ENERGY
freezer.tick(timedelta(seconds=TREND_UPDATE_RATE))
async_fire_time_changed(hass)
await hass.async_block_till_done()
state = hass.states.get(f"sensor.{DEVICE_1_NAME.lower()}_daily_energy")
assert state.state == "0"
state = hass.states.get(f"sensor.{DEVICE_2_NAME.lower()}_daily_energy")
assert state.state == f"{DEVICE_1_DAY_ENERGY:.0f}"
async def test_voltage_sensors(
hass: HomeAssistant,
entity_registry: er.EntityRegistry,