diff --git a/custom_components/victron/__init__.py b/custom_components/victron/__init__.py index 9672a6c..f533eba 100644 --- a/custom_components/victron/__init__.py +++ b/custom_components/victron/__init__.py @@ -2,12 +2,14 @@ from __future__ import annotations +from typing import Any + from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform from homeassistant.core import HomeAssistant from .const import CONF_HOST, CONF_INTERVAL, CONF_PORT, DOMAIN, SCAN_REGISTERS -from .coordinator import victronEnergyDeviceUpdateCoordinator as Coordinator +from .coordinator import VictronEnergyDeviceUpdateCoordinator as Coordinator PLATFORMS: list[Platform] = [ Platform.SENSOR, @@ -52,7 +54,7 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b return True -async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: +async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> Any: """Unload a config entry.""" if unload_ok := await hass.config_entries.async_unload_platforms( config_entry, PLATFORMS diff --git a/custom_components/victron/base.py b/custom_components/victron/base.py index 04722b9..922c97a 100644 --- a/custom_components/victron/base.py +++ b/custom_components/victron/base.py @@ -1,27 +1,27 @@ """Module defines entity descriptions for Victron components.""" from collections.abc import Callable -from dataclasses import dataclass +from typing import Any, dataclass_transform from homeassistant.helpers.entity import EntityDescription from homeassistant.helpers.typing import StateType -@dataclass -class VictronBaseEntityDescription(EntityDescription): +@dataclass_transform(frozen_default=True) +class VictronBaseEntityDescription(EntityDescription): # type: ignore[misc] """An extension of EntityDescription for Victron components.""" @staticmethod - def lambda_func(): + def lambda_func() -> Any: """Return an entitydescription.""" return lambda data, slave, key: data["data"][str(slave) + "." + str(key)] - slave: int = None + slave: int | None = None value_fn: Callable[[dict], StateType] = lambda_func() -@dataclass +@dataclass_transform(frozen_default=True) class VictronWriteBaseEntityDescription(VictronBaseEntityDescription): """An extension of VictronBaseEntityDescription for writeable Victron components.""" - address: int = None + address: float | None = None diff --git a/custom_components/victron/binary_sensor.py b/custom_components/victron/binary_sensor.py index 0cf2de8..09ff7f0 100644 --- a/custom_components/victron/binary_sensor.py +++ b/custom_components/victron/binary_sensor.py @@ -2,9 +2,8 @@ from __future__ import annotations -from dataclasses import dataclass import logging -from typing import cast +from typing import Any, cast, dataclass_transform from homeassistant.components.binary_sensor import ( DOMAIN as BINARY_SENSOR_DOMAIN, @@ -19,7 +18,7 @@ from .base import VictronBaseEntityDescription from .const import DOMAIN, BoolReadEntityType, register_info_dict -from .coordinator import victronEnergyDeviceUpdateCoordinator +from .coordinator import VictronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -31,7 +30,7 @@ async def async_setup_entry( ) -> None: """Set up Victron energy binary sensor entries.""" _LOGGER.debug("attempting to setup binary sensor entities") - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + victron_coordinator: VictronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ config_entry.entry_id ] _LOGGER.debug(victron_coordinator.processed_data()["register_set"]) @@ -39,16 +38,16 @@ async def async_setup_entry( descriptions = [] # TODO cleanup register_set = victron_coordinator.processed_data()["register_set"] - for slave, registerLedger in register_set.items(): - for name in registerLedger: - for register_name, registerInfo in register_info_dict[name].items(): + for slave, register_ledger in register_set.items(): + for name in register_ledger: + for register_name, register_info in register_info_dict[name].items(): _LOGGER.debug( - "unit == %s registerLedger == %s registerInfo", + "unit == %s register_ledger == %s register_info", slave, - registerLedger, + register_ledger, ) - if isinstance(registerInfo.entityType, BoolReadEntityType): + if isinstance(register_info.entity_type, BoolReadEntityType): description = VictronEntityDescription( key=register_name, name=register_name.replace("_", " "), @@ -57,28 +56,28 @@ async def async_setup_entry( _LOGGER.debug("composed description == %s", description) descriptions.append(description) - entities = [] - entity = {} - for description in descriptions: - entity = description - entities.append(VictronBinarySensor(victron_coordinator, entity)) + entities = [ + VictronBinarySensor(victron_coordinator, description) + for description in descriptions + ] async_add_entities(entities, True) -@dataclass +@dataclass_transform(frozen_default=True) class VictronEntityDescription( - BinarySensorEntityDescription, VictronBaseEntityDescription + BinarySensorEntityDescription, # type: ignore[misc] + VictronBaseEntityDescription, ): """Describes victron sensor entity.""" -class VictronBinarySensor(CoordinatorEntity, BinarySensorEntity): +class VictronBinarySensor(CoordinatorEntity, BinarySensorEntity): # type: ignore[misc] """A binary sensor implementation for Victron energy device.""" def __init__( self, - coordinator: victronEnergyDeviceUpdateCoordinator, + coordinator: VictronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription, ) -> None: """Initialize the binary sensor.""" @@ -102,14 +101,14 @@ def __init__( def is_on(self) -> bool: """Return True if the binary sensor is on.""" data = self.description.value_fn( - self.coordinator.processed_data(), + self.coordinator.processed_data(), # type: ignore[call-arg] self.description.slave, self.description.key, ) return cast(bool, data) @property - def available(self) -> bool: + def available(self) -> Any: """Return True if entity is available.""" full_key = str(self.description.slave) + "." + self.description.key return self.coordinator.processed_data()["availability"][full_key] @@ -120,6 +119,6 @@ def device_info(self) -> entity.DeviceInfo: return entity.DeviceInfo( identifiers={(DOMAIN, self.unique_id.split("_")[0])}, name=self.unique_id.split("_")[1], - model=self.unique_id.split("_")[0], + model=self.unique_id.split("_", maxsplit=1)[0], manufacturer="victron", ) diff --git a/custom_components/victron/button.py b/custom_components/victron/button.py index 84d71fc..6a5e7b5 100644 --- a/custom_components/victron/button.py +++ b/custom_components/victron/button.py @@ -2,8 +2,8 @@ from __future__ import annotations -from dataclasses import dataclass import logging +from typing import Any, dataclass_transform from homeassistant.components.button import ( DOMAIN as BUTTON_DOMAIN, @@ -19,7 +19,7 @@ from .base import VictronWriteBaseEntityDescription from .const import CONF_ADVANCED_OPTIONS, DOMAIN, ButtonWriteType, register_info_dict -from .coordinator import victronEnergyDeviceUpdateCoordinator +from .coordinator import VictronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -31,56 +31,56 @@ async def async_setup_entry( ) -> None: """Set up Victron energy binary sensor entries.""" _LOGGER.debug("attempting to setup button entities") - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + victron_coordinator: VictronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ config_entry.entry_id ] descriptions = [] # TODO cleanup register_set = victron_coordinator.processed_data()["register_set"] - for slave, registerLedger in register_set.items(): - for name in registerLedger: - for register_name, registerInfo in register_info_dict[name].items(): + for slave, register_ledger in register_set.items(): + for name in register_ledger: + for register_name, register_info in register_info_dict[name].items(): _LOGGER.debug( - "unit == %s registerLedger == %s registerInfo", + "unit == %s register_ledger == %s register_info", slave, - registerLedger, + register_ledger, ) if not config_entry.options[CONF_ADVANCED_OPTIONS]: continue - if isinstance(registerInfo.entityType, ButtonWriteType): + if isinstance(register_info.entity_type, ButtonWriteType): description = VictronEntityDescription( key=register_name, name=register_name.replace("_", " "), slave=slave, device_class=ButtonDeviceClass.RESTART, - address=registerInfo.register, + address=register_info.register, ) _LOGGER.debug("composed description == %s", description) descriptions.append(description) - entities = [] - entity = {} - for description in descriptions: - entity = description - entities.append(VictronBinarySensor(victron_coordinator, entity)) + entities = [ + VictronBinarySensor(victron_coordinator, description) + for description in descriptions + ] async_add_entities(entities, True) -@dataclass +@dataclass_transform(frozen_default=True) class VictronEntityDescription( - ButtonEntityDescription, VictronWriteBaseEntityDescription + ButtonEntityDescription, # type: ignore[misc] + VictronWriteBaseEntityDescription, ): """Describes victron sensor entity.""" -class VictronBinarySensor(CoordinatorEntity, ButtonEntity): +class VictronBinarySensor(CoordinatorEntity, ButtonEntity): # type: ignore[misc] """A button implementation for Victron energy device.""" def __init__( self, - coordinator: victronEnergyDeviceUpdateCoordinator, + coordinator: VictronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription, ) -> None: """Initialize the sensor.""" @@ -106,7 +106,7 @@ async def async_press(self) -> None: ) @property - def available(self) -> bool: + def available(self) -> Any: """Return True if entity available.""" full_key = str(self.description.slave) + "." + self.description.key return self.coordinator.processed_data()["availability"][full_key] @@ -117,6 +117,6 @@ def device_info(self) -> entity.DeviceInfo: return entity.DeviceInfo( identifiers={(DOMAIN, self.unique_id.split("_")[0])}, name=self.unique_id.split("_")[1], - model=self.unique_id.split("_")[0], + model=self.unique_id.split("_", maxsplit=1)[0], manufacturer="victron", ) diff --git a/custom_components/victron/config_flow.py b/custom_components/victron/config_flow.py index 0eabab3..c78910d 100644 --- a/custom_components/victron/config_flow.py +++ b/custom_components/victron/config_flow.py @@ -3,7 +3,7 @@ from __future__ import annotations import logging -from typing import Any +from typing import TYPE_CHECKING, Any import voluptuous as vol @@ -38,6 +38,10 @@ ) from .hub import VictronHub +if TYPE_CHECKING: + from homeassistant.data_entry_flow import _FlowResultT + + _LOGGER = logging.getLogger(__name__) CONF_RESCAN = "rescan" @@ -79,35 +83,34 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, return {"title": DOMAIN, "data": discovered_devices} -async def scan_connected_devices(hub: VictronHub) -> list: +async def scan_connected_devices(hub: VictronHub) -> Any: """Scan for connected devices.""" return hub.determine_present_devices() -class VictronFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): +@config_entries.HANDLERS.register(DOMAIN) +class VictronFlowHandler(config_entries.ConfigFlow): # type: ignore[misc] """Handle a config flow for victron.""" _LOGGER = logging.getLogger(__name__) VERSION = 1 - def __init__(self): + def __init__(self) -> None: """Initialize the config flow.""" - self.advanced_options = None - self.interval = None - self.port = None - self.host = None + self.advanced_options: Any | None = None + self.interval: int | None = None + self.port: int | None = None + self.host: str | None = None @staticmethod - @callback + @callback # type: ignore[misc] def async_get_options_flow( config_entry: ConfigEntry, ) -> VictronOptionFlowHandler: """Get the options flow for this handler.""" return VictronOptionFlowHandler(config_entry) - async def async_step_user( - self, user_input: dict[str, Any] | None = None - ) -> FlowResult: + async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Any: """Handle the initial step.""" if user_input is None: return self.async_show_form( @@ -135,6 +138,7 @@ async def async_step_user( already_configured = True if not already_configured: + info: dict[str, Any] try: info = await validate_input(self.hass, user_input) except CannotConnect: @@ -157,9 +161,15 @@ async def async_step_user( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors ) - async def async_step_advanced(self, user_input=None): - """Handle write support and limit settings if requested.""" - errors = {} + async def async_step_advanced( + self, user_input: dict[str, Any] | None = None + ) -> Any: + """Handle write support and limit settings if requested. + + :param user_input: + :return: + """ + errors: dict = {} if user_input is not None: if self.host is not None: @@ -240,8 +250,14 @@ async def async_step_advanced(self, user_input=None): ), ) - async def async_step_reconfigure(self, user_input: dict[str, Any] | None = None): - """Add reconfigure step to allow to reconfigure a config entry.""" + async def async_step_reconfigure( + self, user_input: dict[str, Any] | None = None + ) -> Any: + """Add reconfigure step to allow to reconfigure a config entry. + + :param user_input: + :return: + """ config_entry = self.hass.config_entries.async_get_entry( self.context["entry_id"] ) @@ -283,36 +299,47 @@ async def async_step_reconfigure(self, user_input: dict[str, Any] | None = None) ) -class parsedEntry: +class ParsedEntry: """Parsed entry.""" - def __init__(self, decoderInfo: RegisterInfo, value): + def __init__(self, decoderInfo: RegisterInfo, value: Any) -> None: """Initialize the parsed entry.""" self.decoderInfo = decoderInfo self.value = value -class VictronOptionFlowHandler(config_entries.OptionsFlow): +class VictronOptionFlowHandler(config_entries.OptionsFlow): # type: ignore[misc] """Handle options.""" logger = logging.getLogger(__name__) def __init__(self, config_entry: ConfigEntry) -> None: """Initialize options flow.""" - self.config_entry = config_entry + self.config_entry: ConfigEntry = config_entry self.area = None - async def async_step_advanced(self, user_input=None): - """Handle write support and limit settings if requested.""" + async def async_step_advanced( + self, user_input: dict[str, Any] | None = None + ) -> Any: + """Handle write support and limit settings if requested. + + :param user_input: + :return: + """ config = dict(self.config_entry.options) - user_input.pop(CONF_RESCAN, None) + if user_input: + user_input.pop(CONF_RESCAN, None) # combine dictionaries with priority given to user_input dict_priority = {1: user_input, 2: config} - combined_config = {**dict_priority[2], **dict_priority[1]} + combined_config = {**dict_priority[2], **dict_priority[1]} # type: ignore[dict-item] return self.async_create_entry(title="", data=combined_config) - async def async_step_init_read(self, user_input=None): - """Handle write support and limit settings if requested.""" + async def async_step_init_read(self, user_input: dict[str, Any]) -> Any: + """Handle write support and limit settings if requested. + + :param user_input: + :return: + """ config = dict(self.config_entry.options) # combine dictionaries with priority given to user_input if user_input[CONF_RESCAN]: @@ -330,13 +357,17 @@ async def async_step_init_read(self, user_input=None): self.config_entry, options=combined_config, title="" ) _LOGGER.debug("returning step init because advanced options were selected") - errors = {} + errors: dict = {} # move to dedicated function (the write show form) to allow for re-use return self.init_write_form(errors) return self.async_create_entry(title="", data=combined_config) - async def async_step_init_write(self, user_input=None): - """Handle write support and limit settings if requested.""" + async def async_step_init_write(self, user_input: dict[str, Any]) -> Any: + """Handle write support and limit settings if requested. + + :param user_input: + :return: + """ config = dict(self.config_entry.options) # remove temp options = if user_input[CONF_RESCAN]: @@ -355,17 +386,17 @@ async def async_step_init_write(self, user_input=None): self.config_entry, options=combined_config, title="" ) _LOGGER.debug("returning step init because advanced options were selected") - errors = {} + errors: dict = {} # move to dedicated function (the write show form) to allow for re-use return self.init_read_form(errors) return self.async_create_entry(title="", data=combined_config) async def async_step_init( - self, user_input: dict[str, Any] | None = None - ) -> FlowResult: + self, user_input: dict[str, Any] + ) -> FlowResult | Any | None: """Handle a flow initiated by the user.""" - errors = {} + errors: dict = {} config = dict(self.config_entry.options) @@ -394,7 +425,7 @@ async def async_step_init( return self.async_create_entry(title="", data=config) - if config[CONF_ADVANCED_OPTIONS]: + if config[CONF_ADVANCED_OPTIONS]: # type: ignore[unreachable] _LOGGER.debug("advanced options is set") return self.init_write_form(errors) @@ -402,7 +433,7 @@ async def async_step_init( return self.init_read_form(errors) return None - def init_read_form(self, errors: dict): + def init_read_form(self, errors: dict) -> _FlowResultT: """Handle read support and limit settings if requested.""" return self.async_show_form( step_id="init_read", @@ -418,7 +449,7 @@ def init_read_form(self, errors: dict): ), ) - def init_write_form(self, errors: dict): + def init_write_form(self, errors: dict) -> Any: """Handle write support and limit settings if requested.""" config = dict(self.config_entry.options) system_ac_voltage_default = self.config_entry.options.get( @@ -500,7 +531,7 @@ def init_write_form(self, errors: dict): ) @staticmethod - def get_dict_key(dict, val): + def get_dict_key(dict: dict, val: Any) -> Any: """Get the key from a dictionary.""" for key, value in dict.items(): if val == value: @@ -509,9 +540,9 @@ def get_dict_key(dict, val): return "key doesn't exist" -class CannotConnect(HomeAssistantError): +class CannotConnect(HomeAssistantError): # type: ignore[misc] """Error to indicate we cannot connect.""" -class InvalidAuth(HomeAssistantError): +class InvalidAuth(HomeAssistantError): # type: ignore[misc] """Error to indicate there is invalid auth.""" diff --git a/custom_components/victron/const.py b/custom_components/victron/const.py index e6c3ea3..4456d65 100644 --- a/custom_components/victron/const.py +++ b/custom_components/victron/const.py @@ -1,6 +1,7 @@ """Constants for the victron integration.""" from enum import Enum +from typing import Any from homeassistant.components.sensor import SensorStateClass from homeassistant.const import ( @@ -59,10 +60,10 @@ class DeviceType(Enum): class STRING: """Class for string data type.""" - def __init__(self, length=1, read_length=None): + def __init__(self, length: int = 1, read_length: str | None = None) -> None: """Initialize the string data type.""" self.length = length - self.readLength = read_length if read_length is not None else length * 2 + self.read_length = read_length if read_length is not None else length * 2 # maybe change to enum Enum('UINT16', 'UINT32') @@ -75,28 +76,39 @@ def __init__(self, length=1, read_length=None): class EntityType: - """Base entityType.""" + """Base entity_type.""" - def __init__(self, entityTypeName) -> None: - """Initialize the entity type.""" - self.entityTypeName = entityTypeName + def __init__(self, entity_type_name: str | type[Enum]) -> None: + """Initialize the entity type. + + :param entity_type_name: + """ + self.entity_type_name = entity_type_name class ReadEntityType(EntityType): """Read entity type.""" - def __init__(self, entityTypeName: str = "read") -> None: + def __init__(self, entity_type_name: str | type[Enum] = "read") -> None: """Initialize the read entity type.""" - super().__init__(entityTypeName=entityTypeName) + super().__init__(entity_type_name=entity_type_name) + + +class GenericAlarmLedger(Enum): + """Generic alarm ledger.""" + + OK = 0 + WARNING = 1 + ALARM = 2 class TextReadEntityType(ReadEntityType): """Text read entity type.""" - def __init__(self, decodeEnum: Enum) -> None: + def __init__(self, entity_type_name: type[Enum]) -> None: """Initialize the text read entity type.""" super().__init__() - self.decodeEnum = decodeEnum + self.entity_type_name = entity_type_name class BoolReadEntityType(ReadEntityType): @@ -104,7 +116,7 @@ class BoolReadEntityType(ReadEntityType): def __init__(self) -> None: """Initialize the bool read entity type.""" - super().__init__(entityTypeName="bool") + super().__init__(entity_type_name="bool") class ButtonWriteType(EntityType): @@ -112,7 +124,7 @@ class ButtonWriteType(EntityType): def __init__(self) -> None: """Initialize the button write type.""" - super().__init__(entityTypeName="button") + super().__init__(entity_type_name="button") class SwitchWriteType(EntityType): @@ -120,26 +132,26 @@ class SwitchWriteType(EntityType): def __init__(self) -> None: """Initialize the switch write type.""" - super().__init__(entityTypeName="switch") + super().__init__(entity_type_name="switch") class SliderWriteType(EntityType): """Slider write type.""" - def __init__(self, powerType="", negative: bool = False) -> None: + def __init__(self, power_type: str = "", negative: bool = False) -> None: """Initialize the slider write type.""" - super().__init__(entityTypeName="slider") - self.powerType = powerType + super().__init__(entity_type_name="slider") + self.power_type = power_type self.negative = negative class SelectWriteType(EntityType): """Select write type.""" - def __init__(self, optionsEnum: Enum) -> None: + def __init__(self, options_enum: type[Enum]) -> None: """Initialize the select write type.""" - super().__init__(entityTypeName="select") - self.options = optionsEnum + super().__init__(entity_type_name="select") + self.options = options_enum class RegisterInfo: @@ -147,28 +159,28 @@ class RegisterInfo: def __init__( self, - register, - dataType, - unit="", - scale=1, - entityType: EntityType = ReadEntityType(), - step=0, + register: float, + data_type: Any, + unit: str = "", + scale: float = 1, + entity_type: EntityType | type[GenericAlarmLedger] = ReadEntityType(), + step: float = 0, ) -> None: """Initialize the register info.""" self.register = register - self.dataType = dataType + self.data_type = data_type self.unit = ( unit - if not isinstance(entityType, TextReadEntityType) - and not isinstance(dataType, STRING) + if not isinstance(entity_type, TextReadEntityType) + and not isinstance(data_type, STRING) else None ) self.scale = scale self.step = step # Only used for writeable entities - self.entityType = entityType + self.entity_type = entity_type - def determine_stateclass(self): + def determine_stateclass(self) -> Any: """Determine the state class.""" if self.unit == UnitOfEnergy.KILO_WATT_HOUR: return SensorStateClass.TOTAL_INCREASING @@ -177,14 +189,6 @@ def determine_stateclass(self): return SensorStateClass.MEASUREMENT -class generic_alarm_ledger(Enum): - """Generic alarm ledger.""" - - OK = 0 - WARNING = 1 - ALARM = 2 - - gavazi_grid_registers = { "grid_L1_power": RegisterInfo(2600, INT16, UnitOfPower.WATT), "grid_L2_power": RegisterInfo(2601, INT16, UnitOfPower.WATT), @@ -207,7 +211,7 @@ class generic_alarm_ledger(Enum): "grid_L3_energy_reverse": RegisterInfo( 2608, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 ), - "grid_serial": RegisterInfo(2609, STRING(7)), + "grid_serial": RegisterInfo(2609, str(STRING(7))), "grid_L1_voltage": RegisterInfo(2616, UINT16, UnitOfElectricPotential.VOLT, 10), "grid_L1_current": RegisterInfo(2617, INT16, UnitOfElectricCurrent.AMPERE, 10), "grid_L2_voltage": RegisterInfo(2618, UINT16, UnitOfElectricPotential.VOLT, 10), @@ -241,7 +245,7 @@ class generic_alarm_ledger(Enum): } -class vebus_mode(Enum): +class VebusMode(Enum): """Vebus mode.""" CHARGER = 1 @@ -250,7 +254,7 @@ class vebus_mode(Enum): OFF = 4 -class generic_activeinput(Enum): +class GenericActiveinput(Enum): """Generic active input.""" AC_INPUT_1 = 0 @@ -258,7 +262,7 @@ class generic_activeinput(Enum): DISCONNECTED = 240 -class generic_charger_state(Enum): +class GenericChargerState(Enum): """Generic charger state.""" OFF = 0 @@ -276,7 +280,7 @@ class generic_charger_state(Enum): EXTERNAL_CONTROL = 252 -class vebus_error(Enum): +class VebusError(Enum): """Vebus error.""" OK = 0 @@ -350,162 +354,164 @@ class vebus_error(Enum): 28, UINT16 ), # the number count has no unit of measurement "vebus_activein_activeinput": RegisterInfo( - register=29, dataType=UINT16, entityType=TextReadEntityType(generic_activeinput) + register=29, + data_type=UINT16, + entity_type=TextReadEntityType(GenericActiveinput), ), "vebus_soc": RegisterInfo( 30, UINT16, PERCENTAGE, 10, SliderWriteType(PERCENTAGE, False) ), "vebus_state": RegisterInfo( register=31, - dataType=UINT16, - entityType=TextReadEntityType(generic_charger_state), + data_type=UINT16, + entity_type=TextReadEntityType(GenericChargerState), ), # This has no unit of measurement - "vebus_error": RegisterInfo( - register=32, dataType=UINT16, entityType=TextReadEntityType(vebus_error) + "VebusError": RegisterInfo( + register=32, data_type=UINT16, entity_type=TextReadEntityType(VebusError) ), # This has no unit of measurement "vebus_mode": RegisterInfo( - register=33, dataType=UINT16, entityType=SelectWriteType(vebus_mode) + register=33, data_type=UINT16, entity_type=SelectWriteType(VebusMode) ), # This has no unit of measurement "vebus_alarm_hightemperature": RegisterInfo( register=34, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_lowbattery": RegisterInfo( register=35, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_overload": RegisterInfo( register=36, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_L1_acpowersetpoint": RegisterInfo( register=37, - dataType=INT16, + data_type=INT16, unit=UnitOfPower.WATT, - entityType=SliderWriteType("AC", True), + entity_type=SliderWriteType("AC", True), ), "vebus_disablecharge": RegisterInfo( - register=38, dataType=UINT16, entityType=SwitchWriteType() + register=38, data_type=UINT16, entity_type=SwitchWriteType() ), # This has no unit of measurement "vebus_disablefeedin": RegisterInfo( - 39, UINT16, entityType=SwitchWriteType() + 39, UINT16, entity_type=SwitchWriteType() ), # This has no unit of measurement "vebus_L2_acpowersetpoint": RegisterInfo( register=40, - dataType=INT16, + data_type=INT16, unit=UnitOfPower.WATT, - entityType=SliderWriteType("AC", True), + entity_type=SliderWriteType("AC", True), ), "vebus_L3_acpowersetpoint": RegisterInfo( register=41, - dataType=INT16, + data_type=INT16, unit=UnitOfPower.WATT, - entityType=SliderWriteType("AC", True), + entity_type=SliderWriteType("AC", True), ), "vebus_alarm_temperaturesensor": RegisterInfo( register=42, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_voltagesensor": RegisterInfo( register=43, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L1_higtemperature": RegisterInfo( register=44, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L1_lowbattery": RegisterInfo( register=45, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L1_overload": RegisterInfo( register=46, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L1_ripple": RegisterInfo( register=47, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L2_higtemperature": RegisterInfo( register=48, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L2_lowbattery": RegisterInfo( register=49, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L2_overload": RegisterInfo( register=50, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L2_ripple": RegisterInfo( register=51, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L3_higtemperature": RegisterInfo( register=52, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L3_lowbattery": RegisterInfo( register=53, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L3_overload": RegisterInfo( register=54, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_L3_ripple": RegisterInfo( register=55, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_pvinverter_disable": RegisterInfo( - register=56, dataType=UINT16, entityType=SwitchWriteType() + register=56, data_type=UINT16, entity_type=SwitchWriteType() ), # This has no unit of measurement "vebus_bms_allowtocharge": RegisterInfo( - register=57, dataType=UINT16, entityType=BoolReadEntityType() + register=57, data_type=UINT16, entity_type=BoolReadEntityType() ), # This has no unit of measurement "vebus_bms_allowtodischarge": RegisterInfo( - register=58, dataType=UINT16, entityType=BoolReadEntityType() + register=58, data_type=UINT16, entity_type=BoolReadEntityType() ), # This has no unit of measurement "vebus_bms_bmsexpected": RegisterInfo( - register=59, dataType=UINT16, entityType=BoolReadEntityType() + register=59, data_type=UINT16, entity_type=BoolReadEntityType() ), # This has no unit of measurement "vebus_bms_error": RegisterInfo( - register=60, dataType=UINT16, entityType=BoolReadEntityType() + register=60, data_type=UINT16, entity_type=BoolReadEntityType() ), # This has no unit of measurement "vebus_battery_temperature": RegisterInfo(61, INT16, UnitOfTemperature.CELSIUS, 10), "vebus_systemreset": RegisterInfo( - register=62, dataType=UINT16, entityType=ButtonWriteType() + register=62, data_type=UINT16, entity_type=ButtonWriteType() ), # This has no unit of measurement "vebus_alarm_phaserotation": RegisterInfo( register=63, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_alarm_gridlost": RegisterInfo( register=64, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), # This has no unit of measurement "vebus_donotfeedinovervoltage": RegisterInfo( - register=65, dataType=UINT16, entityType=SwitchWriteType() + register=65, data_type=UINT16, entity_type=SwitchWriteType() ), # This has no unit of measurement "vebus_L1_maxfeedinpower": RegisterInfo( 66, UINT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", False) @@ -517,19 +523,19 @@ class vebus_error(Enum): 68, UINT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", False) ), "vebus_state_ignoreacin1": RegisterInfo( - register=69, dataType=UINT16, entityType=BoolReadEntityType() + register=69, data_type=UINT16, entity_type=BoolReadEntityType() ), # This has no unit of measurement "vebus_state_ignoreacin2": RegisterInfo( - register=70, dataType=UINT16, entityType=BoolReadEntityType() + register=70, data_type=UINT16, entity_type=BoolReadEntityType() ), # This has no unit of measurement "vebus_targetpowerismaxfeedin": RegisterInfo( - register=71, dataType=UINT16, entityType=SwitchWriteType() + register=71, data_type=UINT16, entity_type=SwitchWriteType() ), # This has no unit of measurement "vebus_fixsolaroffsetto100mv": RegisterInfo( - register=72, dataType=UINT16, entityType=SwitchWriteType() + register=72, data_type=UINT16, entity_type=SwitchWriteType() ), # This has no unit of measurement "vebus_sustain": RegisterInfo( - register=73, dataType=UINT16, entityType=BoolReadEntityType() + register=73, data_type=UINT16, entity_type=BoolReadEntityType() ), # This has no unit of measurement "vebus_acin1toacout": RegisterInfo(74, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), "vebus_acin1toinverter": RegisterInfo(76, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), @@ -558,71 +564,71 @@ class vebus_error(Enum): "battery_soc": RegisterInfo(266, UINT16, PERCENTAGE, 10), "battery_alarm": RegisterInfo( register=267, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_lowvoltage": RegisterInfo( register=268, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_highvoltage": RegisterInfo( register=269, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_lowstartervoltage": RegisterInfo( register=270, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_highstartervoltage": RegisterInfo( register=271, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_lowsoc": RegisterInfo( register=272, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_lowtemperature": RegisterInfo( register=273, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_hightemperature": RegisterInfo( register=274, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_midvoltage": RegisterInfo( register=275, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_lowfusedvoltage": RegisterInfo( register=276, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_highfusedvoltage": RegisterInfo( register=277, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_fuseblown": RegisterInfo( register=278, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_highinternaltemperature": RegisterInfo( register=279, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_relay": RegisterInfo( - register=280, dataType=UINT16, entityType=SwitchWriteType() + register=280, data_type=UINT16, entity_type=SwitchWriteType() ), "battery_history_deepestdischarge": RegisterInfo( 281, UINT16, UnitOfElectricCurrent.AMPERE, -10 @@ -699,43 +705,43 @@ class vebus_error(Enum): ), "battery_alarm_higchargecurrent": RegisterInfo( register=320, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_highdischargecurrent": RegisterInfo( register=321, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_cellimbalance": RegisterInfo( register=322, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_internalfailure": RegisterInfo( register=323, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_highchargetemperature": RegisterInfo( register=324, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_lowchargetemperature": RegisterInfo( register=325, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_alarm_lowcellvoltage": RegisterInfo( register=326, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } -class battery_state(Enum): +class BatteryState(Enum): """Battery state.""" WAIT_START_INIT = 0 @@ -757,7 +763,7 @@ class battery_state(Enum): PRE_CHARGING = 16 -class battery_error(Enum): +class BatteryError(Enum): """Battery error.""" NONE = 0 @@ -799,17 +805,21 @@ class battery_error(Enum): battery_detail_registers = { - "battery_state": RegisterInfo( - register=1282, dataType=UINT16, entityType=TextReadEntityType(battery_state) + "BatteryState": RegisterInfo( + register=1282, + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), - "battery_error": RegisterInfo( - register=1283, dataType=UINT16, entityType=TextReadEntityType(battery_error) + "BatteryError": RegisterInfo( + register=1283, + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_system_switch": RegisterInfo( - register=1284, dataType=UINT16, entityType=BoolReadEntityType() + register=1284, data_type=UINT16, entity_type=BoolReadEntityType() ), "battery_balancing": RegisterInfo( - register=1285, dataType=UINT16, entityType=BoolReadEntityType() + register=1285, data_type=UINT16, entity_type=BoolReadEntityType() ), "battery_system_numberofbatteries": RegisterInfo(1286, UINT16), "battery_system_batteriesparallel": RegisterInfo(1287, UINT16), @@ -823,25 +833,27 @@ class battery_error(Enum): ), "battery_diagnostics_shutdownsdueerror": RegisterInfo(1292, UINT16), "battery_diagnostics_lasterror_1": RegisterInfo( - register=1293, dataType=UINT16, entityType=TextReadEntityType(battery_error) + register=1293, data_type=UINT16, entity_type=TextReadEntityType(BatteryError) ), "battery_diagnostics_lasterror_2": RegisterInfo( - register=1294, dataType=UINT16, entityType=TextReadEntityType(battery_error) + register=1294, data_type=UINT16, entity_type=TextReadEntityType(BatteryError) ), "battery_diagnostics_lasterror_3": RegisterInfo( - register=1295, dataType=UINT16, entityType=TextReadEntityType(battery_error) + register=1295, data_type=UINT16, entity_type=TextReadEntityType(BatteryError) ), "battery_diagnostics_lasterror_4": RegisterInfo( - register=1296, dataType=UINT16, entityType=TextReadEntityType(battery_error) + register=1296, + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "battery_io_allowtocharge": RegisterInfo( - register=1297, dataType=UINT16, entityType=BoolReadEntityType() + register=1297, data_type=UINT16, entity_type=BoolReadEntityType() ), "battery_io_allowtodischarge": RegisterInfo( - register=1298, dataType=UINT16, entityType=BoolReadEntityType() + register=1298, data_type=UINT16, entity_type=BoolReadEntityType() ), "battery_io_externalrelay": RegisterInfo( - register=1299, dataType=UINT16, entityType=BoolReadEntityType() + register=1299, data_type=UINT16, entity_type=BoolReadEntityType() ), "battery_history_minimumcellvoltage": RegisterInfo( 1300, UINT16, UnitOfElectricPotential.VOLT, 100 @@ -853,21 +865,21 @@ class battery_error(Enum): "battery_system_numberofmodulesonline": RegisterInfo(1303, UINT16), "battery_system_numberofmodulesblockingcharge": RegisterInfo(1304, UINT16), "battery_system_numberofmodulesblockingdischarge": RegisterInfo(1305, UINT16), - "battery_system_minvoltagecellid": RegisterInfo(1306, STRING(4)), - "battery_system_maxvoltagecellid": RegisterInfo(1310, STRING(4)), - "battery_system_mintemperaturecellid": RegisterInfo(1314, STRING(4)), - "battery_system_maxtemperaturecellid": RegisterInfo(1318, STRING(4)), + "battery_system_minvoltagecellid": RegisterInfo(1306, str(STRING(4))), + "battery_system_maxvoltagecellid": RegisterInfo(1310, str(STRING(4))), + "battery_system_mintemperaturecellid": RegisterInfo(1314, str(STRING(4))), + "battery_system_maxtemperaturecellid": RegisterInfo(1318, str(STRING(4))), } -class solarcharger_mode(Enum): +class SolarchargerMode(Enum): """Solar charger mode.""" ON = 1 OFF = 4 -class solarcharger_state(Enum): +class SolarchargerState(Enum): """Solar charger state.""" OFF = 0 @@ -882,7 +894,7 @@ class solarcharger_state(Enum): EXTERNAL_CONTROL = 252 -class solarcharger_equalization_pending(Enum): +class SolarchargerEqualizationPending(Enum): """Solar charger equalization pending.""" NO = 0 @@ -891,7 +903,7 @@ class solarcharger_equalization_pending(Enum): UNAVAILABLE = 3 -class generic_charger_errorcode(Enum): +class GenericChargerErrorcode(Enum): """Generic charger error code.""" NONE = 0 @@ -913,7 +925,7 @@ class generic_charger_errorcode(Enum): INPUT_CURRENT_TOO_HIGH = 34 -class generic_mppoperationmode(Enum): +class GenericMppoperationmode(Enum): """Generic MPP operation mode.""" OFF = 0 @@ -932,11 +944,13 @@ class generic_mppoperationmode(Enum): "solarcharger_battery_temperature": RegisterInfo( 773, INT16, UnitOfTemperature.CELSIUS, 10 ), - "solarcharger_mode": RegisterInfo( - register=774, dataType=UINT16, entityType=SelectWriteType(solarcharger_mode) + "SolarchargerMode": RegisterInfo( + register=774, data_type=UINT16, entity_type=SelectWriteType(GenericAlarmLedger) ), - "solarcharger_state": RegisterInfo( - register=775, dataType=UINT16, entityType=TextReadEntityType(solarcharger_state) + "SolarchargerState": RegisterInfo( + register=775, + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "solarcharger_pv_voltage": RegisterInfo( 776, UINT16, UnitOfElectricPotential.VOLT, 100 @@ -946,29 +960,29 @@ class generic_mppoperationmode(Enum): ), "solarcharger_equallization_pending": RegisterInfo( register=778, - dataType=UINT16, - entityType=TextReadEntityType(solarcharger_equalization_pending), + data_type=UINT16, + entity_type=TextReadEntityType(SolarchargerEqualizationPending), ), "solarcharger_equalization_time_remaining": RegisterInfo( 779, UINT16, UnitOfTime.SECONDS, 10 ), "solarcharger_relay": RegisterInfo( - register=780, dataType=UINT16, entityType=BoolReadEntityType() + register=780, data_type=UINT16, entity_type=BoolReadEntityType() ), "solarcharger_alarm": RegisterInfo( register=781, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "solarcharger_alarm_lowvoltage": RegisterInfo( register=782, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "solarcharger_alarm_highvoltage": RegisterInfo( register=783, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "solarcharger_yield_today": RegisterInfo( 784, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 @@ -980,8 +994,8 @@ class generic_mppoperationmode(Enum): "solarcharger_maxpower_yesterday": RegisterInfo(787, UINT16, UnitOfPower.WATT), "solarcharger_errorcode": RegisterInfo( register=788, - dataType=UINT16, - entityType=TextReadEntityType(generic_charger_errorcode), + data_type=UINT16, + entity_type=TextReadEntityType(GenericChargerErrorcode), ), "solarcharger_yield_power": RegisterInfo(789, UINT16, UnitOfPower.WATT, 10), "solarcharger_yield_user": RegisterInfo( @@ -989,8 +1003,8 @@ class generic_mppoperationmode(Enum): ), "solarcharger_mppoperationmode": RegisterInfo( register=791, - dataType=UINT16, - entityType=TextReadEntityType(generic_mppoperationmode), + data_type=UINT16, + entity_type=TextReadEntityType(GenericMppoperationmode), ), } @@ -1065,7 +1079,7 @@ class generic_mppoperationmode(Enum): } -class generic_position(Enum): +class GenericPosition(Enum): """Generic position.""" AC_INPUT_1 = 0 @@ -1075,7 +1089,7 @@ class generic_position(Enum): pvinverter_registers = { "pvinverter_position": RegisterInfo( - register=1026, dataType=UINT16, entityType=TextReadEntityType(generic_position) + register=1026, data_type=UINT16, entity_type=TextReadEntityType(GenericPosition) ), "pvinverter_L1_voltage": RegisterInfo( 1027, UINT16, UnitOfElectricPotential.VOLT, 10 @@ -1107,7 +1121,7 @@ class generic_position(Enum): "pvinverter_L3_energy_forward": RegisterInfo( 1038, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 ), - "pvinverter_serial": RegisterInfo(1039, STRING(7)), + "pvinverter_serial": RegisterInfo(1039, str(STRING(7))), "pvinverter_L1_energy_forward_total": RegisterInfo( 1046, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 ), @@ -1121,9 +1135,9 @@ class generic_position(Enum): "pvinverter_power_max_capacity": RegisterInfo(1054, UINT32, UnitOfPower.WATT), "pvinverter_powerlimit": RegisterInfo( register=1056, - dataType=UINT32, + data_type=UINT32, unit=UnitOfPower.WATT, - entityType=SliderWriteType("AC", False), + entity_type=SliderWriteType("AC", False), ), } @@ -1141,7 +1155,7 @@ class generic_position(Enum): } -class charger_mode(Enum): +class ChargerMode(Enum): """Charger mode.""" OFF = 0 @@ -1177,48 +1191,48 @@ class charger_mode(Enum): INT16, UnitOfElectricCurrent.AMPERE, 10, - entityType=SliderWriteType("AC", True), + entity_type=SliderWriteType("AC", True), ), "charger_mode": RegisterInfo( - register=2317, dataType=UINT16, entityType=SelectWriteType(charger_mode) + register=2317, data_type=UINT16, entity_type=SelectWriteType(ChargerMode) ), "charger_state": RegisterInfo( register=2318, - dataType=UINT16, - entityType=TextReadEntityType(generic_charger_state), + data_type=UINT16, + entity_type=TextReadEntityType(GenericChargerState), ), "charger_errorcode": RegisterInfo( register=2319, - dataType=UINT16, - entityType=TextReadEntityType(generic_charger_errorcode), + data_type=UINT16, + entity_type=TextReadEntityType(GenericChargerErrorcode), ), "charger_relay": RegisterInfo( - register=2320, dataType=UINT16, entityType=BoolReadEntityType() + register=2320, data_type=UINT16, entity_type=BoolReadEntityType() ), "charger_alarm_lowvoltage": RegisterInfo( register=2321, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "charger_alarm_highvoltage": RegisterInfo( register=2322, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } settings_registers = { "settings_ess_acpowersetpoint": RegisterInfo( register=2700, - dataType=INT16, + data_type=INT16, unit=UnitOfPower.WATT, - entityType=SliderWriteType("AC", True), + entity_type=SliderWriteType("AC", True), ), "settings_ess_maxchargepercentage": RegisterInfo( - register=2701, dataType=UINT16, unit=PERCENTAGE, entityType=SliderWriteType() + register=2701, data_type=UINT16, unit=PERCENTAGE, entity_type=SliderWriteType() ), "settings_ess_maxdischargepercentage": RegisterInfo( - register=2702, dataType=UINT16, unit=PERCENTAGE, entityType=SliderWriteType() + register=2702, data_type=UINT16, unit=PERCENTAGE, entity_type=SliderWriteType() ), "settings_ess_acpowersetpoint2": RegisterInfo( 2703, INT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", True) @@ -1228,21 +1242,21 @@ class charger_mode(Enum): ), "settings_ess_maxchargecurrent": RegisterInfo( register=2705, - dataType=INT16, + data_type=INT16, unit=UnitOfElectricCurrent.AMPERE, - entityType=SliderWriteType("DC", True), + entity_type=SliderWriteType("DC", True), ), "settings_ess_maxfeedinpower": RegisterInfo( 2706, INT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", True) ), "settings_ess_overvoltagefeedin": RegisterInfo( - register=2707, dataType=INT16, entityType=SwitchWriteType() + register=2707, data_type=INT16, entity_type=SwitchWriteType() ), "settings_ess_preventfeedback": RegisterInfo( - register=2708, dataType=INT16, entityType=SwitchWriteType() + register=2708, data_type=INT16, entity_type=SwitchWriteType() ), "settings_ess_feedinpowerlimit": RegisterInfo( - register=2709, dataType=INT16, entityType=BoolReadEntityType() + register=2709, data_type=INT16, entity_type=BoolReadEntityType() ), "settings_systemsetup_maxchargevoltage": RegisterInfo( 2710, @@ -1260,14 +1274,14 @@ class charger_mode(Enum): "gps_course": RegisterInfo(2804, UINT16, "", 100), "gps_speed": RegisterInfo(2805, UINT16, UnitOfSpeed.METERS_PER_SECOND, 100), "gps_fix": RegisterInfo( - register=2806, dataType=UINT16, entityType=BoolReadEntityType() + register=2806, data_type=UINT16, entity_type=BoolReadEntityType() ), "gps_numberofsatellites": RegisterInfo(2807, UINT16), "gps_altitude": RegisterInfo(2808, INT32, UnitOfLength.METERS, 10), } -class ess_batterylife_state(Enum): +class ESSBatterylifeState(Enum): """ESS battery life state.""" BL_DISABLED_DUPLICATE_1 = 0 @@ -1297,20 +1311,20 @@ class ess_mode(Enum): settings_ess_registers = { "settings_ess_batterylife_state": RegisterInfo( register=2900, - dataType=UINT16, - entityType=SelectWriteType(ess_batterylife_state), + data_type=UINT16, + entity_type=SelectWriteType(ESSBatterylifeState), ), "settings_ess_batterylife_minimumsoc": RegisterInfo( 2901, UINT16, PERCENTAGE, 10, SliderWriteType(), 5 ), "settings_ess_mode": RegisterInfo( - register=2902, dataType=UINT16, entityType=SelectWriteType(ess_mode) + register=2902, data_type=UINT16, entity_type=SelectWriteType(ess_mode) ), "settings_ess_batterylife_soclimit": RegisterInfo(2903, UINT16, PERCENTAGE, 10), } -class tank_fluidtype(Enum): +class TankFluidtype(Enum): """Tank fluid type.""" FUEL = 0 @@ -1327,7 +1341,7 @@ class tank_fluidtype(Enum): RAW_WATER = 11 -class tank_status(Enum): +class TankStatus(Enum): """Tank status.""" OK = 0 @@ -1342,12 +1356,12 @@ class tank_status(Enum): "tank_productid": RegisterInfo(3000, UINT16), "tank_capacity": RegisterInfo(3001, UINT32, UnitOfVolume.CUBIC_METERS, 10000), "tank_fluidtype": RegisterInfo( - register=3003, dataType=UINT16, entityType=TextReadEntityType(tank_fluidtype) + register=3003, data_type=UINT16, entity_type=TextReadEntityType(TankFluidtype) ), "tank_level": RegisterInfo(3004, UINT16, PERCENTAGE, 10), "tank_remaining": RegisterInfo(3005, UINT32, UnitOfVolume.CUBIC_METERS, 10000), "tank_status": RegisterInfo( - register=3007, dataType=UINT16, entityType=TextReadEntityType(tank_status) + register=3007, data_type=UINT16, entity_type=TextReadEntityType(TankStatus) ), } @@ -1373,48 +1387,48 @@ class tank_status(Enum): inverter_alarm_registers = { "inverter_alarm_hightemperature": RegisterInfo( register=3110, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "inverter_alarm_highbatteryvoltage": RegisterInfo( register=3111, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "inverter_alarm_highacoutvoltage": RegisterInfo( register=3112, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "inverter_alarm_lowtemperature": RegisterInfo( register=3113, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "inverter_alarm_lowbatteryvoltage": RegisterInfo( register=3114, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "inverter_alarm_lowacoutvoltage": RegisterInfo( register=3115, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "inverter_alarm_overload": RegisterInfo( register=3116, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "inverter_alarm_ripple": RegisterInfo( register=3117, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } -class inverter_mode(Enum): +class InverterMode(Enum): """Inverter mode.""" ON = 2 @@ -1425,13 +1439,13 @@ class inverter_mode(Enum): inverter_info_registers = { "inverter_info_firmwareversion": RegisterInfo(3125, UINT16), "inverter_info_mode": RegisterInfo( - register=3126, dataType=UINT16, entityType=SelectWriteType(inverter_mode) + register=3126, data_type=UINT16, entity_type=SelectWriteType(GenericAlarmLedger) ), "inverter_info_productid": RegisterInfo(3127, UINT16), "inverter_info_state": RegisterInfo( register=3128, - dataType=UINT16, - entityType=TextReadEntityType(generic_charger_state), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } @@ -1516,13 +1530,13 @@ class inverter_mode(Enum): "inverter_tracker_3_power": RegisterInfo(3167, UINT16, UnitOfPower.WATT), "inverter_alarm_lowsoc": RegisterInfo( register=3168, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } -class genset_status(Enum): +class GensetStatus(Enum): """Genset status.""" STANDBY = 0 @@ -1538,7 +1552,7 @@ class genset_status(Enum): ERROR = 10 -class genset_errorcode(Enum): +class GensetErrorcode(Enum): """Genset error code.""" NONE = 0 @@ -1655,13 +1669,13 @@ class genset_errorcode(Enum): "genset_L3_frequency": RegisterInfo(3211, UINT16, UnitOfFrequency.HERTZ, 100), "genset_productid": RegisterInfo(3212, UINT16), "genset_statuscode": RegisterInfo( - register=3213, dataType=UINT16, entityType=TextReadEntityType(genset_status) + register=3213, data_type=UINT16, entity_type=TextReadEntityType(GensetStatus) ), "genset_errorcode": RegisterInfo( - register=3214, dataType=UINT16, entityType=TextReadEntityType(genset_errorcode) + register=3214, data_type=UINT16, entity_type=TextReadEntityType(GensetErrorcode) ), "genset_autostart": RegisterInfo( - register=3215, dataType=UINT16, entityType=BoolReadEntityType() + register=3215, data_type=UINT16, entity_type=BoolReadEntityType() ), "genset_engine_load": RegisterInfo(3216, UINT16, PERCENTAGE), "genset_engine_speed": RegisterInfo(3217, UINT16, REVOLUTIONS_PER_MINUTE), @@ -1681,12 +1695,12 @@ class genset_errorcode(Enum): 3222, UINT16, UnitOfElectricPotential.VOLT, 100 ), "genset_start": RegisterInfo( - register=3223, dataType=UINT16, entityType=SwitchWriteType() + register=3223, data_type=UINT16, entity_type=SwitchWriteType() ), } -class temperature_type(Enum): +class TemperatureType(Enum): """Temperature type.""" BATTERY = 0 @@ -1694,7 +1708,7 @@ class temperature_type(Enum): GENERIC = 2 -class temperature_status(Enum): +class TemperatureStatus(Enum): """Temperature status.""" OK = 0 @@ -1710,15 +1724,17 @@ class temperature_status(Enum): "temperature_scale": RegisterInfo(3301, UINT16, "", 100), "temperature_offset": RegisterInfo(3302, INT16, "", 100), "temperature_type": RegisterInfo( - register=3303, dataType=UINT16, entityType=TextReadEntityType(temperature_type) + register=3303, + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "temperature_temperature": RegisterInfo( 3304, INT16, UnitOfTemperature.CELSIUS, 100 ), - "temperature_status": RegisterInfo( + "TemperatureStatus": RegisterInfo( register=3305, - dataType=UINT16, - entityType=TextReadEntityType(temperature_status), + data_type=UINT16, + entity_type=TextReadEntityType(TemperatureStatus), ), "temperature_humidity": RegisterInfo(3306, UINT16, PERCENTAGE, 10), "temperature_batteryvoltage": RegisterInfo( @@ -1733,7 +1749,7 @@ class temperature_status(Enum): } -class digitalinput_state(Enum): +class DigitalinputState(Enum): """Digital input state.""" LOW = 0 @@ -1750,7 +1766,7 @@ class digitalinput_state(Enum): STOPPED = 11 -class digitalinput_type(Enum): +class DigitalinputType(Enum): """Digital input type.""" DOOR = 2 @@ -1766,21 +1782,23 @@ class digitalinput_type(Enum): "digitalinput_count": RegisterInfo(3420, UINT32), "digitalinput_state": RegisterInfo( register=3422, - dataType=UINT16, - entityType=TextReadEntityType(digitalinput_state), + data_type=UINT16, + entity_type=TextReadEntityType(DigitalinputState), ), "digitalinput_alarm": RegisterInfo( register=3423, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "digitalinput_type": RegisterInfo( - register=3424, dataType=UINT16, entityType=TextReadEntityType(digitalinput_type) + register=3424, + data_type=UINT16, + entity_type=TextReadEntityType(DigitalinputType), ), } -class generator_runningbyconditioncode(Enum): +class GeneratorRunningbyconditioncode(Enum): """Generator running by condition code.""" STOPPED = 0 @@ -1796,7 +1814,7 @@ class generator_runningbyconditioncode(Enum): STOP_ON_AC1 = 10 -class generator_state(Enum): +class GeneratorState(Enum): """Generator state.""" STOPPED = 0 @@ -1804,7 +1822,7 @@ class generator_state(Enum): ERROR = 10 -class generator_error(Enum): +class GeneratorError(Enum): """Generator error.""" NONE = 0 @@ -1814,31 +1832,31 @@ class generator_error(Enum): generator_registers = { "generator_manualstart": RegisterInfo( - register=3500, dataType=UINT16, entityType=SwitchWriteType() + register=3500, data_type=UINT16, entity_type=SwitchWriteType() ), - "generator_runningbyconditioncode": RegisterInfo( + "GeneratorRunningbyconditioncode": RegisterInfo( register=3501, - dataType=UINT16, - entityType=TextReadEntityType(generator_runningbyconditioncode), + data_type=UINT16, + entity_type=TextReadEntityType(GeneratorRunningbyconditioncode), ), "generator_runtime": RegisterInfo(3502, UINT16, UnitOfTime.SECONDS), "generator_quiethours": RegisterInfo( - register=3503, dataType=UINT16, entityType=BoolReadEntityType() + register=3503, data_type=UINT16, entity_type=BoolReadEntityType() ), "generator_runtime_2": RegisterInfo(3504, UINT32, UnitOfTime.SECONDS), "generator_state": RegisterInfo( - register=3506, dataType=UINT16, entityType=TextReadEntityType(generator_state) + register=3506, data_type=UINT16, entity_type=TextReadEntityType(GeneratorState) ), "generator_error": RegisterInfo( - register=3507, dataType=UINT16, entityType=TextReadEntityType(generator_error) + register=3507, data_type=UINT16, entity_type=TextReadEntityType(GeneratorError) ), "generator_alarm_nogeneratoratacin": RegisterInfo( register=3508, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "generator_autostartenabled": RegisterInfo( - register=3509, dataType=UINT16, entityType=SwitchWriteType() + register=3509, data_type=UINT16, entity_type=SwitchWriteType() ), } @@ -1857,7 +1875,7 @@ class generator_error(Enum): evcharger_productid_registers = {"evcharger_productid": RegisterInfo(3800, UINT16)} -class evcharger_mode(Enum): +class EvchargerMode(Enum): """EV charger mode.""" AC_INPUT_1 = 0 @@ -1865,7 +1883,7 @@ class evcharger_mode(Enum): AC_INPUT_2 = 2 -class evcharger_status(Enum): +class EvchargerStatus(Enum): """EV charger status.""" DISCONNECTED = 0 @@ -1887,16 +1905,16 @@ class evcharger_status(Enum): evcharger_registers = { "evcharger_firmwareversion": RegisterInfo(3802, UINT32), - "evcharger_serial": RegisterInfo(3804, STRING(6)), - "evcharger_model": RegisterInfo(3810, STRING(4)), + "evcharger_serial": RegisterInfo(3804, str(STRING(6))), + "evcharger_model": RegisterInfo(3810, str(STRING(4))), "evcharger_maxcurrent": RegisterInfo( register=3814, - dataType=UINT16, + data_type=UINT16, unit=UnitOfElectricCurrent.AMPERE, - entityType=SliderWriteType("AC", False), + entity_type=SliderWriteType("AC", False), ), "evcharger_mode": RegisterInfo( - register=3815, dataType=UINT16, entityType=SelectWriteType(evcharger_mode) + register=3815, data_type=UINT16, entity_type=SelectWriteType(EvchargerMode) ), "evcharger_energy_forward": RegisterInfo( 3816, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 @@ -1908,19 +1926,19 @@ class evcharger_status(Enum): "evcharger_chargingtime": RegisterInfo(3822, UINT16, UnitOfTime.SECONDS, 0.01), "evcharger_current": RegisterInfo(3823, UINT16, UnitOfElectricCurrent.AMPERE), "evcharger_status": RegisterInfo( - register=3824, dataType=UINT16, entityType=TextReadEntityType(evcharger_status) + register=3824, data_type=UINT16, entity_type=TextReadEntityType(EvchargerStatus) ), "evcharger_setcurrent": RegisterInfo( register=3825, - dataType=UINT16, + data_type=UINT16, unit=UnitOfElectricCurrent.AMPERE, - entityType=SliderWriteType("AC", False), + entity_type=SliderWriteType("AC", False), ), "evcharger_startstop": RegisterInfo( - register=3826, dataType=UINT16, entityType=SwitchWriteType() + register=3826, data_type=UINT16, entity_type=SwitchWriteType() ), "evcharger_position": RegisterInfo( - register=3827, dataType=UINT16, entityType=TextReadEntityType(generic_position) + register=3827, data_type=UINT16, entity_type=TextReadEntityType(GenericPosition) ), } @@ -1928,7 +1946,7 @@ class evcharger_status(Enum): "acload_L1_power": RegisterInfo(3900, UINT16, UnitOfPower.WATT), "acload_L2_power": RegisterInfo(3901, UINT16, UnitOfPower.WATT), "acload_L3_power": RegisterInfo(3902, UINT16, UnitOfPower.WATT), - "acload_serial": RegisterInfo(3903, STRING(7)), + "acload_serial": RegisterInfo(3903, str(STRING(7))), "acload_L1_voltage": RegisterInfo(3910, UINT16, UnitOfElectricPotential.VOLT, 10), "acload_L1_current": RegisterInfo(3911, INT16, UnitOfElectricCurrent.AMPERE, 10), "acload_L2_voltage": RegisterInfo(3912, UINT16, UnitOfElectricPotential.VOLT, 10), @@ -1962,38 +1980,38 @@ class evcharger_status(Enum): ), "fuelcell_alarm_lowvoltage": RegisterInfo( register=4006, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "fuelcell_alarm_highvoltage": RegisterInfo( register=4007, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "fuelcell_alarm_lowstartervoltage": RegisterInfo( register=4008, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "fuelcell_alarm_highstartervoltage": RegisterInfo( register=4009, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "fuelcell_alarm_lowtemperature": RegisterInfo( register=4010, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "fuelcell_alarm_hightemperature": RegisterInfo( register=4011, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } -class alternator_state(Enum): +class AlternatorState(Enum): """Alternator state.""" OFF = 0 @@ -2006,7 +2024,7 @@ class alternator_state(Enum): EXTERNAL_CONTROL = 252 -class alternator_errorcode(Enum): +class AlternatorErrorcode(Enum): """Alternator error code.""" HIGH_BATTERY_TEMPERATURE = 12 @@ -2058,41 +2076,41 @@ class alternator_errorcode(Enum): ), "alternator_alarm_lowvoltage": RegisterInfo( register=4106, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "alternator_alarm_highvoltage": RegisterInfo( register=4107, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "alternator_alarm_lowstartervoltage": RegisterInfo( register=4108, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "alternator_alarm_highstartervoltage": RegisterInfo( register=4109, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "alternator_alarm_lowtemperature": RegisterInfo( register=4110, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "alternator_alarm_hightemperature": RegisterInfo( register=4111, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "alternator_state": RegisterInfo( - register=4112, dataType=UINT16, entityType=TextReadEntityType(alternator_state) + register=4112, data_type=UINT16, entity_type=TextReadEntityType(AlternatorState) ), "alternator_errorcode": RegisterInfo( register=4113, - dataType=UINT16, - entityType=TextReadEntityType(alternator_errorcode), + data_type=UINT16, + entity_type=TextReadEntityType(AlternatorErrorcode), ), "alternator_engine_speed": RegisterInfo(4114, UINT16, REVOLUTIONS_PER_MINUTE), "alternator_alternator_speed": RegisterInfo(4115, UINT16, REVOLUTIONS_PER_MINUTE), @@ -2115,33 +2133,33 @@ class alternator_errorcode(Enum): ), "dcsource_alarm_lowvoltage": RegisterInfo( register=4206, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsource_alarm_highvoltage": RegisterInfo( register=4207, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsource_alarm_lowstartervoltage": RegisterInfo( register=4208, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsource_alarm_highstartervoltage": RegisterInfo( register=4209, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsource_alarm_lowtemperature": RegisterInfo( register=4210, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsource_alarm_hightemperature": RegisterInfo( register=4211, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } @@ -2161,33 +2179,33 @@ class alternator_errorcode(Enum): ), "dcload_alarm_lowvoltage": RegisterInfo( register=4306, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcload_alarm_highvoltage": RegisterInfo( register=4307, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcload_alarm_lowstartervoltage": RegisterInfo( register=4308, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcload_alarm_highstartervoltage": RegisterInfo( register=4309, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcload_alarm_lowtemperature": RegisterInfo( register=4310, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcload_alarm_hightemperature": RegisterInfo( register=4311, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } @@ -2210,38 +2228,38 @@ class alternator_errorcode(Enum): ), "dcsystem_alarm_lowvoltage": RegisterInfo( register=4408, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsystem_alarm_highvoltage": RegisterInfo( register=4409, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsystem_alarm_lowstartervoltage": RegisterInfo( register=4410, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsystem_alarm_highstartervoltage": RegisterInfo( register=4411, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsystem_alarm_lowtemperature": RegisterInfo( register=4412, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "dcsystem_alarm_hightemperature": RegisterInfo( register=4413, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } -class multi_mode(Enum): +class MultiMode(Enum): """Multi mode.""" CHARGER = 1 @@ -2305,10 +2323,14 @@ class multi_input_type(Enum): "multi_output_L3_power": RegisterInfo(4518, INT16, UnitOfPower.WATT, 0.1), "multi_output_L1_frequency": RegisterInfo(4519, UINT16, UnitOfFrequency.HERTZ, 100), "multi_input_1_type": RegisterInfo( - register=4520, dataType=UINT16, entityType=TextReadEntityType(multi_input_type) + register=4520, + data_type=UINT16, + entity_type=TextReadEntityType(multi_input_type), ), "multi_input_2_type": RegisterInfo( - register=4521, dataType=UINT16, entityType=TextReadEntityType(multi_input_type) + register=4521, + data_type=UINT16, + entity_type=TextReadEntityType(multi_input_type), ), "multi_input_1_currentlimit": RegisterInfo( 4522, UINT16, UnitOfElectricCurrent.AMPERE, 10, SliderWriteType("AC", False) @@ -2319,8 +2341,8 @@ class multi_input_type(Enum): "multi_numberofphases": RegisterInfo(4524, UINT16), "multi_activein_activeinput": RegisterInfo( register=4525, - dataType=UINT16, - entityType=TextReadEntityType(generic_activeinput), + data_type=UINT16, + entity_type=TextReadEntityType(GenericActiveinput), ), "multi_battery_voltage": RegisterInfo( 4526, UINT16, UnitOfElectricPotential.VOLT, 100 @@ -2334,67 +2356,67 @@ class multi_input_type(Enum): "multi_battery_soc": RegisterInfo(4529, UINT16, PERCENTAGE, 10), "multi_state": RegisterInfo( register=4530, - dataType=UINT16, - entityType=TextReadEntityType(generic_charger_state), + data_type=UINT16, + entity_type=TextReadEntityType(GenericChargerState), ), "multi_mode": RegisterInfo( - register=4531, dataType=UINT16, entityType=SelectWriteType(multi_mode) + register=4531, data_type=UINT16, entity_type=SelectWriteType(MultiMode) ), "multi_alarm_hightemperature": RegisterInfo( register=4532, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "multi_alarm_highvoltage": RegisterInfo( register=4533, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "multi_alarm_highvoltageacout": RegisterInfo( register=4534, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "multi_alarm_lowtemperature": RegisterInfo( register=4535, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "multi_alarm_lowvoltage": RegisterInfo( register=4536, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "multi_alarm_lowvoltageacout": RegisterInfo( register=4537, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "multi_alarm_overload": RegisterInfo( register=4538, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "multi_alarm_ripple": RegisterInfo( register=4539, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), "multi_yield_pv_power": RegisterInfo(4540, UINT16, UnitOfPower.WATT), "multi_yield_user": RegisterInfo(4541, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), "multi_relay": RegisterInfo( - register=4542, dataType=UINT16, entityType=BoolReadEntityType() + register=4542, data_type=UINT16, entity_type=BoolReadEntityType() ), "multi_mppoperationmode": RegisterInfo( register=4543, - dataType=UINT16, - entityType=TextReadEntityType(generic_mppoperationmode), + data_type=UINT16, + entity_type=TextReadEntityType(GenericMppoperationmode), ), "multi_pv_voltage": RegisterInfo(4544, UINT16, UnitOfElectricPotential.VOLT, 10), "multi_errorcode": RegisterInfo( register=4545, - dataType=UINT16, - entityType=TextReadEntityType(generic_charger_errorcode), + data_type=UINT16, + entity_type=TextReadEntityType(GenericChargerErrorcode), ), "multi_energy_acin1toacout": RegisterInfo( 4546, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 @@ -2512,8 +2534,8 @@ class multi_input_type(Enum): "multi_tracker_3_power": RegisterInfo(4601, UINT16, UnitOfPower.WATT), "multi_alarm_lowsoc": RegisterInfo( register=4602, - dataType=UINT16, - entityType=TextReadEntityType(generic_alarm_ledger), + data_type=UINT16, + entity_type=TextReadEntityType(GenericAlarmLedger), ), } @@ -2529,12 +2551,12 @@ class register_input_source(Enum): system_registers = { - "system_serial": RegisterInfo(800, STRING(6)), + "system_serial": RegisterInfo(800, str(STRING(6))), "system_relay_0": RegisterInfo( - register=806, dataType=UINT16, entityType=SwitchWriteType() + register=806, data_type=UINT16, entity_type=SwitchWriteType() ), "system_relay_1": RegisterInfo( - register=807, dataType=UINT16, entityType=SwitchWriteType() + register=807, data_type=UINT16, entity_type=SwitchWriteType() ), "system_pvonoutput_L1": RegisterInfo(808, UINT16, UnitOfPower.WATT), "system_pvonoutput_L2": RegisterInfo(809, UINT16, UnitOfPower.WATT), @@ -2556,13 +2578,13 @@ class register_input_source(Enum): "system_genset_L3": RegisterInfo(825, INT16, UnitOfPower.WATT), "system_input_source": RegisterInfo( register=826, - dataType=INT16, - entityType=TextReadEntityType(register_input_source), + data_type=INT16, + entity_type=TextReadEntityType(register_input_source), ), } -class system_battery_state(Enum): +class SystemBatteryState(Enum): """Battery state.""" IDLE = 0 @@ -2579,10 +2601,10 @@ class system_battery_state(Enum): ), "system_battery_power": RegisterInfo(842, INT16, UnitOfPower.WATT), "system_battery_soc": RegisterInfo(843, UINT16, PERCENTAGE), - "system_battery_state": RegisterInfo( + "system_BatteryState": RegisterInfo( register=844, - dataType=UINT16, - entityType=TextReadEntityType(system_battery_state), + data_type=UINT16, + entity_type=TextReadEntityType(SystemBatteryState), ), "system_battery_amphours": RegisterInfo( 845, UINT16, UnitOfElectricCurrent.AMPERE, -10 diff --git a/custom_components/victron/coordinator.py b/custom_components/victron/coordinator.py index 21324ef..ed97db4 100644 --- a/custom_components/victron/coordinator.py +++ b/custom_components/victron/coordinator.py @@ -5,10 +5,14 @@ from collections import OrderedDict from datetime import timedelta import logging +from typing import Any, Generic, TypeVar import pymodbus from pymodbus.constants import Endian + +# this import needs to be able to be completely removed if the preparation for 3.9.0 is done from pymodbus.payload import BinaryPayloadDecoder +from pymodbus.pdu import ModbusPDU if "3.7.0" <= pymodbus.__version__ <= "3.7.4": from pymodbus.pdu.register_read_message import ReadHoldingRegistersResponse @@ -31,10 +35,12 @@ ) from .hub import VictronHub +_DataT = TypeVar("_DataT", default=dict[str, Any]) + _LOGGER = logging.getLogger(__name__) -class victronEnergyDeviceUpdateCoordinator(DataUpdateCoordinator): +class VictronEnergyDeviceUpdateCoordinator(DataUpdateCoordinator, Generic[_DataT]): # type: ignore[misc] """Gather data for the energy device.""" api: VictronHub @@ -43,8 +49,8 @@ def __init__( self, hass: HomeAssistant, host: str, - port: str, - decodeInfo: OrderedDict, + port: int, + decode_info: OrderedDict, interval: int, ) -> None: """Initialize Update Coordinator.""" @@ -54,7 +60,7 @@ def __init__( ) self.api = VictronHub(host, port) self.api.connect() - self.decodeInfo = decodeInfo + self.decodeInfo = decode_info self.interval = interval # async def force_update_data(self) -> None: @@ -62,20 +68,21 @@ def __init__( # self.async_set_updated_data(data) async def _async_update_data(self) -> dict: - """Fetch all device and sensor data from api.""" - data = "" - """Get the latest data from victron""" + """Get the latest data from victron.""" self.logger.debug("Fetching victron data") self.logger.debug(self.decodeInfo) - parsed_data = OrderedDict() - unavailable_entities = OrderedDict() + parsed_data: dict = OrderedDict() + unavailable_entities: dict = OrderedDict() if self.data is None: - self.data = {"data": OrderedDict(), "availability": OrderedDict()} + self.data: dict[str, _DataT] = { # type: ignore[unreachable] + "data": OrderedDict(), + "availability": OrderedDict(), + } - for unit, registerInfo in self.decodeInfo.items(): - for name in registerInfo: + for unit, register_info in self.decodeInfo.items(): + for name in register_info: data = await self.fetch_registers(unit, register_info_dict[name]) # TODO safety check if result is actual data if not unavailable if data.isError(): @@ -112,7 +119,7 @@ async def _async_update_data(self) -> dict: def parse_register_data( self, buffer: ReadHoldingRegistersResponse, - registerInfo: OrderedDict(str, RegisterInfo), + register_info: dict[str, RegisterInfo], unit: int, ) -> dict: """Parse the register data.""" @@ -120,79 +127,113 @@ def parse_register_data( buffer.registers, byteorder=Endian.BIG ) decoded_data = OrderedDict() - for key, value in registerInfo.items(): + for key, value in register_info.items(): full_key = str(unit) + "." + key - if value.dataType == UINT16: + if value.data_type == UINT16: decoded_data[full_key] = self.decode_scaling( decoder.decode_16bit_uint(), value.scale, value.unit ) - elif value.dataType == INT16: + elif value.data_type == INT16: decoded_data[full_key] = self.decode_scaling( decoder.decode_16bit_int(), value.scale, value.unit ) - elif value.dataType == UINT32: + elif value.data_type == UINT32: decoded_data[full_key] = self.decode_scaling( decoder.decode_32bit_uint(), value.scale, value.unit ) - elif value.dataType == INT32: + elif value.data_type == INT32: decoded_data[full_key] = self.decode_scaling( decoder.decode_32bit_int(), value.scale, value.unit ) - elif isinstance(value.dataType, STRING): + elif isinstance(value.data_type, STRING): decoded_data[full_key] = ( - decoder.decode_string(value.dataType.readLength) + decoder.decode_string(value.data_type.read_length) .split(b"\x00")[0] .decode() ) else: - raise DecodeDataTypeUnsupported( - f"Not supported dataType: {value.dataType}" + raise DecodedataTypeUnsupported( + f"Not supported data_type: {value.data_type}" ) return decoded_data - def decode_scaling(self, number, scale, unit): - """Decode the scaling.""" + def decode_scaling(self, number: float, scale: float, unit: str | None) -> float: + """Decode the scaling. + + :param number: + :param scale: + :param unit: + :return: + """ if unit == "" and scale == 1: return round(number) return number / scale - def encode_scaling(self, value, unit, scale): - """Encode the scaling.""" + def encode_scaling(self, value: float, unit: str, scale: int | None) -> Any: + """Encode the scaling. + + :param value: + :param unit: + :param scale: + :return: + """ if scale == 0: return value if unit == "" and scale == 1: return int(round(value)) - return int(value * scale) + if scale is not None: + return int(value * scale) + return None - def get_data(self): + def get_data(self) -> dict[str, _DataT]: """Return the data.""" return self.data - async def async_update_local_entry(self, key, value): - """Update the local entry.""" + async def async_update_local_entry(self, key: str, value: Any) -> Any: + """Update the local entry. + + :param key: + :param value: + :return: + """ data = self.data - data["data"][key] = value + data["data"][key] = value # type:ignore[index] self.async_set_updated_data(data) await self.async_request_refresh() - def processed_data(self): + def processed_data(self) -> Any: """Return the processed data.""" return self.data - async def fetch_registers(self, unit, registerData): - """Fetch the registers.""" + async def fetch_registers( + self, unit: str, register_data: dict[str, RegisterInfo] + ) -> Any: + """Fetch the registers. + + :param unit: + :param register_data: + :return: + """ try: # run api_update in async job return await self.hass.async_add_executor_job( - self.api_update, unit, registerData + self.api_update, unit, register_data ) except HomeAssistantError as e: raise UpdateFailed("Fetching registers failed") from e - def write_register(self, unit, address, value): - """Write to the register.""" + def write_register( + self, unit: int | None, address: float | None, value: float + ) -> None: + """Write to the register. + + :param unit: + :param address: + :param value: + :return: + """ # try: self.api_write(unit, address, value) @@ -201,29 +242,40 @@ def write_register(self, unit, address, value): # TODO raise specific write error # _LOGGER.error("failed to write to option:", e - def api_write(self, unit, address, value): + def api_write( + self, unit: int | None, address: float | None, value: float + ) -> ModbusPDU: """Write to the api.""" # recycle connection return self.api.write_register(unit=unit, address=address, value=value) - def api_update(self, unit, registerInfo): - """Update the api.""" + def api_update(self, unit: int, register_info: dict[str, RegisterInfo]) -> Any: + """Update the api. + + :param unit: + :param register_info: + :return: + """ # recycle connection return self.api.read_holding_registers( unit=unit, - address=self.api.get_first_register_id(registerInfo), - count=self.api.calculate_register_count(registerInfo), + address=self.api.get_first_register_id(register_info), + count=self.api.calculate_register_count(register_info), ) -class DecodeDataTypeUnsupported(Exception): +class DecodedataTypeUnsupported(Exception): """Exception for unsupported data type.""" class DataEntry: """Data entry class.""" - def __init__(self, unit, value) -> None: - """Initialize the data entry.""" + def __init__(self, unit: int, value: int) -> None: + """Initialize the data entry. + + :param unit: + :param value: + """ self.unit = unit self.value = value diff --git a/custom_components/victron/hub.py b/custom_components/victron/hub.py index 84f384b..19e42cd 100644 --- a/custom_components/victron/hub.py +++ b/custom_components/victron/hub.py @@ -1,13 +1,22 @@ """Support for Victron Energy devices.""" -from collections import OrderedDict + import logging import threading +from typing import Any from pymodbus.client import ModbusTcpClient +from pymodbus.pdu import ModbusPDU from homeassistant.exceptions import HomeAssistantError -from .const import INT32, STRING, UINT32, register_info_dict, valid_unit_ids +from .const import ( + INT32, + STRING, + UINT32, + RegisterInfo, + register_info_dict, + valid_unit_ids, +) _LOGGER = logging.getLogger(__name__) @@ -22,52 +31,63 @@ def __init__(self, host: str, port: int) -> None: self._client = ModbusTcpClient(host=self.host, port=self.port) self._lock = threading.Lock() - def is_still_connected(self): + def is_still_connected(self) -> Any: """Check if the connection is still open.""" return self._client.is_socket_open() - def connect(self): + def connect(self) -> Any: """Connect to the Modbus TCP server.""" return self._client.connect() - def disconnect(self): + def disconnect(self) -> Any: """Disconnect from the Modbus TCP server.""" if self._client.is_socket_open(): return self._client.close() return None - def write_register(self, unit, address, value): - """Write a register.""" + def write_register( + self, unit: int | None, address: float | None, value: float + ) -> ModbusPDU: + """Write a register. + + :param unit: + :param address: + :param value: + :return: + """ slave = int(unit) if unit else 1 return self._client.write_register(address=address, value=value, slave=slave) - def read_holding_registers(self, unit, address, count): + def read_holding_registers(self, unit: int, address: int, count: int) -> Any: """Read holding registers.""" slave = int(unit) if unit else 1 return self._client.read_holding_registers( address=address, count=count, slave=slave ) - def calculate_register_count(self, registerInfoDict: OrderedDict): + def calculate_register_count( + self, register_info_dict: dict[str, RegisterInfo] + ) -> Any: """Calculate the number of registers to read.""" - first_key = next(iter(registerInfoDict)) - last_key = next(reversed(registerInfoDict)) + first_key = next(iter(register_info_dict)) + last_key = next(reversed(register_info_dict)) end_correction = 1 - if registerInfoDict[last_key].dataType in (INT32, UINT32): + if register_info_dict[last_key].data_type in (INT32, UINT32): end_correction = 2 - elif isinstance(registerInfoDict[last_key].dataType, STRING): - end_correction = registerInfoDict[last_key].dataType.length + elif isinstance(register_info_dict[last_key].data_type, STRING): + end_correction = register_info_dict[last_key].data_type.length return ( - registerInfoDict[last_key].register - registerInfoDict[first_key].register + register_info_dict[last_key].register + - register_info_dict[first_key].register ) + end_correction - def get_first_register_id(self, registerInfoDict: OrderedDict): + def get_first_register_id(self, register_infoDict: dict[str, RegisterInfo]) -> Any: """Return first register id.""" - first_register = next(iter(registerInfoDict)) - return registerInfoDict[first_register].register + first_register = next(iter(register_infoDict)) + return register_infoDict[first_register].register - def determine_present_devices(self): + def determine_present_devices(self) -> Any: """Determine which devices are present.""" valid_devices = {} diff --git a/custom_components/victron/manifest.json b/custom_components/victron/manifest.json index 53687a2..63a96f9 100644 --- a/custom_components/victron/manifest.json +++ b/custom_components/victron/manifest.json @@ -15,6 +15,6 @@ "pymodbus>=3.7.4" ], "ssdp": [], - "version": "v0.5.0", + "version": "v0.0.0", "zeroconf": [] } diff --git a/custom_components/victron/number.py b/custom_components/victron/number.py index c489fd5..8337c07 100644 --- a/custom_components/victron/number.py +++ b/custom_components/victron/number.py @@ -2,8 +2,8 @@ from __future__ import annotations -from dataclasses import dataclass import logging +from typing import Any, dataclass_transform from homeassistant import config_entries from homeassistant.components.number import ( @@ -37,7 +37,7 @@ SliderWriteType, register_info_dict, ) -from .coordinator import victronEnergyDeviceUpdateCoordinator +from .coordinator import VictronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -48,66 +48,75 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up victron switch devices.""" - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + victron_coordinator: VictronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ config_entry.entry_id ] _LOGGER.debug("attempting to setup number entities") - descriptions = [] + descriptions: list = [] _LOGGER.debug(config_entry) # TODO cleanup if config_entry.options[CONF_ADVANCED_OPTIONS]: register_set = victron_coordinator.processed_data()["register_set"] - for slave, registerLedger in register_set.items(): - for name in registerLedger: - for register_name, registerInfo in register_info_dict[name].items(): + for slave, register_ledger in register_set.items(): + for name in register_ledger: + for register_name, register_info in register_info_dict[name].items(): _LOGGER.debug( - "unit == %s registerLedger == %s registerInfo", + "unit == %s register_ledger == %s register_info", slave, - registerLedger, + register_ledger, ) - if isinstance(registerInfo.entityType, SliderWriteType): + if isinstance(register_info.entity_type, SliderWriteType): description = VictronEntityDescription( key=register_name, name=register_name.replace("_", " "), slave=slave, - native_unit_of_measurement=registerInfo.unit, + native_unit_of_measurement=register_info.unit, mode=NumberMode.SLIDER if config_entry.options[CONF_USE_SLIDERS] else NumberMode.BOX, native_min_value=determine_min_value( - registerInfo.unit, + register_info.unit, config_entry.options, - registerInfo.entityType.powerType, - registerInfo.entityType.negative, + register_info.entity_type.power_type, + register_info.entity_type.negative, ), native_max_value=determine_max_value( - registerInfo.unit, + register_info.unit, config_entry.options, - registerInfo.entityType.powerType, + register_info.entity_type.power_type, ), entity_category=EntityCategory.CONFIG, - address=registerInfo.register, - scale=registerInfo.scale, - native_step=registerInfo.step, + address=register_info.register, + scale=register_info.scale, + native_step=register_info.step, ) _LOGGER.debug("composed description == %s", descriptions) descriptions.append(description) - entities = [] - entity = {} - for description in descriptions: - entity = description - entities.append(VictronNumber(victron_coordinator, entity)) + entities = [ + VictronNumber(victron_coordinator, description) for description in descriptions + ] + _LOGGER.debug("adding number") async_add_entities(entities) _LOGGER.debug("adding numbering") def determine_min_value( - unit, config_entry: config_entries.ConfigEntry, powerType, negative: bool -) -> int: - """Determine the minimum value for a number entity.""" + unit: str | None, + config_entry: config_entries.ConfigEntry, + power_type: str, + negative: bool, +) -> Any: + """Determine the minimum value for a number entity. + + :param unit: + :param config_entry: + :param power_type: + :param negative: + :return: + """ if unit == PERCENTAGE: return 0 if unit == UnitOfElectricPotential.VOLT: @@ -123,7 +132,7 @@ def determine_min_value( * int(config_entry[CONF_NUMBER_OF_PHASES]) * config_entry[CONF_AC_CURRENT_LIMIT] ) - if powerType == "AC" + if power_type == "AC" else ( int(config_entry[CONF_DC_SYSTEM_VOLTAGE].dc_voltage) * config_entry[CONF_DC_CURRENT_LIMIT] @@ -135,9 +144,9 @@ def determine_min_value( return 0 if unit == UnitOfElectricCurrent.AMPERE: if negative: - if powerType == "AC": + if power_type == "AC": return -config_entry[CONF_AC_CURRENT_LIMIT] - if powerType == "DC": + if power_type == "DC": return -config_entry[CONF_DC_CURRENT_LIMIT] return None return 0 @@ -145,9 +154,15 @@ def determine_min_value( def determine_max_value( - unit, config_entry: config_entries.ConfigEntry, powerType -) -> int: - """Determine the maximum value for a number entity.""" + unit: str | None, config_entry: config_entries.ConfigEntry, power_type: str +) -> Any: + """Determine the maximum value for a number entity. + + :param unit: + :param config_entry: + :param power_type: + :return: + """ if unit == PERCENTAGE: return 100 if unit == UnitOfElectricPotential.VOLT: @@ -162,7 +177,7 @@ def determine_max_value( * int(config_entry[CONF_NUMBER_OF_PHASES]) * config_entry[CONF_AC_CURRENT_LIMIT] ) - if powerType == "AC" + if power_type == "AC" else ( int(config_entry[CONF_DC_SYSTEM_VOLTAGE]) * config_entry[CONF_DC_CURRENT_LIMIT] @@ -170,15 +185,15 @@ def determine_max_value( ) return round(max_value / 100) * 100 if unit == UnitOfElectricCurrent.AMPERE: - if powerType == "AC": + if power_type == "AC": return config_entry[CONF_AC_CURRENT_LIMIT] - if powerType == "DC": + if power_type == "DC": return config_entry[CONF_DC_CURRENT_LIMIT] return None return 0 -@dataclass +@dataclass_transform(frozen_default=True) class VictronNumberMixin: """A class that describes number entities.""" @@ -186,16 +201,16 @@ class VictronNumberMixin: mode: bool | None = None -@dataclass +@dataclass_transform(frozen_default=True) class VictronNumberStep: """A class that adds stepping to number entities.""" native_step: float = 0 -@dataclass +@dataclass_transform(frozen_default=False) class VictronEntityDescription( - NumberEntityDescription, + NumberEntityDescription, # type: ignore[misc] VictronWriteBaseEntityDescription, VictronNumberMixin, VictronNumberStep, @@ -206,14 +221,14 @@ class VictronEntityDescription( key: str | None = None -class VictronNumber(NumberEntity): +class VictronNumber(NumberEntity): # type: ignore[misc] """Victron number.""" description: VictronEntityDescription def __init__( self, - coordinator: victronEnergyDeviceUpdateCoordinator, + coordinator: VictronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription, ) -> None: """Initialize the entity.""" @@ -223,7 +238,7 @@ def __init__( self.data_key = str(self.description.slave) + "." + str(self.description.key) - self._attr_native_value = self.description.value_fn( + self._attr_native_value = self.description.value_fn( # type: ignore[call-arg] self.coordinator.processed_data(), self.description.slave, self.description.key, @@ -254,10 +269,10 @@ async def async_set_native_value(self, value: float) -> None: await self.coordinator.async_update_local_entry(self.data_key, int(value)) @property - def native_value(self) -> float: + def native_value(self) -> Any: """Return the state of the entity.""" value = self.description.value_fn( - data=self.coordinator.processed_data(), + data=self.coordinator.processed_data(), # type: ignore[call-arg] slave=self.description.slave, key=self.description.key, ) @@ -268,7 +283,7 @@ def native_value(self) -> float: return value @property - def native_step(self) -> float | None: + def native_step(self) -> Any: """Return the step width of the entity.""" if ( self.description.mode != NumberMode.SLIDER @@ -287,27 +302,30 @@ def native_step(self) -> float | None: return 1 @property - def native_min_value(self) -> float: + def native_min_value(self) -> Any: """Return the minimum value of the entity.""" return self.description.native_min_value @property - def native_max_value(self) -> float: + def native_max_value(self) -> Any: """Return the maximum value of the entity.""" return self.description.native_max_value @property - def available(self) -> bool: + def available(self) -> Any: """Return True if entity is available.""" - full_key = str(self.description.slave) + "." + self.description.key + if self.description.key: + full_key = str(self.description.slave) + "." + self.description.key + else: + full_key = str(self.description.slave) + "." return self.coordinator.processed_data()["availability"][full_key] @property def device_info(self) -> entity.DeviceInfo: """Return the device info.""" return entity.DeviceInfo( - identifiers={(DOMAIN, self.unique_id.split("_")[0])}, + identifiers={(DOMAIN, self.unique_id.split("_", maxsplit=1)[0])}, name=self.unique_id.split("_")[1], - model=self.unique_id.split("_")[0], + model=self.unique_id.split("_", maxsplit=1)[0], manufacturer="victron", ) diff --git a/custom_components/victron/popBuffer.py b/custom_components/victron/popBuffer.py new file mode 100644 index 0000000..4a23896 --- /dev/null +++ b/custom_components/victron/popBuffer.py @@ -0,0 +1,42 @@ +"""popBuffer.""" + +from typing import Any + + +class PopBuffer: + """A buffer wrapper class that allows for positional awareness in buffer for decoding register data.""" + + def __init__(self, size: int) -> None: + """Buffer wrapper class that allows for positional awareness in buffer for decoding register data. + + :param size: Size of the buffer + """ + self.buffer = [None] * size + self.size: int = size + self.position = 0 + + def get_item_in_buffer(self, data_type: Any) -> None: + """Get the item in the buffer. + + :param data_type: buffer item + :return: + """ + # TODO: decomment + # match data_type: + # case UINT16: + # # Handle UINT16 + # pass + # case UINT32: + # # Handle UINT32 + # pass + # case INT16: + # # Handle INT16 + # pass + # case INT32: + # # Handle INT32 + # pass + # case _: + # raise ValueError(f"Unsupported data type: {data_type}") + item = self.buffer[self.position] + self.position += 1 + return item diff --git a/custom_components/victron/select.py b/custom_components/victron/select.py index 1b990be..56335a8 100644 --- a/custom_components/victron/select.py +++ b/custom_components/victron/select.py @@ -2,10 +2,10 @@ from __future__ import annotations -from dataclasses import dataclass from datetime import timedelta from enum import Enum import logging +from typing import Any, dataclass_transform from homeassistant.components.select import ( DOMAIN as SELECT_DOMAIN, @@ -21,7 +21,7 @@ from .base import VictronWriteBaseEntityDescription from .const import CONF_ADVANCED_OPTIONS, DOMAIN, SelectWriteType, register_info_dict -from .coordinator import victronEnergyDeviceUpdateCoordinator +from .coordinator import VictronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -32,7 +32,7 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up victron select devices.""" - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + victron_coordinator: VictronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ config_entry.entry_id ] _LOGGER.debug("attempting to setup select entities") @@ -40,47 +40,48 @@ async def async_setup_entry( # TODO cleanup if config_entry.options[CONF_ADVANCED_OPTIONS]: register_set = victron_coordinator.processed_data()["register_set"] - for slave, registerLedger in register_set.items(): - for name in registerLedger: - for register_name, registerInfo in register_info_dict[name].items(): - if isinstance(registerInfo.entityType, SelectWriteType): + for slave, register_ledger in register_set.items(): + for name in register_ledger: + for register_name, register_info in register_info_dict[name].items(): + if isinstance(register_info.entity_type, SelectWriteType): _LOGGER.debug( - "unit == %s registerLedger == %s registerInfo", + "unit == %s register_ledger == %s register_info", slave, - registerLedger, + register_ledger, ) description = VictronEntityDescription( key=register_name, name=register_name.replace("_", " "), slave=slave, - options=registerInfo.entityType.options, - address=registerInfo.register, + options=register_info.entity_type.options, + address=register_info.register, ) descriptions.append(description) _LOGGER.debug("composed description == %s", description) - entities = [] - entity = {} - for description in descriptions: - entity = description - entities.append(VictronSelect(hass, victron_coordinator, entity)) + entities = [ + VictronSelect(hass, victron_coordinator, description) + for description in descriptions + ] + _LOGGER.debug("adding selects") _LOGGER.debug(entities) async_add_entities(entities) -@dataclass +@dataclass_transform(frozen_default=True) class VictronEntityDescription( - SelectEntityDescription, VictronWriteBaseEntityDescription + SelectEntityDescription, # type: ignore[misc] + VictronWriteBaseEntityDescription, ): """Describes victron sensor entity.""" - options: Enum = None + options: type[Enum] = Enum -class VictronSelect(CoordinatorEntity, SelectEntity): +class VictronSelect(CoordinatorEntity, SelectEntity): # type: ignore[misc] """Representation of a Victron switch.""" description: VictronEntityDescription @@ -88,7 +89,7 @@ class VictronSelect(CoordinatorEntity, SelectEntity): def __init__( self, hass: HomeAssistant, - coordinator: victronEnergyDeviceUpdateCoordinator, + coordinator: VictronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription, ) -> None: """Initialize the select.""" @@ -106,14 +107,14 @@ def __init__( self.entity_id = f"{SELECT_DOMAIN}.{DOMAIN}_{self.description.key}" self._update_job = HassJob(self.async_schedule_update_ha_state) - self._unsub_update = None + self._unsub_update: bool super().__init__(coordinator) async def async_update(self) -> None: """Get the latest data and updates the states.""" _LOGGER.debug("select_async_update") try: - self._attr_native_value = self.description.value_fn( + self._attr_native_value = self.description.value_fn( # type: ignore[call-arg] self.coordinator.processed_data(), self.description.slave, self.description.key, @@ -125,8 +126,8 @@ async def async_update(self) -> None: # Cancel the currently scheduled event if there is any if self._unsub_update: - self._unsub_update() - self._unsub_update = None + self._unsub_update() # type: ignore[misc] + self._unsub_update = None # type: ignore[assignment] # Schedule the next update at exactly the next whole hour sharp self._unsub_update = event.async_track_point_in_utc_time( @@ -136,10 +137,10 @@ async def async_update(self) -> None: ) @property - def current_option(self) -> str: + def current_option(self) -> Any: """Return the currently selected option.""" return self.description.options( - self.description.value_fn( + self.description.value_fn( # type: ignore[call-arg] self.coordinator.processed_data(), self.description.slave, self.description.key, @@ -163,7 +164,7 @@ async def async_select_option(self, option: str) -> None: # TODO extract these type of property definitions to base class @property - def available(self) -> bool: + def available(self) -> Any: """Return True if entity available.""" full_key = str(self.description.slave) + "." + self.description.key return self.coordinator.processed_data()["availability"][full_key] @@ -174,6 +175,6 @@ def device_info(self) -> entity.DeviceInfo: return entity.DeviceInfo( identifiers={(DOMAIN, self.unique_id.split("_")[0])}, name=self.unique_id.split("_")[1], - model=self.unique_id.split("_")[0], + model=self.unique_id.split("_", maxsplit=1)[0], manufacturer="victron", ) diff --git a/custom_components/victron/sensor.py b/custom_components/victron/sensor.py index c349e3d..c2e6adb 100644 --- a/custom_components/victron/sensor.py +++ b/custom_components/victron/sensor.py @@ -1,7 +1,7 @@ """Support for Victron energy sensors.""" -from dataclasses import dataclass import logging +from typing import Any, dataclass_transform from homeassistant.components.sensor import ( DOMAIN as SENSOR_DOMAIN, @@ -37,7 +37,7 @@ TextReadEntityType, register_info_dict, ) -from .coordinator import victronEnergyDeviceUpdateCoordinator +from .coordinator import VictronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -49,7 +49,7 @@ async def async_setup_entry( ) -> None: """Set up Victron energy sensor entries.""" _LOGGER.debug("attempting to setup sensor entities") - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + victron_coordinator: VictronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ config_entry.entry_id ] _LOGGER.debug(victron_coordinator.processed_data()["register_set"]) @@ -57,50 +57,53 @@ async def async_setup_entry( descriptions = [] # TODO cleanup register_set = victron_coordinator.processed_data()["register_set"] - for slave, registerLedger in register_set.items(): - for name in registerLedger: - for register_name, registerInfo in register_info_dict[name].items(): + for slave, register_ledger in register_set.items(): + for name in register_ledger: + for register_name, register_info in register_info_dict[name].items(): _LOGGER.debug( - "unit == %s registerLedger == %s registerInfo", + "unit == %s register_ledger == %s register_info", slave, - registerLedger, + register_ledger, ) if config_entry.options[CONF_ADVANCED_OPTIONS]: if not isinstance( - registerInfo.entityType, ReadEntityType - ) or isinstance(registerInfo.entityType, BoolReadEntityType): + register_info.entity_type, ReadEntityType + ) or isinstance(register_info.entity_type, BoolReadEntityType): continue description = VictronEntityDescription( key=register_name, name=register_name.replace("_", " "), - native_unit_of_measurement=registerInfo.unit, - state_class=registerInfo.determine_stateclass(), + native_unit_of_measurement=register_info.unit, + state_class=register_info.determine_stateclass(), slave=slave, device_class=determine_victron_device_class( - register_name, registerInfo.unit + register_name, register_info.unit ), - entity_type=registerInfo.entityType - if isinstance(registerInfo.entityType, TextReadEntityType) + entity_type=register_info.entity_type + if isinstance(register_info.entity_type, TextReadEntityType) else None, ) _LOGGER.debug("composed description == %s", description) descriptions.append(description) - entities = [] - entity = {} - for description in descriptions: - entity = description - entities.append(VictronSensor(victron_coordinator, entity)) + entities = [ + VictronSensor(victron_coordinator, description) for description in descriptions + ] # Add an entity for each sensor type async_add_entities(entities, True) -def determine_victron_device_class(name, unit): - """Determine the device class of a sensor based on its name and unit.""" - if unit == PERCENTAGE and "soc" in name: +def determine_victron_device_class(name: str | None, unit: str | None) -> Any: + """Determine the device class of a sensor based on its name and unit. + + :param name: + :param unit: + :return: + """ + if name and unit == PERCENTAGE and "soc" in name: return SensorDeviceClass.BATTERY if unit == PERCENTAGE: return None # Device classes aren't supported for voltage deviation and other % based entities that do not report SOC, moisture or humidity @@ -120,7 +123,7 @@ def determine_victron_device_class(name, unit): SensorDeviceClass.VOLUME_STORAGE ) # Perhaps change this to water if only water is measured in volume units if unit in [member.value for member in UnitOfSpeed]: - if "meteo" in name: + if name and "meteo" in name: return SensorDeviceClass.WIND_SPEED return SensorDeviceClass.SPEED if unit in [member.value for member in UnitOfPressure]: @@ -132,19 +135,22 @@ def determine_victron_device_class(name, unit): return None -@dataclass -class VictronEntityDescription(SensorEntityDescription, VictronBaseEntityDescription): +@dataclass_transform(frozen_default=True) +class VictronEntityDescription( + SensorEntityDescription, # type: ignore[misc] + VictronBaseEntityDescription, +): """Describes victron sensor entity.""" - entity_type: ReadEntityType = None + entity_type: ReadEntityType | None = None -class VictronSensor(CoordinatorEntity, SensorEntity): +class VictronSensor(CoordinatorEntity, SensorEntity): # type: ignore[misc] """Representation of a Victron energy sensor.""" def __init__( self, - coordinator: victronEnergyDeviceUpdateCoordinator, + coordinator: VictronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription, ) -> None: """Initialize the sensor.""" @@ -168,12 +174,12 @@ def __init__( super().__init__(coordinator) - @callback + @callback # type: ignore[misc] def _handle_coordinator_update(self) -> None: """Get the latest data and updates the states.""" try: if self.available: - data = self.description.value_fn( + data = self.description.value_fn( # type: ignore[call-arg] self.coordinator.processed_data(), self.description.slave, self.description.key, @@ -181,8 +187,11 @@ def _handle_coordinator_update(self) -> None: if self.entity_type is not None and isinstance( self.entity_type, TextReadEntityType ): - if data in {item.value for item in self.entity_type.decodeEnum}: - self._attr_native_value = self.entity_type.decodeEnum( + if data in { + item.value # type: ignore[union-attr] + for item in self.entity_type.entity_type_name + }: + self._attr_native_value = self.entity_type.entity_type_name( # type: ignore[operator] data ).name.split("_DUPLICATE")[0] else: @@ -191,7 +200,7 @@ def _handle_coordinator_update(self) -> None: "The reported value %s for entity %s isn't a decobale value. Please report this error to the integrations maintainer", data, self._attr_name, - exc_info=1, + exc_info=1, # type: ignore[arg-type] ) else: self._attr_native_value = data @@ -203,7 +212,7 @@ def _handle_coordinator_update(self) -> None: self._attr_native_value = None @property - def available(self) -> bool: + def available(self) -> Any: """Return True if entity is available.""" full_key = str(self.description.slave) + "." + self.description.key return self.coordinator.processed_data()["availability"][full_key] @@ -212,8 +221,8 @@ def available(self) -> bool: def device_info(self) -> entity.DeviceInfo: """Return the device info.""" return entity.DeviceInfo( - identifiers={(DOMAIN, self.unique_id.split("_")[0])}, + identifiers={(DOMAIN, self.unique_id.split("_", maxsplit=1)[0])}, name=self.unique_id.split("_")[1], - model=self.unique_id.split("_")[0], + model=self.unique_id.split("_", maxsplit=1)[0], manufacturer="victron", # to be dynamically set for gavazzi and redflow ) diff --git a/custom_components/victron/switch.py b/custom_components/victron/switch.py index 2e496d5..51571cd 100644 --- a/custom_components/victron/switch.py +++ b/custom_components/victron/switch.py @@ -2,9 +2,8 @@ from __future__ import annotations -from dataclasses import dataclass import logging -from typing import Any, cast +from typing import Any, cast, dataclass_transform from homeassistant.components.switch import ( DOMAIN as SWITCH_DOMAIN, @@ -19,7 +18,7 @@ from .base import VictronWriteBaseEntityDescription from .const import CONF_ADVANCED_OPTIONS, DOMAIN, SwitchWriteType, register_info_dict -from .coordinator import victronEnergyDeviceUpdateCoordinator +from .coordinator import VictronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) @@ -30,7 +29,7 @@ async def async_setup_entry( async_add_entities: AddEntitiesCallback, ) -> None: """Set up victron switch devices.""" - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + victron_coordinator: VictronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ config_entry.entry_id ] _LOGGER.debug("attempting to setup switch entities") @@ -38,50 +37,51 @@ async def async_setup_entry( # TODO cleanup if config_entry.options[CONF_ADVANCED_OPTIONS]: register_set = victron_coordinator.processed_data()["register_set"] - for slave, registerLedger in register_set.items(): - for name in registerLedger: - for register_name, registerInfo in register_info_dict[name].items(): + for slave, register_ledger in register_set.items(): + for name in register_ledger: + for register_name, register_info in register_info_dict[name].items(): _LOGGER.debug( - "unit == %s registerLedger == %s registerInfo == %s", + "unit == %s register_ledger == %s register_info == %s", slave, - registerLedger, - registerInfo, + register_ledger, + register_info, ) - if isinstance(registerInfo.entityType, SwitchWriteType): + if isinstance(register_info.entity_type, SwitchWriteType): description = VictronEntityDescription( key=register_name, name=register_name.replace("_", " "), slave=slave, - address=registerInfo.register, + address=register_info.register, ) descriptions.append(description) _LOGGER.debug("composed description == %s", description) - entities = [] - entity = {} - for description in descriptions: - entity = description - entities.append(VictronSwitch(hass, victron_coordinator, entity)) + entities = [ + VictronSwitch(hass, victron_coordinator, description) + for description in descriptions + ] + _LOGGER.debug("adding switches") _LOGGER.debug(entities) async_add_entities(entities) -@dataclass +@dataclass_transform(frozen_default=True) class VictronEntityDescription( - SwitchEntityDescription, VictronWriteBaseEntityDescription + SwitchEntityDescription, # type: ignore[misc] + VictronWriteBaseEntityDescription, ): """Describes victron sensor entity.""" -class VictronSwitch(CoordinatorEntity, SwitchEntity): +class VictronSwitch(CoordinatorEntity, SwitchEntity): # type: ignore[misc] """Representation of a Victron switch.""" def __init__( self, hass: HomeAssistant, - coordinator: victronEnergyDeviceUpdateCoordinator, + coordinator: VictronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription, ) -> None: """Initialize the switch.""" @@ -119,7 +119,7 @@ async def async_turn_off(self, **kwargs: Any) -> None: @property def is_on(self) -> bool: """Return true if switch is on.""" - data = self.description.value_fn( + data = self.description.value_fn( # type: ignore[call-arg] self.coordinator.processed_data(), self.description.slave, self.description.key, @@ -127,7 +127,7 @@ def is_on(self) -> bool: return cast(bool, data) @property - def available(self) -> bool: + def available(self) -> Any: """Return True if entity is available.""" full_key = str(self.description.slave) + "." + self.description.key return self.coordinator.processed_data()["availability"][full_key] @@ -138,6 +138,6 @@ def device_info(self) -> entity.DeviceInfo: return entity.DeviceInfo( identifiers={(DOMAIN, self.unique_id.split("_")[0])}, name=self.unique_id.split("_")[1], - model=self.unique_id.split("_")[0], + model=self.unique_id.split("_", maxsplit=1)[0], manufacturer="victron", )