From d077c3b8d106e7e102a5a58a8a07ed381ff06567 Mon Sep 17 00:00:00 2001 From: Matt Zimmerman Date: Mon, 28 Feb 2022 11:31:34 -0800 Subject: [PATCH] Add sensor to expose Powerwall backup reserve percentage (#66393) --- .../components/powerwall/__init__.py | 1 + homeassistant/components/powerwall/models.py | 1 + homeassistant/components/powerwall/sensor.py | 25 ++++++++++++++++++- tests/components/powerwall/mocks.py | 5 ++++ tests/components/powerwall/test_sensor.py | 12 +++++++++ 5 files changed, 43 insertions(+), 1 deletion(-) diff --git a/homeassistant/components/powerwall/__init__.py b/homeassistant/components/powerwall/__init__.py index 10504e2aa06..d2850330b7a 100644 --- a/homeassistant/components/powerwall/__init__.py +++ b/homeassistant/components/powerwall/__init__.py @@ -229,6 +229,7 @@ def _fetch_powerwall_data(power_wall: Powerwall) -> PowerwallData: meters=power_wall.get_meters(), grid_services_active=power_wall.is_grid_services_active(), grid_status=power_wall.get_grid_status(), + backup_reserve=power_wall.get_backup_reserve_percentage(), ) diff --git a/homeassistant/components/powerwall/models.py b/homeassistant/components/powerwall/models.py index 472d9e59304..cb9b84be16a 100644 --- a/homeassistant/components/powerwall/models.py +++ b/homeassistant/components/powerwall/models.py @@ -38,6 +38,7 @@ class PowerwallData: meters: MetersAggregates grid_services_active: bool grid_status: GridStatus + backup_reserve: float class PowerwallRuntimeData(TypedDict): diff --git a/homeassistant/components/powerwall/sensor.py b/homeassistant/components/powerwall/sensor.py index bc8ab1c0215..9efa5f380dd 100644 --- a/homeassistant/components/powerwall/sensor.py +++ b/homeassistant/components/powerwall/sensor.py @@ -45,7 +45,11 @@ async def async_setup_entry( | PowerWallImportSensor | PowerWallExportSensor | PowerWallChargeSensor - ] = [PowerWallChargeSensor(powerwall_data)] + | PowerWallBackupReserveSensor + ] = [ + PowerWallChargeSensor(powerwall_data), + PowerWallBackupReserveSensor(powerwall_data), + ] for meter in data.meters.meters: entities.extend( @@ -111,6 +115,25 @@ class PowerWallEnergySensor(PowerWallEntity, SensorEntity): } +class PowerWallBackupReserveSensor(PowerWallEntity, SensorEntity): + """Representation of the Powerwall backup reserve setting.""" + + _attr_name = "Powerwall Backup Reserve" + _attr_state_class = SensorStateClass.MEASUREMENT + _attr_native_unit_of_measurement = PERCENTAGE + _attr_device_class = SensorDeviceClass.BATTERY + + @property + def unique_id(self) -> str: + """Device Uniqueid.""" + return f"{self.base_unique_id}_backup_reserve" + + @property + def native_value(self) -> int: + """Get the current value in percentage.""" + return round(self.data.backup_reserve) + + class PowerWallEnergyDirectionSensor(PowerWallEntity, SensorEntity): """Representation of an Powerwall Direction Energy sensor.""" diff --git a/tests/components/powerwall/mocks.py b/tests/components/powerwall/mocks.py index 1eac0319819..ae6601b0215 100644 --- a/tests/components/powerwall/mocks.py +++ b/tests/components/powerwall/mocks.py @@ -37,6 +37,7 @@ async def _mock_powerwall_with_fixtures(hass): status=PowerwallStatus(status), device_type=DeviceType(device_type["device_type"]), serial_numbers=["TG0123456789AB", "TG9876543210BA"], + backup_reserve_percentage=15.0, ) @@ -50,6 +51,7 @@ def _mock_powerwall_return_value( status=None, device_type=None, serial_numbers=None, + backup_reserve_percentage=None, ): powerwall_mock = MagicMock(Powerwall("1.2.3.4")) powerwall_mock.get_site_info = Mock(return_value=site_info) @@ -60,6 +62,9 @@ def _mock_powerwall_return_value( powerwall_mock.get_status = Mock(return_value=status) powerwall_mock.get_device_type = Mock(return_value=device_type) powerwall_mock.get_serial_numbers = Mock(return_value=serial_numbers) + powerwall_mock.get_backup_reserve_percentage = Mock( + return_value=backup_reserve_percentage + ) powerwall_mock.is_grid_services_active = Mock(return_value=grid_services_active) return powerwall_mock diff --git a/tests/components/powerwall/test_sensor.py b/tests/components/powerwall/test_sensor.py index 33c186e922c..9ff5bd19e39 100644 --- a/tests/components/powerwall/test_sensor.py +++ b/tests/components/powerwall/test_sensor.py @@ -121,3 +121,15 @@ async def test_sensors(hass): # HA changes the implementation and a new one appears for key, value in expected_attributes.items(): assert state.attributes[key] == value + + state = hass.states.get("sensor.powerwall_backup_reserve") + assert state.state == "15" + expected_attributes = { + "unit_of_measurement": PERCENTAGE, + "friendly_name": "Powerwall Backup Reserve", + "device_class": "battery", + } + # Only test for a subset of attributes in case + # HA changes the implementation and a new one appears + for key, value in expected_attributes.items(): + assert state.attributes[key] == value