Add battery data to Autarco integration (#125924)

* Rename site to account_site

* Add battery service with entities

* Test UpdateFailed exception in coordinator

* Add battery data to diagnostics report

* Add TOTAL state_class where needed

* Fix

---------

Co-authored-by: Joostlek <joostlek@outlook.com>
This commit is contained in:
Klaas Schoute 2024-09-20 12:53:15 +02:00 committed by GitHub
parent 76967e848d
commit 184580257d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
8 changed files with 669 additions and 19 deletions

View File

@ -4,11 +4,19 @@ from __future__ import annotations
from typing import NamedTuple
from autarco import AccountSite, Autarco, Inverter, Solar
from autarco import (
AccountSite,
Autarco,
AutarcoConnectionError,
Battery,
Inverter,
Site,
Solar,
)
from homeassistant.config_entries import ConfigEntry
from homeassistant.core import HomeAssistant
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator
from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed
from .const import DOMAIN, LOGGER, SCAN_INTERVAL
@ -18,6 +26,8 @@ class AutarcoData(NamedTuple):
solar: Solar
inverters: dict[str, Inverter]
site: Site
battery: Battery | None
class AutarcoDataUpdateCoordinator(DataUpdateCoordinator[AutarcoData]):
@ -29,7 +39,7 @@ class AutarcoDataUpdateCoordinator(DataUpdateCoordinator[AutarcoData]):
self,
hass: HomeAssistant,
client: Autarco,
site: AccountSite,
account_site: AccountSite,
) -> None:
"""Initialize global Autarco data updater."""
super().__init__(
@ -39,11 +49,22 @@ class AutarcoDataUpdateCoordinator(DataUpdateCoordinator[AutarcoData]):
update_interval=SCAN_INTERVAL,
)
self.client = client
self.site = site
self.account_site = account_site
async def _async_update_data(self) -> AutarcoData:
"""Fetch data from Autarco API."""
battery = None
try:
site = await self.client.get_site(self.account_site.public_key)
solar = await self.client.get_solar(self.account_site.public_key)
inverters = await self.client.get_inverters(self.account_site.public_key)
if site.has_battery:
battery = await self.client.get_battery(self.account_site.public_key)
except AutarcoConnectionError as error:
raise UpdateFailed(error) from error
return AutarcoData(
solar=await self.client.get_solar(self.site.public_key),
inverters=await self.client.get_inverters(self.site.public_key),
solar=solar,
inverters=inverters,
site=site,
battery=battery,
)

View File

