Avoid mutating entity descriptions in sunweg (#105982)

This commit is contained in:
Erik Montnemery 2023-12-18 21:03:40 +01:00 committed by GitHub
parent 27f81b3f63
commit 1d1cd6be57
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 105 additions and 72 deletions

View File

@ -10,11 +10,10 @@ from homeassistant import config_entries
from homeassistant.config_entries import ConfigEntry
from homeassistant.const import CONF_PASSWORD, CONF_USERNAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers.typing import StateType
from homeassistant.helpers.typing import StateType, UndefinedType
from homeassistant.util import Throttle
from .const import CONF_PLANT_ID, DOMAIN, PLATFORMS, DeviceType
from .sensor_types.sensor_entity_description import SunWEGSensorEntityDescription
SCAN_INTERVAL = datetime.timedelta(minutes=5)
@ -102,24 +101,30 @@ class SunWEGData:
def get_data(
self,
entity_description: SunWEGSensorEntityDescription,
*,
api_variable_key: str,
api_variable_unit: str | None,
deep_name: str | None,
device_type: DeviceType,
inverter_id: int = 0,
deep_name: str | None = None,
) -> StateType | datetime.datetime:
inverter_id: int,
name: str | UndefinedType | None,
native_unit_of_measurement: str | None,
never_resets: bool,
previous_value_drop_threshold: float | None,
) -> tuple[StateType | datetime.datetime, str | None]:
"""Get the data."""
_LOGGER.debug(
"Data request for: %s",
entity_description.name,
name,
)
variable = entity_description.api_variable_key
previous_unit = entity_description.native_unit_of_measurement
variable = api_variable_key
previous_unit = native_unit_of_measurement
api_value = self.get_api_value(variable, device_type, inverter_id, deep_name)
previous_value = self.previous_values.get(variable)
return_value = api_value
if entity_description.api_variable_unit is not None:
entity_description.native_unit_of_measurement = self.get_api_value(
entity_description.api_variable_unit,
if api_variable_unit is not None:
native_unit_of_measurement = self.get_api_value(
api_variable_unit,
device_type,
inverter_id,
deep_name,
@ -127,18 +132,18 @@ class SunWEGData:
# If we have a 'drop threshold' specified, then check it and correct if needed
if (
entity_description.previous_value_drop_threshold is not None
previous_value_drop_threshold is not None
and previous_value is not None
and api_value is not None
and previous_unit == entity_description.native_unit_of_measurement
and previous_unit == native_unit_of_measurement
):
_LOGGER.debug(
(
"%s - Drop threshold specified (%s), checking for drop... API"
" Value: %s, Previous Value: %s"
),
entity_description.name,
entity_description.previous_value_drop_threshold,
name,
previous_value_drop_threshold,
api_value,
previous_value,
)
@ -149,7 +154,7 @@ class SunWEGData:
# Note - The energy dashboard takes care of drops within 10%
# of the current value, however if the value is low e.g. 0.2
# and drops by 0.1 it classes as a reset.
if -(entity_description.previous_value_drop_threshold) <= diff < 0:
if -(previous_value_drop_threshold) <= diff < 0:
_LOGGER.debug(
(
"Diff is negative, but only by a small amount therefore not a"
@ -161,9 +166,7 @@ class SunWEGData:
)
return_value = previous_value
else:
_LOGGER.debug(
"%s - No drop detected, using API value", entity_description.name
)
_LOGGER.debug("%s - No drop detected, using API value", name)
# Lifetime total values should always be increasing, they will never reset,
# however the API sometimes returns 0 values when the clock turns to 00:00
@ -178,7 +181,7 @@ class SunWEGData:
# - Previous value will not exist meaning 0 will be returned
# - This is an edge case that would be better handled by looking
# up the previous value of the entity from the recorder
if entity_description.never_resets and api_value == 0 and previous_value:
if never_resets and api_value == 0 and previous_value:
_LOGGER.debug(
(
"API value is 0, but this value should never reset, returning"
@ -190,4 +193,4 @@ class SunWEGData:
self.previous_values[variable] = return_value
return return_value
return (return_value, native_unit_of_measurement)

View File

@ -1,7 +1,6 @@
"""Read status of SunWEG inverters."""
from __future__ import annotations
import datetime
import logging
from types import MappingProxyType
from typing import Any
@ -16,7 +15,6 @@ from homeassistant.const import CONF_NAME
from homeassistant.core import HomeAssistant
from homeassistant.helpers.device_registry import DeviceInfo
from homeassistant.helpers.entity_platform import AddEntitiesCallback
from homeassistant.helpers.typing import StateType
from . import SunWEGData
from .const import CONF_PLANT_ID, DEFAULT_PLANT_ID, DOMAIN, DeviceType
@ -160,18 +158,20 @@ class SunWEGInverter(SensorEntity):
name=name,
)
@property
def native_value(
self,
) -> StateType | datetime.datetime:
"""Return the state of the sensor."""
return self.probe.get_data(
self.entity_description,
device_type=self.device_type,
inverter_id=self.inverter_id,
deep_name=self.deep_name,
)
def update(self) -> None:
"""Get the latest data from the Sun WEG API and updates the state."""
self.probe.update()
(
self._attr_native_value,
self._attr_native_unit_of_measurement,
) = self.probe.get_data(
api_variable_key=self.entity_description.api_variable_key,
api_variable_unit=self.entity_description.api_variable_unit,
deep_name=self.deep_name,
device_type=self.device_type,
inverter_id=self.inverter_id,
name=self.entity_description.name,
native_unit_of_measurement=self.native_unit_of_measurement,
never_resets=self.entity_description.never_resets,
previous_value_drop_threshold=self.entity_description.previous_value_drop_threshold,
)

View File

@ -95,26 +95,41 @@ async def test_sunwegdata_get_data_drop_threshold() -> None:
)
entity_description.previous_value_drop_threshold = 0.1
data.get_api_value.return_value = 3.0
assert (
data.get_data(
entity_description=entity_description, device_type=DeviceType.TOTAL
)
== 3.0
)
assert data.get_data(
api_variable_key=entity_description.api_variable_key,
api_variable_unit=entity_description.api_variable_unit,
deep_name=None,
device_type=DeviceType.TOTAL,
inverter_id=0,
name=entity_description.name,
native_unit_of_measurement=entity_description.native_unit_of_measurement,
never_resets=entity_description.never_resets,
previous_value_drop_threshold=entity_description.previous_value_drop_threshold,
) == (3.0, None)
data.get_api_value.return_value = 2.91
assert (
data.get_data(
entity_description=entity_description, device_type=DeviceType.TOTAL
)
== 3.0
)
assert data.get_data(
api_variable_key=entity_description.api_variable_key,
api_variable_unit=entity_description.api_variable_unit,
deep_name=None,
device_type=DeviceType.TOTAL,
inverter_id=0,
name=entity_description.name,
native_unit_of_measurement=entity_description.native_unit_of_measurement,
never_resets=entity_description.never_resets,
previous_value_drop_threshold=entity_description.previous_value_drop_threshold,
) == (3.0, None)
data.get_api_value.return_value = 2.8
assert (
data.get_data(
entity_description=entity_description, device_type=DeviceType.TOTAL
)
== 2.8
)
assert data.get_data(
api_variable_key=entity_description.api_variable_key,
api_variable_unit=entity_description.api_variable_unit,
deep_name=None,
device_type=DeviceType.TOTAL,
inverter_id=0,
name=entity_description.name,
native_unit_of_measurement=entity_description.native_unit_of_measurement,
never_resets=entity_description.never_resets,
previous_value_drop_threshold=entity_description.previous_value_drop_threshold,
) == (2.8, None)
async def test_sunwegdata_get_data_never_reset() -> None:
@ -127,23 +142,38 @@ async def test_sunwegdata_get_data_never_reset() -> None:
)
entity_description.never_resets = True
data.get_api_value.return_value = 3.0
assert (
data.get_data(
entity_description=entity_description, device_type=DeviceType.TOTAL
)
== 3.0
)
assert data.get_data(
api_variable_key=entity_description.api_variable_key,
api_variable_unit=entity_description.api_variable_unit,
deep_name=None,
device_type=DeviceType.TOTAL,
inverter_id=0,
name=entity_description.name,
native_unit_of_measurement=entity_description.native_unit_of_measurement,
never_resets=entity_description.never_resets,
previous_value_drop_threshold=entity_description.previous_value_drop_threshold,
) == (3.0, None)
data.get_api_value.return_value = 0
assert (
data.get_data(
entity_description=entity_description, device_type=DeviceType.TOTAL
)
== 3.0
)
assert data.get_data(
api_variable_key=entity_description.api_variable_key,
api_variable_unit=entity_description.api_variable_unit,
deep_name=None,
device_type=DeviceType.TOTAL,
inverter_id=0,
name=entity_description.name,
native_unit_of_measurement=entity_description.native_unit_of_measurement,
never_resets=entity_description.never_resets,
previous_value_drop_threshold=entity_description.previous_value_drop_threshold,
) == (3.0, None)
data.get_api_value.return_value = 2.8
assert (
data.get_data(
entity_description=entity_description, device_type=DeviceType.TOTAL
)
== 2.8
)
assert data.get_data(
api_variable_key=entity_description.api_variable_key,
api_variable_unit=entity_description.api_variable_unit,
deep_name=None,
device_type=DeviceType.TOTAL,
inverter_id=0,
name=entity_description.name,
native_unit_of_measurement=entity_description.native_unit_of_measurement,
never_resets=entity_description.never_resets,
previous_value_drop_threshold=entity_description.previous_value_drop_threshold,
) == (2.8, None)