From 25f3cdde50dad6f5c536b02a42b8c3470475e7c9 Mon Sep 17 00:00:00 2001 From: "J. Nick Koston" Date: Mon, 9 Aug 2021 18:03:22 -0500 Subject: [PATCH] Add powerwall import and export sensors (#54018) Co-authored-by: Bram Kragten --- homeassistant/components/powerwall/const.py | 2 - homeassistant/components/powerwall/sensor.py | 64 ++++++++++++++++++-- tests/components/powerwall/test_sensor.py | 23 ++++--- 3 files changed, 75 insertions(+), 14 deletions(-) diff --git a/homeassistant/components/powerwall/const.py b/homeassistant/components/powerwall/const.py index c86333cb9f8..b2cd48df276 100644 --- a/homeassistant/components/powerwall/const.py +++ b/homeassistant/components/powerwall/const.py @@ -9,8 +9,6 @@ POWERWALL_API_CHANGED = "api_changed" UPDATE_INTERVAL = 30 ATTR_FREQUENCY = "frequency" -ATTR_ENERGY_EXPORTED = "energy_exported_(in_kW)" -ATTR_ENERGY_IMPORTED = "energy_imported_(in_kW)" ATTR_INSTANT_AVERAGE_VOLTAGE = "instant_average_voltage" ATTR_INSTANT_TOTAL_CURRENT = "instant_total_current" ATTR_IS_ACTIVE = "is_active" diff --git a/homeassistant/components/powerwall/sensor.py b/homeassistant/components/powerwall/sensor.py index d536c776bf0..b2281c515ae 100644 --- a/homeassistant/components/powerwall/sensor.py +++ b/homeassistant/components/powerwall/sensor.py @@ -6,14 +6,15 @@ from tesla_powerwall import MeterType from homeassistant.components.sensor import STATE_CLASS_MEASUREMENT, SensorEntity from homeassistant.const import ( DEVICE_CLASS_BATTERY, + DEVICE_CLASS_ENERGY, DEVICE_CLASS_POWER, + ENERGY_KILO_WATT_HOUR, PERCENTAGE, POWER_KILO_WATT, ) +import homeassistant.util.dt as dt_util from .const import ( - ATTR_ENERGY_EXPORTED, - ATTR_ENERGY_IMPORTED, ATTR_FREQUENCY, ATTR_INSTANT_AVERAGE_VOLTAGE, ATTR_INSTANT_TOTAL_CURRENT, @@ -29,6 +30,11 @@ from .const import ( ) from .entity import PowerWallEntity +_METER_DIRECTION_EXPORT = "export" +_METER_DIRECTION_IMPORT = "import" +_METER_DIRECTIONS = [_METER_DIRECTION_EXPORT, _METER_DIRECTION_IMPORT] + + _LOGGER = logging.getLogger(__name__) @@ -55,6 +61,18 @@ async def async_setup_entry(hass, config_entry, async_add_entities): powerwalls_serial_numbers, ) ) + for meter_direction in _METER_DIRECTIONS: + entities.append( + PowerWallEnergyDirectionSensor( + meter, + coordinator, + site_info, + status, + device_type, + powerwalls_serial_numbers, + meter_direction, + ) + ) entities.append( PowerWallChargeSensor( @@ -124,9 +142,47 @@ class PowerWallEnergySensor(PowerWallEntity, SensorEntity): meter = self.coordinator.data[POWERWALL_API_METERS].get_meter(self._meter) return { ATTR_FREQUENCY: round(meter.frequency, 1), - ATTR_ENERGY_EXPORTED: meter.get_energy_exported(), - ATTR_ENERGY_IMPORTED: meter.get_energy_imported(), ATTR_INSTANT_AVERAGE_VOLTAGE: round(meter.average_voltage, 1), ATTR_INSTANT_TOTAL_CURRENT: meter.get_instant_total_current(), ATTR_IS_ACTIVE: meter.is_active(), } + + +class PowerWallEnergyDirectionSensor(PowerWallEntity, SensorEntity): + """Representation of an Powerwall Direction Energy sensor.""" + + _attr_state_class = STATE_CLASS_MEASUREMENT + _attr_unit_of_measurement = ENERGY_KILO_WATT_HOUR + _attr_device_class = DEVICE_CLASS_ENERGY + _attr_last_reset = dt_util.utc_from_timestamp(0) + + def __init__( + self, + meter: MeterType, + coordinator, + site_info, + status, + device_type, + powerwalls_serial_numbers, + meter_direction, + ): + """Initialize the sensor.""" + super().__init__( + coordinator, site_info, status, device_type, powerwalls_serial_numbers + ) + self._meter = meter + self._meter_direction = meter_direction + self._attr_name = ( + f"Powerwall {self._meter.value.title()} {self._meter_direction.title()}" + ) + self._attr_unique_id = ( + f"{self.base_unique_id}_{self._meter.value}_{self._meter_direction}" + ) + + @property + def state(self): + """Get the current value in kWh.""" + meter = self.coordinator.data[POWERWALL_API_METERS].get_meter(self._meter) + if self._meter_direction == _METER_DIRECTION_EXPORT: + return meter.get_energy_exported() + return meter.get_energy_imported() diff --git a/tests/components/powerwall/test_sensor.py b/tests/components/powerwall/test_sensor.py index 32c7da9c78e..33c186e922c 100644 --- a/tests/components/powerwall/test_sensor.py +++ b/tests/components/powerwall/test_sensor.py @@ -39,8 +39,6 @@ async def test_sensors(hass): assert state.state == "0.032" expected_attributes = { "frequency": 60, - "energy_exported_(in_kW)": 10429.5, - "energy_imported_(in_kW)": 4824.2, "instant_average_voltage": 120.7, "unit_of_measurement": "kW", "friendly_name": "Powerwall Site Now", @@ -52,12 +50,16 @@ async def test_sensors(hass): for key, value in expected_attributes.items(): assert state.attributes[key] == value + assert float(hass.states.get("sensor.powerwall_site_export").state) == 10429.5 + assert float(hass.states.get("sensor.powerwall_site_import").state) == 4824.2 + + export_attributes = hass.states.get("sensor.powerwall_site_export").attributes + assert export_attributes["unit_of_measurement"] == "kWh" + state = hass.states.get("sensor.powerwall_load_now") assert state.state == "1.971" expected_attributes = { "frequency": 60, - "energy_exported_(in_kW)": 1056.8, - "energy_imported_(in_kW)": 4693.0, "instant_average_voltage": 120.7, "unit_of_measurement": "kW", "friendly_name": "Powerwall Load Now", @@ -69,12 +71,13 @@ async def test_sensors(hass): for key, value in expected_attributes.items(): assert state.attributes[key] == value + assert float(hass.states.get("sensor.powerwall_load_export").state) == 1056.8 + assert float(hass.states.get("sensor.powerwall_load_import").state) == 4693.0 + state = hass.states.get("sensor.powerwall_battery_now") assert state.state == "-8.55" expected_attributes = { "frequency": 60.0, - "energy_exported_(in_kW)": 3620.0, - "energy_imported_(in_kW)": 4216.2, "instant_average_voltage": 240.6, "unit_of_measurement": "kW", "friendly_name": "Powerwall Battery Now", @@ -86,12 +89,13 @@ async def test_sensors(hass): for key, value in expected_attributes.items(): assert state.attributes[key] == value + assert float(hass.states.get("sensor.powerwall_battery_export").state) == 3620.0 + assert float(hass.states.get("sensor.powerwall_battery_import").state) == 4216.2 + state = hass.states.get("sensor.powerwall_solar_now") assert state.state == "10.49" expected_attributes = { "frequency": 60, - "energy_exported_(in_kW)": 9864.2, - "energy_imported_(in_kW)": 28.2, "instant_average_voltage": 120.7, "unit_of_measurement": "kW", "friendly_name": "Powerwall Solar Now", @@ -103,6 +107,9 @@ async def test_sensors(hass): for key, value in expected_attributes.items(): assert state.attributes[key] == value + assert float(hass.states.get("sensor.powerwall_solar_export").state) == 9864.2 + assert float(hass.states.get("sensor.powerwall_solar_import").state) == 28.2 + state = hass.states.get("sensor.powerwall_charge") assert state.state == "47" expected_attributes = {