@ -18,9 +18,9 @@ async def async_get_config_entry_diagnostics(
return {
"sites_data": [
{
"id": coordinator.site.site_id,
"name": coordinator.site.system_name,
"health": coordinator.site.health,
"id": coordinator.account_site.site_id,
"name": coordinator.account_site.system_name,
"health": coordinator.account_site.health,
"solar": {
"power_production": coordinator.data.solar.power_production,
"energy_production_today": coordinator.data.solar.energy_production_today,
@ -37,6 +37,23 @@ async def async_get_config_entry_diagnostics(
}
for inverter in coordinator.data.inverters.values()
],
**(
{
"battery": {
"flow_now": coordinator.data.battery.flow_now,
"net_charged_now": coordinator.data.battery.net_charged_now,
"state_of_charge": coordinator.data.battery.state_of_charge,
"discharged_today": coordinator.data.battery.discharged_today,
"discharged_month": coordinator.data.battery.discharged_month,
"discharged_total": coordinator.data.battery.discharged_total,
"charged_today": coordinator.data.battery.charged_today,
"charged_month": coordinator.data.battery.charged_month,
"charged_total": coordinator.data.battery.charged_total,
}
}
if coordinator.data.battery is not None
else {}
),
}
for coordinator in autarco_data
],

View File

@ -5,7 +5,7 @@ from __future__ import annotations
from collections.abc import Callable
from dataclasses import dataclass
from autarco import Inverter, Solar
from autarco import Battery, Inverter, Solar
from homeassistant.components.sensor import (
SensorDeviceClass,
@ -13,7 +13,7 @@ from homeassistant.components.sensor import (
SensorEntityDescription,
SensorStateClass,
)
from homeassistant.const import UnitOfEnergy, UnitOfPower
from homeassistant.const import PERCENTAGE, UnitOfEnergy, UnitOfPower
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceEntryType, DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
@ -25,6 +25,81 @@ from .const import DOMAIN
from .coordinator import AutarcoDataUpdateCoordinator
@dataclass(frozen=True, kw_only=True)
class AutarcoBatterySensorEntityDescription(SensorEntityDescription):
"""Describes an Autarco sensor entity."""
value_fn: Callable[[Battery], StateType]
SENSORS_BATTERY: tuple[AutarcoBatterySensorEntityDescription, ...] = (
AutarcoBatterySensorEntityDescription(
key="flow_now",
translation_key="flow_now",
native_unit_of_measurement=UnitOfPower.WATT,
device_class=SensorDeviceClass.POWER,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda battery: battery.flow_now,
),
AutarcoBatterySensorEntityDescription(
key="state_of_charge",
translation_key="state_of_charge",
native_unit_of_measurement=PERCENTAGE,
device_class=SensorDeviceClass.BATTERY,
state_class=SensorStateClass.MEASUREMENT,
value_fn=lambda battery: battery.state_of_charge,
),
AutarcoBatterySensorEntityDescription(
key="discharged_today",
translation_key="discharged_today",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL,
value_fn=lambda battery: battery.discharged_today,
),
AutarcoBatterySensorEntityDescription(
key="discharged_month",
translation_key="discharged_month",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL,
value_fn=lambda battery: battery.discharged_month,
),
AutarcoBatterySensorEntityDescription(
key="discharged_total",
translation_key="discharged_total",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda battery: battery.discharged_total,
),
AutarcoBatterySensorEntityDescription(
key="charged_today",
translation_key="charged_today",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL,
value_fn=lambda battery: battery.charged_today,
),
AutarcoBatterySensorEntityDescription(
key="charged_month",
translation_key="charged_month",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL,
value_fn=lambda battery: battery.charged_month,
),
AutarcoBatterySensorEntityDescription(
key="charged_total",
translation_key="charged_total",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL_INCREASING,
value_fn=lambda battery: battery.charged_total,
),
)
@dataclass(frozen=True, kw_only=True)
class AutarcoSolarSensorEntityDescription(SensorEntityDescription):
"""Describes an Autarco sensor entity."""
@ -46,6 +121,7 @@ SENSORS_SOLAR: tuple[AutarcoSolarSensorEntityDescription, ...] = (
translation_key="energy_production_today",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL,
value_fn=lambda solar: solar.energy_production_today,
),
AutarcoSolarSensorEntityDescription(
@ -53,6 +129,7 @@ SENSORS_SOLAR: tuple[AutarcoSolarSensorEntityDescription, ...] = (
translation_key="energy_production_month",
native_unit_of_measurement=UnitOfEnergy.KILO_WATT_HOUR,
device_class=SensorDeviceClass.ENERGY,
state_class=SensorStateClass.TOTAL,
value_fn=lambda solar: solar.energy_production_month,
),
AutarcoSolarSensorEntityDescription(
@ -117,9 +194,52 @@ async def async_setup_entry(
for description in SENSORS_INVERTER
for inverter in coordinator.data.inverters
)
if coordinator.data.battery:
entities.extend(
AutarcoBatterySensorEntity(
coordinator=coordinator,
description=description,
)
for description in SENSORS_BATTERY
)
async_add_entities(entities)
class AutarcoBatterySensorEntity(
CoordinatorEntity[AutarcoDataUpdateCoordinator], SensorEntity
):
"""Defines an Autarco battery sensor."""
entity_description: AutarcoBatterySensorEntityDescription
_attr_has_entity_name = True
def __init__(
self,
*,
coordinator: AutarcoDataUpdateCoordinator,
description: AutarcoBatterySensorEntityDescription,
) -> None:
"""Initialize Autarco sensor."""
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = (
f"{coordinator.account_site.site_id}_battery_{description.key}"
)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{coordinator.account_site.site_id}_battery")},
entry_type=DeviceEntryType.SERVICE,
manufacturer="Autarco",
name="Battery",
)
@property
def native_value(self) -> StateType:
"""Return the state of the sensor."""
assert self.coordinator.data.battery is not None
return self.entity_description.value_fn(self.coordinator.data.battery)
class AutarcoSolarSensorEntity(
CoordinatorEntity[AutarcoDataUpdateCoordinator], SensorEntity
):
@ -138,9 +258,11 @@ class AutarcoSolarSensorEntity(
super().__init__(coordinator)
self.entity_description = description
self._attr_unique_id = f"{coordinator.site.site_id}_solar_{description.key}"
self._attr_unique_id = (
f"{coordinator.account_site.site_id}_solar_{description.key}"
)
self._attr_device_info = DeviceInfo(
identifiers={(DOMAIN, f"{coordinator.site.site_id}_solar")},
identifiers={(DOMAIN, f"{coordinator.account_site.site_id}_solar")},
entry_type=DeviceEntryType.SERVICE,
manufacturer="Autarco",
name="Solar",

View File

@ -23,6 +23,30 @@
},
"entity": {
"sensor": {
"flow_now": {
"name": "Flow now"
},
"state_of_charge": {
"name": "State of charge"
},
"discharged_today": {
"name": "Discharged today"
},
"discharged_month": {
"name": "Discharged month"
},
"discharged_total": {
"name": "Discharged total"
},
"charged_today": {
"name": "Charged today"
},
"charged_month": {
"name": "Charged month"
},
"charged_total": {
"name": "Charged total"
},
"power_production": {
"name": "Power production"
},

View File

@ -3,7 +3,7 @@
from collections.abc import Generator
from unittest.mock import AsyncMock, patch
from autarco import AccountSite, Inverter, Solar
from autarco import AccountSite, Battery, Inverter, Solar
import pytest
from homeassistant.components.autarco.const import DOMAIN
@ -66,6 +66,17 @@ def mock_autarco_client() -> Generator[AsyncMock]:
health="OK",
),
}
client.get_battery.return_value = Battery(
flow_now=777,
net_charged_now=777,
state_of_charge=56,
discharged_today=2,
discharged_month=25,
discharged_total=696,
charged_today=1,
charged_month=26,
charged_total=748,
)
yield client

View File

@ -3,6 +3,17 @@
dict({
'sites_data': list([
dict({
'battery': dict({
'charged_month': 26,
'charged_today': 1,
'charged_total': 748,
'discharged_month': 25,
'discharged_today': 2,
'discharged_total': 696,
'flow_now': 777,
'net_charged_now': 777,
'state_of_charge': 56,
}),
'health': 'OK',
'id': 1,
'inverters': list([

View File

@ -1,4 +1,412 @@
# serializer version: 1
# name: test_all_sensors[sensor.battery_charged_month-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.battery_charged_month',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Charged month',
'platform': 'autarco',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charged_month',
'unique_id': '1_battery_charged_month',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_all_sensors[sensor.battery_charged_month-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Battery Charged month',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.battery_charged_month',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '26',
})
# ---
# name: test_all_sensors[sensor.battery_charged_today-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.battery_charged_today',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Charged today',
'platform': 'autarco',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charged_today',
'unique_id': '1_battery_charged_today',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_all_sensors[sensor.battery_charged_today-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Battery Charged today',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.battery_charged_today',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '1',
})
# ---
# name: test_all_sensors[sensor.battery_charged_total-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.battery_charged_total',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Charged total',
'platform': 'autarco',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'charged_total',
'unique_id': '1_battery_charged_total',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_all_sensors[sensor.battery_charged_total-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Battery Charged total',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.battery_charged_total',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '748',
})
# ---
# name: test_all_sensors[sensor.battery_discharged_month-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.battery_discharged_month',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Discharged month',
'platform': 'autarco',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'discharged_month',
'unique_id': '1_battery_discharged_month',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_all_sensors[sensor.battery_discharged_month-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Battery Discharged month',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.battery_discharged_month',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '25',
})
# ---
# name: test_all_sensors[sensor.battery_discharged_today-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.battery_discharged_today',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Discharged today',
'platform': 'autarco',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'discharged_today',
'unique_id': '1_battery_discharged_today',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_all_sensors[sensor.battery_discharged_today-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Battery Discharged today',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.battery_discharged_today',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '2',
})
# ---
# name: test_all_sensors[sensor.battery_discharged_total-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.battery_discharged_total',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.ENERGY: 'energy'>,
'original_icon': None,
'original_name': 'Discharged total',
'platform': 'autarco',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'discharged_total',
'unique_id': '1_battery_discharged_total',
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
})
# ---
# name: test_all_sensors[sensor.battery_discharged_total-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Battery Discharged total',
'state_class': <SensorStateClass.TOTAL_INCREASING: 'total_increasing'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
'entity_id': 'sensor.battery_discharged_total',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '696',
})
# ---
# name: test_all_sensors[sensor.battery_flow_now-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.battery_flow_now',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.POWER: 'power'>,
'original_icon': None,
'original_name': 'Flow now',
'platform': 'autarco',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'flow_now',
'unique_id': '1_battery_flow_now',
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
})
# ---
# name: test_all_sensors[sensor.battery_flow_now-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'power',
'friendly_name': 'Battery Flow now',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': <UnitOfPower.WATT: 'W'>,
}),
'context': <ANY>,
'entity_id': 'sensor.battery_flow_now',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '777',
})
# ---
# name: test_all_sensors[sensor.battery_state_of_charge-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
}),
'area_id': None,
'capabilities': dict({
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
'disabled_by': None,
'domain': 'sensor',
'entity_category': None,
'entity_id': 'sensor.battery_state_of_charge',
'has_entity_name': True,
'hidden_by': None,
'icon': None,
'id': <ANY>,
'labels': set({
}),
'name': None,
'options': dict({
}),
'original_device_class': <SensorDeviceClass.BATTERY: 'battery'>,
'original_icon': None,
'original_name': 'State of charge',
'platform': 'autarco',
'previous_unique_id': None,
'supported_features': 0,
'translation_key': 'state_of_charge',
'unique_id': '1_battery_state_of_charge',
'unit_of_measurement': '%',
})
# ---
# name: test_all_sensors[sensor.battery_state_of_charge-state]
StateSnapshot({
'attributes': ReadOnlyDict({
'device_class': 'battery',
'friendly_name': 'Battery State of charge',
'state_class': <SensorStateClass.MEASUREMENT: 'measurement'>,
'unit_of_measurement': '%',
}),
'context': <ANY>,
'entity_id': 'sensor.battery_state_of_charge',
'last_changed': <ANY>,
'last_reported': <ANY>,
'last_updated': <ANY>,
'state': '56',
})
# ---
# name: test_all_sensors[sensor.inverter_test_serial_1_energy_ac_output_total-entry]
EntityRegistryEntrySnapshot({
'aliases': set({
@ -208,7 +616,9 @@
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
@ -241,6 +651,7 @@
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Solar Energy production month',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,
@ -256,7 +667,9 @@
'aliases': set({
}),
'area_id': None,
'capabilities': None,
'capabilities': dict({
'state_class': <SensorStateClass.TOTAL: 'total'>,
}),
'config_entry_id': <ANY>,
'device_class': None,
'device_id': <ANY>,
@ -289,6 +702,7 @@
'attributes': ReadOnlyDict({
'device_class': 'energy',
'friendly_name': 'Solar Energy production today',
'state_class': <SensorStateClass.TOTAL: 'total'>,
'unit_of_measurement': <UnitOfEnergy.KILO_WATT_HOUR: 'kWh'>,
}),
'context': <ANY>,

View File

@ -1,16 +1,20 @@
"""Test the sensor provided by the Autarco integration."""
from unittest.mock import MagicMock, patch
from datetime import timedelta
from unittest.mock import AsyncMock, MagicMock, patch
from autarco import AutarcoConnectionError
from freezegun.api import FrozenDateTimeFactory
from syrupy import SnapshotAssertion
from homeassistant.const import Platform
from homeassistant.config_entries import ConfigEntryState
from homeassistant.const import STATE_UNAVAILABLE, Platform
from homeassistant.core import HomeAssistant
from homeassistant.helpers import entity_registry as er
from . import setup_integration
from tests.common import MockConfigEntry, snapshot_platform
from tests.common import MockConfigEntry, async_fire_time_changed, snapshot_platform
async def test_all_sensors(
@ -25,3 +29,29 @@ async def test_all_sensors(
await setup_integration(hass, mock_config_entry)
await snapshot_platform(hass, entity_registry, snapshot, mock_config_entry.entry_id)
async def test_update_failed(
hass: HomeAssistant,
mock_autarco_client: AsyncMock,
mock_config_entry: MockConfigEntry,
freezer: FrozenDateTimeFactory,
) -> None:
"""Test entities become unavailable after failed update."""
await setup_integration(hass, mock_config_entry)
assert mock_config_entry.state is ConfigEntryState.LOADED
assert (
hass.states.get("sensor.inverter_test_serial_1_energy_ac_output_total").state
is not None
)
mock_autarco_client.get_solar.side_effect = AutarcoConnectionError
freezer.tick(timedelta(minutes=5))
async_fire_time_changed(hass)
await hass.async_block_till_done()
assert (
hass.states.get("sensor.inverter_test_serial_1_energy_ac_output_total").state
== STATE_UNAVAILABLE
)