From 4b8f946ad4d86c6a1c9600931c1e74186a784f16 Mon Sep 17 00:00:00 2001 From: julesxxl Date: Thu, 26 Dec 2024 12:57:47 +0100 Subject: [PATCH] from PR #264: ruff format and ruff check --fix and some mypy/pylint erros and fix PR #264 and fix issues #259, #261 --- .gitignore | 1 + custom_components/victron/__init__.py | 28 +- custom_components/victron/base.py | 18 +- custom_components/victron/binary_sensor.py | 86 +- custom_components/victron/button.py | 78 +- custom_components/victron/config_flow.py | 362 ++-- custom_components/victron/const.py | 2262 +++++++++++++++----- custom_components/victron/coordinator.py | 146 +- custom_components/victron/hub.py | 37 +- custom_components/victron/manifest.json | 4 +- custom_components/victron/number.py | 257 ++- custom_components/victron/select.py | 117 +- custom_components/victron/sensor.py | 170 +- custom_components/victron/switch.py | 98 +- 14 files changed, 2601 insertions(+), 1063 deletions(-) diff --git a/.gitignore b/.gitignore index 2ac398d..1be9e74 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ custom_components/victron/__pycache__ +.DS_Store diff --git a/custom_components/victron/__init__.py b/custom_components/victron/__init__.py index f12a329..9672a6c 100644 --- a/custom_components/victron/__init__.py +++ b/custom_components/victron/__init__.py @@ -1,14 +1,22 @@ """The victron integration.""" + from __future__ import annotations from homeassistant.config_entries import ConfigEntry from homeassistant.const import Platform from homeassistant.core import HomeAssistant -from .const import DOMAIN, CONF_HOST, CONF_PORT, SCAN_REGISTERS, CONF_INTERVAL +from .const import CONF_HOST, CONF_INTERVAL, CONF_PORT, DOMAIN, SCAN_REGISTERS from .coordinator import victronEnergyDeviceUpdateCoordinator as Coordinator -PLATFORMS: list[Platform] = [Platform.SENSOR, Platform.SWITCH, Platform.NUMBER, Platform.SELECT, Platform.BINARY_SENSOR, Platform.BUTTON] +PLATFORMS: list[Platform] = [ + Platform.SENSOR, + Platform.SWITCH, + Platform.NUMBER, + Platform.SELECT, + Platform.BINARY_SENSOR, + Platform.BUTTON, +] async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: @@ -20,8 +28,13 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b # TODO 3. Store an API object for your platforms to access # hass.data[DOMAIN][entry.entry_id] = MyApi(...) - coordinator = Coordinator(hass, config_entry.options[CONF_HOST], config_entry.options[CONF_PORT], - config_entry.data[SCAN_REGISTERS], config_entry.options[CONF_INTERVAL]) + coordinator = Coordinator( + hass, + config_entry.options[CONF_HOST], + config_entry.options[CONF_PORT], + config_entry.data[SCAN_REGISTERS], + config_entry.options[CONF_INTERVAL], + ) # try: # await coordinator.async_config_entry_first_refresh() # except ConfigEntryNotReady: @@ -41,11 +54,14 @@ async def async_setup_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> b async def async_unload_entry(hass: HomeAssistant, config_entry: ConfigEntry) -> bool: """Unload a config entry.""" - if unload_ok := await hass.config_entries.async_unload_platforms(config_entry, PLATFORMS): + if unload_ok := await hass.config_entries.async_unload_platforms( + config_entry, PLATFORMS + ): hass.data[DOMAIN].pop(config_entry.entry_id) return unload_ok + async def update_listener(hass: HomeAssistant, config_entry: ConfigEntry) -> None: """Update listener.""" - await hass.config_entries.async_reload(config_entry.entry_id) \ No newline at end of file + await hass.config_entries.async_reload(config_entry.entry_id) diff --git a/custom_components/victron/base.py b/custom_components/victron/base.py index 373e27d..f5d741e 100644 --- a/custom_components/victron/base.py +++ b/custom_components/victron/base.py @@ -1,14 +1,20 @@ from collections.abc import Callable -from homeassistant.helpers.typing import StateType - from dataclasses import dataclass + from homeassistant.helpers.entity import EntityDescription +from homeassistant.helpers.typing import StateType + @dataclass class VictronBaseEntityDescription(EntityDescription): - slave: int = None - value_fn: Callable[[dict], StateType] = lambda data, slave, key: data["data"][str(slave) + "." + str(key)] + @staticmethod + def lambda_func(): + return lambda data, slave, key: data["data"][str(slave) + "." + str(key)] + + slave: int = None + value_fn: Callable[[dict], StateType] = lambda_func() -@dataclass + +@dataclass class VictronWriteBaseEntityDescription(VictronBaseEntityDescription): - address: int = None \ No newline at end of file + address: int = None diff --git a/custom_components/victron/binary_sensor.py b/custom_components/victron/binary_sensor.py index 184442f..dfaf629 100644 --- a/custom_components/victron/binary_sensor.py +++ b/custom_components/victron/binary_sensor.py @@ -1,32 +1,29 @@ """Support for Victron Energy binary sensors.""" -from __future__ import annotations - -from contextlib import suppress -from typing import cast - -from homeassistant.core import HomeAssistant, HassJob -from collections.abc import Callable -from homeassistant.helpers.typing import StateType +from __future__ import annotations from dataclasses import dataclass +import logging +from typing import cast -from homeassistant.helpers.update_coordinator import CoordinatorEntity - +from homeassistant.components.binary_sensor import ( + DOMAIN as BINARY_SENSOR_DOMAIN, + BinarySensorEntity, + BinarySensorEntityDescription, +) from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant +from homeassistant.core import HassJob, HomeAssistant +from homeassistant.helpers import entity from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers import event, entity - -from homeassistant.components.binary_sensor import BinarySensorEntityDescription, BinarySensorEntity, DOMAIN as BINARY_SENSOR_DOMAIN +from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .coordinator import victronEnergyDeviceUpdateCoordinator from .base import VictronBaseEntityDescription -from .const import DOMAIN, CONF_ADVANCED_OPTIONS, register_info_dict, BoolReadEntityType +from .const import DOMAIN, BoolReadEntityType, register_info_dict +from .coordinator import victronEnergyDeviceUpdateCoordinator -import logging _LOGGER = logging.getLogger(__name__) + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, @@ -34,21 +31,29 @@ 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][config_entry.entry_id] + victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + config_entry.entry_id + ] _LOGGER.debug(victron_coordinator.processed_data()["register_set"]) _LOGGER.debug(victron_coordinator.processed_data()["data"]) descriptions = [] - #TODO cleanup + # 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(): - _LOGGER.debug("unit == " + str(slave) + " registerLedger == " + str(registerLedger) + " registerInfo ") + _LOGGER.debug( + "unit == " + + str(slave) + + " registerLedger == " + + str(registerLedger) + + " registerInfo " + ) if isinstance(registerInfo.entityType, BoolReadEntityType): description = VictronEntityDescription( key=register_name, - name=register_name.replace('_', ' '), + name=register_name.replace("_", " "), slave=slave, ) _LOGGER.debug("composed description == " + str(description)) @@ -58,28 +63,29 @@ async def async_setup_entry( entity = {} for description in descriptions: entity = description - entities.append( - VictronBinarySensor( - victron_coordinator, - entity - )) + entities.append(VictronBinarySensor(victron_coordinator, entity)) - async_add_entities( - entities, True - ) + async_add_entities(entities, True) @dataclass -class VictronEntityDescription(BinarySensorEntityDescription, VictronBaseEntityDescription): +class VictronEntityDescription( + BinarySensorEntityDescription, VictronBaseEntityDescription +): """Describes victron sensor entity.""" + class VictronBinarySensor(CoordinatorEntity, BinarySensorEntity): """A binary sensor implementation for Victron energy device.""" - def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription) -> None: + def __init__( + self, + coordinator: victronEnergyDeviceUpdateCoordinator, + description: VictronEntityDescription, + ) -> None: """Initialize the binary sensor.""" self.description: VictronEntityDescription = description - #this needs to be changed to allow multiple of the same type + # this needs to be changed to allow multiple of the same type self._attr_device_class = description.device_class self._attr_name = f"{description.name}" @@ -97,7 +103,11 @@ def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, descriptio @property def is_on(self) -> bool: """Return True if the binary sensor is on.""" - data = self.description.value_fn(self.coordinator.processed_data(), self.description.slave, self.description.key) + data = self.description.value_fn( + self.coordinator.processed_data(), + self.description.slave, + self.description.key, + ) return cast(bool, data) @property @@ -109,10 +119,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]) - }, - name=self.unique_id.split('_')[1], - model=self.unique_id.split('_')[0], + identifiers={(DOMAIN, self.unique_id.split("_")[0])}, + name=self.unique_id.split("_")[1], + model=self.unique_id.split("_")[0], manufacturer="victron", - ) \ No newline at end of file + ) diff --git a/custom_components/victron/button.py b/custom_components/victron/button.py index e77056e..b590b2d 100644 --- a/custom_components/victron/button.py +++ b/custom_components/victron/button.py @@ -1,26 +1,29 @@ """Support for Victron energy button sensors.""" -from __future__ import annotations -from homeassistant.core import HomeAssistant, HassJob +from __future__ import annotations from dataclasses import dataclass +import logging -from homeassistant.helpers.update_coordinator import CoordinatorEntity - +from homeassistant.components.button import ( + DOMAIN as BUTTON_DOMAIN, + ButtonDeviceClass, + ButtonEntity, + ButtonEntityDescription, +) from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant -from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.core import HassJob, HomeAssistant from homeassistant.helpers import entity - -from homeassistant.components.button import ButtonEntityDescription, ButtonDeviceClass, ButtonEntity, DOMAIN as BUTTON_DOMAIN +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity from .base import VictronWriteBaseEntityDescription +from .const import CONF_ADVANCED_OPTIONS, DOMAIN, ButtonWriteType, register_info_dict from .coordinator import victronEnergyDeviceUpdateCoordinator -from .const import DOMAIN, CONF_ADVANCED_OPTIONS, register_info_dict, ButtonWriteType -import logging _LOGGER = logging.getLogger(__name__) + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, @@ -28,21 +31,29 @@ 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][config_entry.entry_id] + victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + config_entry.entry_id + ] descriptions = [] - #TODO cleanup + # 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(): - _LOGGER.debug("unit == " + str(slave) + " registerLedger == " + str(registerLedger) + " registerInfo ") + _LOGGER.debug( + "unit == " + + str(slave) + + " registerLedger == " + + str(registerLedger) + + " registerInfo " + ) if not config_entry.options[CONF_ADVANCED_OPTIONS]: - continue + continue if isinstance(registerInfo.entityType, ButtonWriteType): description = VictronEntityDescription( key=register_name, - name=register_name.replace('_', ' '), + name=register_name.replace("_", " "), slave=slave, device_class=ButtonDeviceClass.RESTART, address=registerInfo.register, @@ -54,25 +65,26 @@ async def async_setup_entry( entity = {} for description in descriptions: entity = description - entities.append( - VictronBinarySensor( - victron_coordinator, - entity - )) + entities.append(VictronBinarySensor(victron_coordinator, entity)) + + async_add_entities(entities, True) - async_add_entities( - entities, True - ) @dataclass -class VictronEntityDescription(ButtonEntityDescription, VictronWriteBaseEntityDescription): +class VictronEntityDescription( + ButtonEntityDescription, VictronWriteBaseEntityDescription +): """Describes victron sensor entity.""" class VictronBinarySensor(CoordinatorEntity, ButtonEntity): """A button implementation for Victron energy device.""" - def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription) -> None: + def __init__( + self, + coordinator: victronEnergyDeviceUpdateCoordinator, + description: VictronEntityDescription, + ) -> None: """Initialize the sensor.""" self.description: VictronEntityDescription = description self._attr_device_class = description.device_class @@ -91,7 +103,9 @@ def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, descriptio async def async_press(self) -> None: """Handle the button press.""" - self.coordinator.write_register(unit=self.description.slave, address=self.description.address, value=1) + self.coordinator.write_register( + unit=self.description.slave, address=self.description.address, value=1 + ) @property def available(self) -> bool: @@ -102,10 +116,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]) - }, - name=self.unique_id.split('_')[1], - model=self.unique_id.split('_')[0], - manufacturer="victron", - ) \ No newline at end of file + identifiers={(DOMAIN, self.unique_id.split("_")[0])}, + name=self.unique_id.split("_")[1], + model=self.unique_id.split("_")[0], + manufacturer="victron", + ) diff --git a/custom_components/victron/config_flow.py b/custom_components/victron/config_flow.py index 187b32d..1131a07 100644 --- a/custom_components/victron/config_flow.py +++ b/custom_components/victron/config_flow.py @@ -1,4 +1,5 @@ """Config flow for victron integration.""" + from __future__ import annotations import logging @@ -6,24 +7,35 @@ import voluptuous as vol - - from homeassistant import config_entries -from homeassistant.core import HomeAssistant +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback from homeassistant.data_entry_flow import FlowResult from homeassistant.exceptions import HomeAssistantError - from homeassistant.helpers.selector import ( - SelectSelectorConfig, - SelectSelector, SelectOptionDict, + SelectSelector, + SelectSelectorConfig, ) -from homeassistant.core import callback - -from homeassistant.config_entries import ConfigEntry, ConfigFlow, OptionsFlow - -from .const import DOMAIN, CONF_HOST, CONF_PORT, CONF_INTERVAL, RegisterInfo, SCAN_REGISTERS, CONF_ADVANCED_OPTIONS, CONF_DC_SYSTEM_VOLTAGE, CONF_AC_SYSTEM_VOLTAGE, CONF_DC_CURRENT_LIMIT, CONF_AC_CURRENT_LIMIT, CONF_NUMBER_OF_PHASES, CONF_USE_SLIDERS, DC_VOLTAGES, AC_VOLTAGES, PHASE_CONFIGURATIONS +from .const import ( + AC_VOLTAGES, + CONF_AC_CURRENT_LIMIT, + CONF_AC_SYSTEM_VOLTAGE, + CONF_ADVANCED_OPTIONS, + CONF_DC_CURRENT_LIMIT, + CONF_DC_SYSTEM_VOLTAGE, + CONF_HOST, + CONF_INTERVAL, + CONF_NUMBER_OF_PHASES, + CONF_PORT, + CONF_USE_SLIDERS, + DC_VOLTAGES, + DOMAIN, + PHASE_CONFIGURATIONS, + SCAN_REGISTERS, + RegisterInfo, +) from .hub import VictronHub _LOGGER = logging.getLogger(__name__) @@ -39,6 +51,7 @@ } ) + async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, Any]: """Validate the user input allows us to connect. @@ -52,22 +65,18 @@ async def validate_input(hass: HomeAssistant, data: dict[str, Any]) -> dict[str, # your_validate_func, data["username"], data["password"] # ) - _LOGGER.debug("host = "+ data[CONF_HOST]) - _LOGGER.debug("port = "+ str(data[CONF_PORT])) + _LOGGER.debug("host = " + data[CONF_HOST]) + _LOGGER.debug("port = " + str(data[CONF_PORT])) hub = VictronHub(data[CONF_HOST], data[CONF_PORT]) - - + try: hub.connect() _LOGGER.debug("connection was succesfull") - discovered_devices = await scan_connected_devices(hub=hub) - _LOGGER.debug("successfully discovered devices") - except: - _LOGGER.error("failed to connect to the victron device") - return { - "title": DOMAIN, - "data": discovered_devices - } + discovered_devices = await scan_connected_devices(hub=hub) + _LOGGER.debug("successfully discovered devices") + except HomeAssistantError: + _LOGGER.error("failed to connect to the victron device:") + return {"title": DOMAIN, "data": discovered_devices} async def scan_connected_devices(hub: VictronHub) -> list: @@ -80,6 +89,12 @@ class VictronFlowHandler(config_entries.ConfigFlow, domain=DOMAIN): _LOGGER = logging.getLogger(__name__) VERSION = 1 + def __init__(self): + self.advanced_options = None + self.interval = None + self.port = None + self.host = None + @staticmethod @callback def async_get_options_flow( @@ -96,27 +111,25 @@ async def async_step_user( return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA ) - else: - if user_input[CONF_ADVANCED_OPTIONS]: - _LOGGER.debug("configuring advanced options") - self.host = user_input[CONF_HOST] - self.port = user_input[CONF_PORT] - self.interval = user_input[CONF_INTERVAL] - self.advanced_options = user_input[CONF_ADVANCED_OPTIONS] - return await self.async_step_advanced() + if user_input[CONF_ADVANCED_OPTIONS]: + _LOGGER.debug("configuring advanced options") + self.host = user_input[CONF_HOST] + self.port = user_input[CONF_PORT] + self.interval = user_input[CONF_INTERVAL] + self.advanced_options = user_input[CONF_ADVANCED_OPTIONS] + return await self.async_step_advanced() errors = {} already_configured = False - if user_input[CONF_INTERVAL] < 1: - user_input[CONF_INTERVAL] = 1 + user_input[CONF_INTERVAL] = max(user_input[CONF_INTERVAL], 1) try: - #not yet working + # not yet working await self.async_set_unique_id("victron") self._abort_if_unique_id_configured() - except Exception as e: - errors["base"] = "already_configured" + except HomeAssistantError as e: + errors["base"] = f"already_configured: {e!s}" already_configured = True if not already_configured: @@ -126,13 +139,17 @@ async def async_step_user( errors["base"] = "cannot_connect" except InvalidAuth: errors["base"] = "invalid_auth" - except Exception: # pylint: disable=broad-except - _LOGGER.exception("Unexpected exception") + except HomeAssistantError: + _LOGGER.exception("Unexpected exception:") errors["base"] = "unknown" - - #data property can't be changed in options flow if user wants to refresh + + # data property can't be changed in options flow if user wants to refresh options = user_input - return self.async_create_entry(title=info["title"], data = { SCAN_REGISTERS: info["data"] }, options=options) + return self.async_create_entry( + title=info["title"], + data={SCAN_REGISTERS: info["data"]}, + options=options, + ) return self.async_show_form( step_id="user", data_schema=STEP_USER_DATA_SCHEMA, errors=errors @@ -144,8 +161,6 @@ async def async_step_advanced(self, user_input=None): if user_input is not None: if self.host is not None: - - options = user_input options[CONF_HOST] = self.host options[CONF_PORT] = self.port @@ -153,8 +168,12 @@ async def async_step_advanced(self, user_input=None): options[CONF_ADVANCED_OPTIONS] = bool(self.advanced_options) options[CONF_NUMBER_OF_PHASES] = int(user_input[CONF_NUMBER_OF_PHASES]) options[CONF_USE_SLIDERS] = bool(user_input[CONF_USE_SLIDERS]) - options[CONF_AC_SYSTEM_VOLTAGE] = int(user_input[CONF_AC_SYSTEM_VOLTAGE]) - options[CONF_DC_SYSTEM_VOLTAGE] = int(user_input[CONF_DC_SYSTEM_VOLTAGE]) + options[CONF_AC_SYSTEM_VOLTAGE] = int( + user_input[CONF_AC_SYSTEM_VOLTAGE] + ) + options[CONF_DC_SYSTEM_VOLTAGE] = int( + user_input[CONF_DC_SYSTEM_VOLTAGE] + ) try: info = await validate_input(self.hass, user_input) @@ -162,18 +181,24 @@ async def async_step_advanced(self, user_input=None): errors["base"] = "cannot_connect" except InvalidAuth: errors["base"] = "invalid_auth" - except Exception: # pylint: disable=broad-except + except HomeAssistantError: _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" _LOGGER.debug("setting up extra entry") - return self.async_create_entry(title=info["title"], data = { SCAN_REGISTERS: info["data"] }, options=options) + return self.async_create_entry( + title=info["title"], + data={SCAN_REGISTERS: info["data"]}, + options=options, + ) return self.async_show_form( step_id="advanced", errors=errors, data_schema=vol.Schema( { - vol.Required(CONF_AC_SYSTEM_VOLTAGE, default=str(AC_VOLTAGES["US (120)"])): SelectSelector( + vol.Required( + CONF_AC_SYSTEM_VOLTAGE, default=str(AC_VOLTAGES["US (120)"]) + ): SelectSelector( SelectSelectorConfig( options=[ SelectOptionDict(value=str(value), label=key) @@ -181,7 +206,10 @@ async def async_step_advanced(self, user_input=None): ] ), ), - vol.Required(CONF_NUMBER_OF_PHASES, default=str(PHASE_CONFIGURATIONS["single phase"])): SelectSelector( + vol.Required( + CONF_NUMBER_OF_PHASES, + default=str(PHASE_CONFIGURATIONS["single phase"]), + ): SelectSelector( SelectSelectorConfig( options=[ SelectOptionDict(value=str(value), label=key) @@ -189,8 +217,12 @@ async def async_step_advanced(self, user_input=None): ] ), ), - vol.Required(CONF_AC_CURRENT_LIMIT, default=0): vol.All(vol.Coerce(int, "must be a number")), - vol.Required(CONF_DC_SYSTEM_VOLTAGE, default=str(DC_VOLTAGES["lifepo4_12v"])): SelectSelector( + vol.Required(CONF_AC_CURRENT_LIMIT, default=0): vol.All( + vol.Coerce(int, "must be a number") + ), + vol.Required( + CONF_DC_SYSTEM_VOLTAGE, default=str(DC_VOLTAGES["lifepo4_12v"]) + ): SelectSelector( SelectSelectorConfig( options=[ SelectOptionDict(value=str(value), label=key) @@ -198,9 +230,13 @@ async def async_step_advanced(self, user_input=None): ] ), ), - vol.Required(CONF_DC_CURRENT_LIMIT, default= 0): vol.All(vol.Coerce(int, "must be a number")), - vol.Optional(CONF_USE_SLIDERS, default=True): bool - })) + vol.Required(CONF_DC_CURRENT_LIMIT, default=0): vol.All( + vol.Coerce(int, "must be a number") + ), + vol.Optional(CONF_USE_SLIDERS, default=True): bool, + } + ), + ) async def async_step_reconfigure(self, user_input: dict[str, Any] | None = None): """Add reconfigure step to allow to reconfigure a config entry.""" @@ -208,15 +244,15 @@ async def async_step_reconfigure(self, user_input: dict[str, Any] | None = None) self.context["entry_id"] ) errors = {} - + if user_input is not None: - try: + try: hub = VictronHub(user_input[CONF_HOST], user_input[CONF_PORT]) await hub.connect() _LOGGER.info("connection was succesfull") - except: - errors["base"] = "cannot_connect" - + except HomeAssistantError as e: + errors["base"] = f"cannot_connect ({e!s})" + else: new_options = config_entry.options | { CONF_HOST: user_input[CONF_HOST], @@ -233,15 +269,19 @@ async def async_step_reconfigure(self, user_input: dict[str, Any] | None = None) step_id="reconfigure", data_schema=vol.Schema( { - vol.Required(CONF_HOST, default=config_entry.options[CONF_HOST]): str, - vol.Required(CONF_PORT, default=config_entry.options[CONF_PORT]): int + vol.Required( + CONF_HOST, default=config_entry.options[CONF_HOST] + ): str, + vol.Required( + CONF_PORT, default=config_entry.options[CONF_PORT] + ): int, } ), - errors=errors + errors=errors, ) -class parsedEntry(): +class parsedEntry: def __init__(self, decoderInfo: RegisterInfo, value): self.decoderInfo = decoderInfo self.value = value @@ -261,62 +301,60 @@ async def async_step_advanced(self, user_input=None): """Handle write support and limit settings if requested.""" config = dict(self.config_entry.options) 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]} - return self.async_create_entry(title="", data = combined_config) - + # combine dictionaries with priority given to user_input + dict_priority = {1: user_input, 2: config} + combined_config = {**dict_priority[2], **dict_priority[1]} + 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.""" config = dict(self.config_entry.options) - #combine dictionaries with priority given to user_input + # combine dictionaries with priority given to user_input if user_input[CONF_RESCAN]: info = await validate_input(self.hass, config) - self.hass.config_entries.async_update_entry(self.config_entry, - data = { SCAN_REGISTERS: info["data"] }, - title="" + self.hass.config_entries.async_update_entry( + self.config_entry, data={SCAN_REGISTERS: info["data"]}, title="" ) user_input.pop(CONF_RESCAN, None) - dict_priority = {1 : user_input, 2: config} - combined_config = {**dict_priority[2], **dict_priority[1]} + dict_priority = {1: user_input, 2: config} + combined_config = {**dict_priority[2], **dict_priority[1]} if user_input[CONF_ADVANCED_OPTIONS]: - self.hass.config_entries.async_update_entry(self.config_entry, - options=combined_config, title="") + self.hass.config_entries.async_update_entry( + self.config_entry, options=combined_config, title="" + ) _LOGGER.debug("returning step init because advanced options were selected") errors = {} - #move to dedicated function (the write show form) to allow for re-use + # move to dedicated function (the write show form) to allow for re-use return self.init_write_form(errors) - else: - return self.async_create_entry(title="", data = combined_config) + 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.""" config = dict(self.config_entry.options) - #remove temp options = + # remove temp options = if user_input[CONF_RESCAN]: info = await validate_input(self.hass, config) - self.hass.config_entries.async_update_entry(self.config_entry, - data = { SCAN_REGISTERS: info["data"] }, - title="" + self.hass.config_entries.async_update_entry( + self.config_entry, data={SCAN_REGISTERS: info["data"]}, title="" ) 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]} + # combine dictionaries with priority given to user_input + dict_priority = {1: user_input, 2: config} + combined_config = {**dict_priority[2], **dict_priority[1]} if not user_input[CONF_ADVANCED_OPTIONS]: - self.hass.config_entries.async_update_entry(self.config_entry, - options=combined_config, title="") + self.hass.config_entries.async_update_entry( + self.config_entry, options=combined_config, title="" + ) _LOGGER.debug("returning step init because advanced options were selected") errors = {} - #move to dedicated function (the write show form) to allow for re-use + # 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) + return self.async_create_entry(title="", data=combined_config) async def async_step_init( self, user_input: dict[str, Any] | None = None @@ -324,44 +362,40 @@ async def async_step_init( """Handle a flow initiated by the user.""" errors = {} - config = dict(self.config_entry.options) if user_input is not None: - if user_input[CONF_INTERVAL] not in (None, ""): config[CONF_INTERVAL] = user_input[CONF_INTERVAL] try: if user_input[CONF_RESCAN]: info = await validate_input(self.hass, self.config_entry.options) - #config[SCAN_REGISTERS] = info["data"] + # config[SCAN_REGISTERS] = info["data"] _LOGGER.debug(info) except CannotConnect: errors["base"] = "cannot_connect" except InvalidAuth: errors["base"] = "invalid_auth" - except Exception: # pylint: disable=broad-except + except HomeAssistantError: _LOGGER.exception("Unexpected exception") errors["base"] = "unknown" - + if user_input[CONF_RESCAN]: - self.hass.config_entries.async_update_entry(self.config_entry, - data = { SCAN_REGISTERS: info["data"] }, - title="" + self.hass.config_entries.async_update_entry( + self.config_entry, data={SCAN_REGISTERS: info["data"]}, title="" ) - #return self.async_create_entry(title="", data={}) + # return self.async_create_entry(title="", data={}) - return self.async_create_entry(title="", data = config) + return self.async_create_entry(title="", data=config) if config[CONF_ADVANCED_OPTIONS]: _LOGGER.debug("advanced options is set") return self.init_write_form(errors) - else: - if user_input is None: - return self.init_read_form(errors) - + if user_input is None: + return self.init_read_form(errors) + return None def init_read_form(self, errors: dict): return self.async_show_form( @@ -373,69 +407,103 @@ def init_read_form(self, errors: dict): CONF_INTERVAL, default=self.config_entry.options[CONF_INTERVAL] ): vol.All(vol.Coerce(int)), vol.Optional(CONF_RESCAN, default=False): bool, - vol.Optional(CONF_ADVANCED_OPTIONS, default=False): bool + vol.Optional(CONF_ADVANCED_OPTIONS, default=False): bool, }, ), ) def init_write_form(self, errors: dict): config = dict(self.config_entry.options) - system_ac_voltage_default = self.config_entry.options.get(CONF_AC_SYSTEM_VOLTAGE, AC_VOLTAGES["US (120)"]) - system_dc_voltage_default = self.config_entry.options.get(CONF_DC_SYSTEM_VOLTAGE, DC_VOLTAGES["lifepo4_12v"]) - system_number_of_phases_default = self.config_entry.options.get(CONF_NUMBER_OF_PHASES, PHASE_CONFIGURATIONS["single phase"]) + system_ac_voltage_default = self.config_entry.options.get( + CONF_AC_SYSTEM_VOLTAGE, AC_VOLTAGES["US (120)"] + ) + system_dc_voltage_default = self.config_entry.options.get( + CONF_DC_SYSTEM_VOLTAGE, DC_VOLTAGES["lifepo4_12v"] + ) + system_number_of_phases_default = self.config_entry.options.get( + CONF_NUMBER_OF_PHASES, PHASE_CONFIGURATIONS["single phase"] + ) errors = {} return self.async_show_form( - step_id="init_write", - errors=errors, - data_schema=vol.Schema( - { - vol.Required( - CONF_INTERVAL, default=self.config_entry.options[CONF_INTERVAL] - ): vol.All(vol.Coerce(int)), - vol.Required(CONF_AC_SYSTEM_VOLTAGE, default=str(system_ac_voltage_default)): SelectSelector( - SelectSelectorConfig( - options=[ - SelectOptionDict(value=str(value), label=key) - for key, value in AC_VOLTAGES.items() - ] - ), + step_id="init_write", + errors=errors, + data_schema=vol.Schema( + { + vol.Required( + CONF_INTERVAL, default=self.config_entry.options[CONF_INTERVAL] + ): vol.All(vol.Coerce(int)), + vol.Required( + CONF_AC_SYSTEM_VOLTAGE, default=str(system_ac_voltage_default) + ): SelectSelector( + SelectSelectorConfig( + options=[ + SelectOptionDict(value=str(value), label=key) + for key, value in AC_VOLTAGES.items() + ] ), - vol.Required(CONF_NUMBER_OF_PHASES, default=str(system_number_of_phases_default)): SelectSelector( - SelectSelectorConfig( - options=[ - SelectOptionDict(value=str(value), label=key) - for key, value in PHASE_CONFIGURATIONS.items() - ] - ), + ), + vol.Required( + CONF_NUMBER_OF_PHASES, + default=str(system_number_of_phases_default), + ): SelectSelector( + SelectSelectorConfig( + options=[ + SelectOptionDict(value=str(value), label=key) + for key, value in PHASE_CONFIGURATIONS.items() + ] ), - vol.Required(CONF_AC_CURRENT_LIMIT, default=config.get(CONF_AC_CURRENT_LIMIT, 1)): vol.All(vol.Coerce(int, "must be the max current of a single phase as a number")), - vol.Required(CONF_DC_SYSTEM_VOLTAGE, default=str(system_dc_voltage_default)): SelectSelector( - SelectSelectorConfig( - options=[ - SelectOptionDict(value=str(value), label=key) - for key, value in DC_VOLTAGES.items() - ] - ), + ), + vol.Required( + CONF_AC_CURRENT_LIMIT, + default=config.get(CONF_AC_CURRENT_LIMIT, 1), + ): vol.All( + vol.Coerce( + int, "must be the max current of a single phase as a number" + ) + ), + vol.Required( + CONF_DC_SYSTEM_VOLTAGE, default=str(system_dc_voltage_default) + ): SelectSelector( + SelectSelectorConfig( + options=[ + SelectOptionDict(value=str(value), label=key) + for key, value in DC_VOLTAGES.items() + ] ), - vol.Required(CONF_DC_CURRENT_LIMIT, default=config.get(CONF_DC_CURRENT_LIMIT,1)): vol.All(vol.Coerce(int, "must be the total DC current for the system as a number")), - vol.Optional(CONF_USE_SLIDERS, default=config.get(CONF_USE_SLIDERS, config.get(CONF_USE_SLIDERS, True))): bool, - vol.Optional(CONF_RESCAN, default=False): bool, - vol.Optional(CONF_ADVANCED_OPTIONS, default=True): bool - }, - ), - ) + ), + vol.Required( + CONF_DC_CURRENT_LIMIT, + default=config.get(CONF_DC_CURRENT_LIMIT, 1), + ): vol.All( + vol.Coerce( + int, + "must be the total DC current for the system as a number", + ) + ), + vol.Optional( + CONF_USE_SLIDERS, + default=config.get( + CONF_USE_SLIDERS, config.get(CONF_USE_SLIDERS, True) + ), + ): bool, + vol.Optional(CONF_RESCAN, default=False): bool, + vol.Optional(CONF_ADVANCED_OPTIONS, default=True): bool, + }, + ), + ) - def get_dict_key(self, dict, val): + @staticmethod + def get_dict_key(dict, val): for key, value in dict.items(): if val == value: return key - + return "key doesn't exist" + class CannotConnect(HomeAssistantError): """Error to indicate we cannot connect.""" class InvalidAuth(HomeAssistantError): """Error to indicate there is invalid auth.""" - diff --git a/custom_components/victron/const.py b/custom_components/victron/const.py index bd19267..98c427a 100644 --- a/custom_components/victron/const.py +++ b/custom_components/victron/const.py @@ -1,24 +1,25 @@ """Constants for the victron integration.""" + from enum import Enum + +from homeassistant.components.sensor import SensorStateClass from homeassistant.const import ( PERCENTAGE, - UnitOfPower, - UnitOfEnergy, - UnitOfElectricPotential, + REVOLUTIONS_PER_MINUTE, UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, UnitOfFrequency, - UnitOfLength, - UnitOfTime, - REVOLUTIONS_PER_MINUTE, UnitOfIrradiance, + UnitOfLength, UnitOfPower, + UnitOfPressure, + UnitOfSpeed, UnitOfTemperature, + UnitOfTime, UnitOfVolume, - UnitOfSpeed, - UnitOfPressure, ) - -from homeassistant.components.sensor import SensorStateClass + class DeviceType(Enum): GRID = 1 @@ -38,80 +39,110 @@ class DeviceType(Enum): CONF_DC_CURRENT_LIMIT = "dc_current" CONF_DC_SYSTEM_VOLTAGE = "dc_voltage" CONF_AC_SYSTEM_VOLTAGE = "ac_voltage" -CONF_NUMBER_OF_PHASES = "number_of_phases" +CONF_NUMBER_OF_PHASES = "number_of_phases" CONF_USE_SLIDERS = "use_sliders" -AC_VOLTAGES = { "US (120)": 120, "EU (230)": 230 } # For now only most common voltages supported -DC_VOLTAGES = { "lifepo4_12v": 12, "lifepo4_24v": 24, "lifepo4_48v": 48 } #only 3 volt nominal 4s, 8s and 16s lifepo4 configurations currently supported -PHASE_CONFIGURATIONS = { "single phase": 1, "split phase": 2, "three phase": 3 } +AC_VOLTAGES = { + "US (120)": 120, + "EU (230)": 230, +} # For now only most common voltages supported +DC_VOLTAGES = { + "lifepo4_12v": 12, + "lifepo4_24v": 24, + "lifepo4_48v": 48, +} # only 3 volt nominal 4s, 8s and 16s lifepo4 configurations currently supported +PHASE_CONFIGURATIONS = {"single phase": 1, "split phase": 2, "three phase": 3} + -class STRING(): +class STRING: def __init__(self, length=1, read_length=None): self.length = length - self.readLength = read_length if read_length is not None else length*2 + self.readLength = read_length if read_length is not None else length * 2 -#maybe change to enum Enum('UINT16', 'UINT32') + +# maybe change to enum Enum('UINT16', 'UINT32') UINT16 = "uint16" -INT16 = "int16" +INT16 = "int16" UINT32 = "uint32" -INT32 = "int32" +INT32 = "int32" UINT16_MAX = 65535 -class EntityType(): + +class EntityType: def __init__(self, entityTypeName) -> None: self.entityTypeName = entityTypeName + class ReadEntityType(EntityType): def __init__(self, entityTypeName: str = "read") -> None: super().__init__(entityTypeName=entityTypeName) + class TextReadEntityType(ReadEntityType): def __init__(self, decodeEnum: Enum) -> None: super().__init__() self.decodeEnum = decodeEnum + class BoolReadEntityType(ReadEntityType): def __init__(self) -> None: super().__init__(entityTypeName="bool") + class ButtonWriteType(EntityType): def __init__(self) -> None: super().__init__(entityTypeName="button") + class SwitchWriteType(EntityType): def __init__(self) -> None: super().__init__(entityTypeName="switch") + class SliderWriteType(EntityType): - def __init__(self, powerType="", negative: bool=False) -> None: + def __init__(self, powerType="", negative: bool = False) -> None: super().__init__(entityTypeName="slider") self.powerType = powerType self.negative = negative - + + class SelectWriteType(EntityType): def __init__(self, optionsEnum: Enum) -> None: super().__init__(entityTypeName="select") self.options = optionsEnum -class RegisterInfo(): - def __init__(self, register, dataType, unit="", scale=1, entityType: EntityType = ReadEntityType(), step=0) -> None: +class RegisterInfo: + def __init__( + self, + register, + dataType, + unit="", + scale=1, + entityType: EntityType = ReadEntityType(), + step=0, + ) -> None: self.register = register self.dataType = dataType - self.unit = unit if not isinstance(entityType, TextReadEntityType) and not isinstance(dataType, STRING) else None + self.unit = ( + unit + if not isinstance(entityType, TextReadEntityType) + and not isinstance(dataType, STRING) + else None + ) self.scale = scale self.step = step - #Only used for writeable entities + # Only used for writeable entities self.entityType = entityType def determine_stateclass(self): if self.unit == UnitOfEnergy.KILO_WATT_HOUR: return SensorStateClass.TOTAL_INCREASING - elif self.unit is None: + if self.unit is None: return None - else: - return SensorStateClass.MEASUREMENT + return SensorStateClass.MEASUREMENT + class generic_alarm_ledger(Enum): OK = 0 @@ -119,16 +150,28 @@ class generic_alarm_ledger(Enum): ALARM = 2 -gavazi_grid_registers = { +gavazi_grid_registers = { "grid_L1_power": RegisterInfo(2600, INT16, UnitOfPower.WATT), "grid_L2_power": RegisterInfo(2601, INT16, UnitOfPower.WATT), "grid_L3_power": RegisterInfo(2602, INT16, UnitOfPower.WATT), - "grid_L1_energy_forward": RegisterInfo(2603, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L3_energy_forward": RegisterInfo(2605, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L2_energy_forward": RegisterInfo(2604, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L1_energy_reverse": RegisterInfo(2606, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L2_energy_reverse": RegisterInfo(2607, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L3_energy_reverse": RegisterInfo(2608, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), + "grid_L1_energy_forward": RegisterInfo( + 2603, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L3_energy_forward": RegisterInfo( + 2605, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L2_energy_forward": RegisterInfo( + 2604, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L1_energy_reverse": RegisterInfo( + 2606, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L2_energy_reverse": RegisterInfo( + 2607, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L3_energy_reverse": RegisterInfo( + 2608, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), "grid_serial": RegisterInfo(2609, STRING(7)), "grid_L1_voltage": RegisterInfo(2616, UINT16, UnitOfElectricPotential.VOLT, 10), "grid_L1_current": RegisterInfo(2617, INT16, UnitOfElectricCurrent.AMPERE, 10), @@ -136,27 +179,46 @@ class generic_alarm_ledger(Enum): "grid_L2_current": RegisterInfo(2619, INT16, UnitOfElectricCurrent.AMPERE, 10), "grid_L3_voltage": RegisterInfo(2620, UINT16, UnitOfElectricPotential.VOLT, 10), "grid_L3_current": RegisterInfo(2621, INT16, UnitOfElectricCurrent.AMPERE, 10), - "grid_L1_energy_forward_total": RegisterInfo(2622, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L2_energy_forward_total": RegisterInfo(2624, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L3_energy_forward_total": RegisterInfo(2626, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L1_energy_reverse_total": RegisterInfo(2628, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L2_energy_reverse_total": RegisterInfo(2630, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_L3_energy_reverse_total": RegisterInfo(2632, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_energy_forward_total": RegisterInfo(2634, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "grid_energy_reverse_total": RegisterInfo(2636, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100) + "grid_L1_energy_forward_total": RegisterInfo( + 2622, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L2_energy_forward_total": RegisterInfo( + 2624, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L3_energy_forward_total": RegisterInfo( + 2626, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L1_energy_reverse_total": RegisterInfo( + 2628, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L2_energy_reverse_total": RegisterInfo( + 2630, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_L3_energy_reverse_total": RegisterInfo( + 2632, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_energy_forward_total": RegisterInfo( + 2634, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "grid_energy_reverse_total": RegisterInfo( + 2636, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), } - + + class vebus_mode(Enum): CHARGER = 1 INVERTER = 2 ON = 3 OFF = 4 + class generic_activeinput(Enum): AC_INPUT_1 = 0 AC_INPUT_2 = 1 DISCONNECTED = 240 + class generic_charger_state(Enum): OFF = 0 LOW_POWER = 1 @@ -172,6 +234,7 @@ class generic_charger_state(Enum): POWER_SUPPLY = 11 EXTERNAL_CONTROL = 252 + class vebus_error(Enum): OK = 0 EXTERNAL_PHASE_TRIGGERED_SWITCHOFF = 1 @@ -191,19 +254,38 @@ class vebus_error(Enum): FIRMWARE_INCOMPATIBILTIY = 25 INTERNAL_ERROR = 26 -vebus_registers = { - "vebus_activein_L1_voltage": RegisterInfo(3, UINT16, UnitOfElectricPotential.VOLT, 10), - "vebus_activein_L2_voltage": RegisterInfo(4, UINT16, UnitOfElectricPotential.VOLT, 10), - "vebus_activein_L3_voltage": RegisterInfo(5, UINT16, UnitOfElectricPotential.VOLT, 10), - "vebus_activein_L1_current": RegisterInfo(6, INT16, UnitOfElectricCurrent.AMPERE, 10), - "vebus_activein_L2_current": RegisterInfo(7, INT16, UnitOfElectricCurrent.AMPERE, 10), - "vebus_activein_L3_current": RegisterInfo(8, INT16, UnitOfElectricCurrent.AMPERE, 10), + +vebus_registers = { + "vebus_activein_L1_voltage": RegisterInfo( + 3, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "vebus_activein_L2_voltage": RegisterInfo( + 4, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "vebus_activein_L3_voltage": RegisterInfo( + 5, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "vebus_activein_L1_current": RegisterInfo( + 6, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "vebus_activein_L2_current": RegisterInfo( + 7, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "vebus_activein_L3_current": RegisterInfo( + 8, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), "vebus_activein_L1_frequency": RegisterInfo(9, INT16, UnitOfFrequency.HERTZ, 100), "vebus_activein_L2_frequency": RegisterInfo(10, INT16, UnitOfFrequency.HERTZ, 100), - "vebus_activein_L3_frequency": RegisterInfo(11,INT16, UnitOfFrequency.HERTZ, 100), - "vebus_activein_L1_power": RegisterInfo(12, INT16, UnitOfPower.WATT, 0.1), # could be either POWER_WATT or POWER_VOLT_AMPERE W was chosen - "vebus_activein_L2_power": RegisterInfo(13, INT16, UnitOfPower.WATT, 0.1), # could be either POWER_WATT or POWER_VOLT_AMPERE W was chosen - "vebus_activein_L3_power": RegisterInfo(14, INT16, UnitOfPower.WATT, 0.1), # could be either POWER_WATT or POWER_VOLT_AMPERE W was chosen + "vebus_activein_L3_frequency": RegisterInfo(11, INT16, UnitOfFrequency.HERTZ, 100), + "vebus_activein_L1_power": RegisterInfo( + 12, INT16, UnitOfPower.WATT, 0.1 + ), # could be either POWER_WATT or POWER_VOLT_AMPERE W was chosen + "vebus_activein_L2_power": RegisterInfo( + 13, INT16, UnitOfPower.WATT, 0.1 + ), # could be either POWER_WATT or POWER_VOLT_AMPERE W was chosen + "vebus_activein_L3_power": RegisterInfo( + 14, INT16, UnitOfPower.WATT, 0.1 + ), # could be either POWER_WATT or POWER_VOLT_AMPERE W was chosen "vebus_out_L1_voltage": RegisterInfo(15, UINT16, UnitOfElectricPotential.VOLT, 10), "vebus_out_L2_voltage": RegisterInfo(16, UINT16, UnitOfElectricPotential.VOLT, 10), "vebus_out_L3_voltage": RegisterInfo(17, UINT16, UnitOfElectricPotential.VOLT, 10), @@ -211,58 +293,199 @@ class vebus_error(Enum): "vebus_out_L2_current": RegisterInfo(19, INT16, UnitOfElectricCurrent.AMPERE, 10), "vebus_out_L3_current": RegisterInfo(20, INT16, UnitOfElectricCurrent.AMPERE, 10), "vebus_out_L1_frequency": RegisterInfo(21, INT16, UnitOfFrequency.HERTZ, 100), - "vebus_activein_currentlimit": RegisterInfo(22, INT16, UnitOfElectricCurrent.AMPERE, 10, SliderWriteType("AC", True)), + "vebus_activein_currentlimit": RegisterInfo( + 22, INT16, UnitOfElectricCurrent.AMPERE, 10, SliderWriteType("AC", True) + ), "vebus_out_L1_power": RegisterInfo(23, INT16, UnitOfPower.WATT, 0.1), "vebus_out_L2_power": RegisterInfo(24, INT16, UnitOfPower.WATT, 0.1), "vebus_out_L3_power": RegisterInfo(25, INT16, UnitOfPower.WATT, 0.1), - "vebus_battery_voltage": RegisterInfo(26, UINT16, UnitOfElectricPotential.VOLT, 100), + "vebus_battery_voltage": RegisterInfo( + 26, UINT16, UnitOfElectricPotential.VOLT, 100 + ), "vebus_battery_current": RegisterInfo(27, INT16, UnitOfElectricCurrent.AMPERE, 10), - "vebus_numberofphases": RegisterInfo(28, UINT16), #the number count has no unit of measurement - "vebus_activein_activeinput": RegisterInfo(register=29, dataType=UINT16, entityType=TextReadEntityType(generic_activeinput)), + "vebus_numberofphases": RegisterInfo( + 28, UINT16 + ), # the number count has no unit of measurement + "vebus_activein_activeinput": RegisterInfo( + register=29, dataType=UINT16, entityType=TextReadEntityType(generic_activeinput) + ), "vebus_soc": RegisterInfo(30, UINT16, PERCENTAGE, 10, SliderWriteType()), - "vebus_state": RegisterInfo(register=31, dataType=UINT16, entityType=TextReadEntityType(generic_charger_state)), #This has no unit of measurement - "vebus_error": RegisterInfo(register=32, dataType=UINT16, entityType=TextReadEntityType(vebus_error)), #This has no unit of measurement - "vebus_mode": RegisterInfo(register=33, dataType=UINT16, entityType=SelectWriteType(vebus_mode)), #This has no unit of measurement - "vebus_alarm_hightemperature": RegisterInfo(register=34, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_lowbattery": RegisterInfo(register=35, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_overload": RegisterInfo(register=36,dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_L1_acpowersetpoint": RegisterInfo(register=37, dataType=INT16, unit=UnitOfPower.WATT, entityType=SliderWriteType("AC", True)), - "vebus_disablecharge": RegisterInfo(register=38, dataType=UINT16, entityType=SwitchWriteType()), #This has no unit of measurement - "vebus_disablefeedin": RegisterInfo(39, UINT16, entityType=SwitchWriteType()), #This has no unit of measurement - "vebus_L2_acpowersetpoint": RegisterInfo(register=40, dataType=INT16, unit=UnitOfPower.WATT, entityType=SliderWriteType("AC", True)), - "vebus_L3_acpowersetpoint": RegisterInfo(register=41, dataType=INT16, unit=UnitOfPower.WATT, entityType=SliderWriteType("AC", True)), - "vebus_alarm_temperaturesensor": RegisterInfo(register=42, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_voltagesensor": RegisterInfo(register=43, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L1_higtemperature": RegisterInfo(register=44, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L1_lowbattery": RegisterInfo(register=45, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L1_overload": RegisterInfo(register=46, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L1_ripple": RegisterInfo(register=47, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L2_higtemperature": RegisterInfo(register=48, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L2_lowbattery": RegisterInfo(register=49, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L2_overload": RegisterInfo(register=50, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L2_ripple": RegisterInfo(register=51, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L3_higtemperature": RegisterInfo(register=52, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L3_lowbattery": RegisterInfo(register=53, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L3_overload": RegisterInfo(register=54, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_L3_ripple": RegisterInfo(register=55, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_pvinverter_disable": RegisterInfo(register=56, dataType=UINT16, entityType=SwitchWriteType()), #This has no unit of measurement - "vebus_bms_allowtocharge": RegisterInfo(register=57, dataType=UINT16, entityType=BoolReadEntityType()), #This has no unit of measurement - "vebus_bms_allowtodischarge": RegisterInfo(register=58, dataType=UINT16, entityType=BoolReadEntityType()), #This has no unit of measurement - "vebus_bms_bmsexpected": RegisterInfo(register=59, dataType=UINT16, entityType=BoolReadEntityType()), #This has no unit of measurement - "vebus_bms_error": RegisterInfo(register=60, dataType=UINT16, entityType=BoolReadEntityType()), #This has no unit of measurement + "vebus_state": RegisterInfo( + register=31, + dataType=UINT16, + entityType=TextReadEntityType(generic_charger_state), + ), # This has no unit of measurement + "vebus_error": RegisterInfo( + register=32, dataType=UINT16, entityType=TextReadEntityType(vebus_error) + ), # This has no unit of measurement + "vebus_mode": RegisterInfo( + register=33, dataType=UINT16, entityType=SelectWriteType(vebus_mode) + ), # This has no unit of measurement + "vebus_alarm_hightemperature": RegisterInfo( + register=34, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_lowbattery": RegisterInfo( + register=35, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_overload": RegisterInfo( + register=36, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_L1_acpowersetpoint": RegisterInfo( + register=37, + dataType=INT16, + unit=UnitOfPower.WATT, + entityType=SliderWriteType("AC", True), + ), + "vebus_disablecharge": RegisterInfo( + register=38, dataType=UINT16, entityType=SwitchWriteType() + ), # This has no unit of measurement + "vebus_disablefeedin": RegisterInfo( + 39, UINT16, entityType=SwitchWriteType() + ), # This has no unit of measurement + "vebus_L2_acpowersetpoint": RegisterInfo( + register=40, + dataType=INT16, + unit=UnitOfPower.WATT, + entityType=SliderWriteType("AC", True), + ), + "vebus_L3_acpowersetpoint": RegisterInfo( + register=41, + dataType=INT16, + unit=UnitOfPower.WATT, + entityType=SliderWriteType("AC", True), + ), + "vebus_alarm_temperaturesensor": RegisterInfo( + register=42, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_voltagesensor": RegisterInfo( + register=43, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L1_higtemperature": RegisterInfo( + register=44, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L1_lowbattery": RegisterInfo( + register=45, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L1_overload": RegisterInfo( + register=46, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L1_ripple": RegisterInfo( + register=47, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L2_higtemperature": RegisterInfo( + register=48, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L2_lowbattery": RegisterInfo( + register=49, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L2_overload": RegisterInfo( + register=50, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L2_ripple": RegisterInfo( + register=51, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L3_higtemperature": RegisterInfo( + register=52, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L3_lowbattery": RegisterInfo( + register=53, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L3_overload": RegisterInfo( + register=54, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_L3_ripple": RegisterInfo( + register=55, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_pvinverter_disable": RegisterInfo( + register=56, dataType=UINT16, entityType=SwitchWriteType() + ), # This has no unit of measurement + "vebus_bms_allowtocharge": RegisterInfo( + register=57, dataType=UINT16, entityType=BoolReadEntityType() + ), # This has no unit of measurement + "vebus_bms_allowtodischarge": RegisterInfo( + register=58, dataType=UINT16, entityType=BoolReadEntityType() + ), # This has no unit of measurement + "vebus_bms_bmsexpected": RegisterInfo( + register=59, dataType=UINT16, entityType=BoolReadEntityType() + ), # This has no unit of measurement + "vebus_bms_error": RegisterInfo( + register=60, dataType=UINT16, entityType=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()), #This has no unit of measurement - "vebus_alarm_phaserotation": RegisterInfo(register=63, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_alarm_gridlost": RegisterInfo(register=64, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), #This has no unit of measurement - "vebus_donotfeedinovervoltage": RegisterInfo(register=65, dataType=UINT16, entityType=SwitchWriteType()), #This has no unit of measurement - "vebus_L1_maxfeedinpower": RegisterInfo(66, UINT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", False)), - "vebus_L2_maxfeedinpower": RegisterInfo(67, UINT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", False)), - "vebus_L3_maxfeedinpower": RegisterInfo(68, UINT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", False)), - "vebus_state_ignoreacin1": RegisterInfo(register=69, dataType=UINT16, entityType=BoolReadEntityType()), #This has no unit of measurement - "vebus_state_ignoreacin2": RegisterInfo(register=70, dataType=UINT16, entityType=BoolReadEntityType()), #This has no unit of measurement - "vebus_targetpowerismaxfeedin": RegisterInfo(register=71, dataType=UINT16, entityType=SwitchWriteType()), #This has no unit of measurement - "vebus_fixsolaroffsetto100mv": RegisterInfo(register=72, dataType=UINT16, entityType=SwitchWriteType()), #This has no unit of measurement - "vebus_sustain": RegisterInfo(register=73, dataType=UINT16, entityType=BoolReadEntityType()), #This has no unit of measurement + "vebus_systemreset": RegisterInfo( + register=62, dataType=UINT16, entityType=ButtonWriteType() + ), # This has no unit of measurement + "vebus_alarm_phaserotation": RegisterInfo( + register=63, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_alarm_gridlost": RegisterInfo( + register=64, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), # This has no unit of measurement + "vebus_donotfeedinovervoltage": RegisterInfo( + register=65, dataType=UINT16, entityType=SwitchWriteType() + ), # This has no unit of measurement + "vebus_L1_maxfeedinpower": RegisterInfo( + 66, UINT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", False) + ), + "vebus_L2_maxfeedinpower": RegisterInfo( + 67, UINT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", False) + ), + "vebus_L3_maxfeedinpower": RegisterInfo( + 68, UINT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", False) + ), + "vebus_state_ignoreacin1": RegisterInfo( + register=69, dataType=UINT16, entityType=BoolReadEntityType() + ), # This has no unit of measurement + "vebus_state_ignoreacin2": RegisterInfo( + register=70, dataType=UINT16, entityType=BoolReadEntityType() + ), # This has no unit of measurement + "vebus_targetpowerismaxfeedin": RegisterInfo( + register=71, dataType=UINT16, entityType=SwitchWriteType() + ), # This has no unit of measurement + "vebus_fixsolaroffsetto100mv": RegisterInfo( + register=72, dataType=UINT16, entityType=SwitchWriteType() + ), # This has no unit of measurement + "vebus_sustain": RegisterInfo( + register=73, dataType=UINT16, entityType=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), "vebus_acin2toacout": RegisterInfo(78, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), @@ -272,76 +495,201 @@ class vebus_error(Enum): "vebus_invertertoacin1": RegisterInfo(86, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), "vebus_invertertoacin2": RegisterInfo(88, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), "vebus_invertertoacout": RegisterInfo(90, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "vebus_outtoinverter": RegisterInfo(92, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100) + "vebus_outtoinverter": RegisterInfo(92, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), } battery_registers = { "battery_voltage": RegisterInfo(259, UINT16, UnitOfElectricPotential.VOLT, 100), - "battery_starter_voltage": RegisterInfo(260, UINT16, UnitOfElectricPotential.VOLT, 100), + "battery_starter_voltage": RegisterInfo( + 260, UINT16, UnitOfElectricPotential.VOLT, 100 + ), "battery_current": RegisterInfo(261, INT16, UnitOfElectricCurrent.AMPERE, 10), "battery_temperature": RegisterInfo(262, INT16, UnitOfTemperature.CELSIUS, 10), "battery_midvoltage": RegisterInfo(263, UINT16, UnitOfElectricPotential.VOLT, 100), "battery_midvoltagedeviation": RegisterInfo(264, UINT16, PERCENTAGE, 100), - "battery_consumedamphours": RegisterInfo(265, UINT16, UnitOfElectricCurrent.AMPERE, -10), + "battery_consumedamphours": RegisterInfo( + 265, UINT16, UnitOfElectricCurrent.AMPERE, -10 + ), "battery_soc": RegisterInfo(266, UINT16, PERCENTAGE, 10), - "battery_alarm": RegisterInfo(register=267, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_lowvoltage": RegisterInfo(register=268, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_highvoltage": RegisterInfo(register=269, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_lowstartervoltage": RegisterInfo(register=270, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_highstartervoltage": RegisterInfo(register=271, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_lowsoc": RegisterInfo(register=272, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_lowtemperature": RegisterInfo(register=273, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_hightemperature": RegisterInfo(register=274, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_midvoltage": RegisterInfo(register=275, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_lowfusedvoltage": RegisterInfo(register=276, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_highfusedvoltage": RegisterInfo(register=277, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_fuseblown": RegisterInfo(register=278, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_highinternaltemperature": RegisterInfo(register=279, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_relay": RegisterInfo(register=280, dataType=UINT16, entityType=SwitchWriteType()), - "battery_history_deepestdischarge": RegisterInfo(281, UINT16, UnitOfElectricCurrent.AMPERE, -10), - "battery_history_lastdischarge": RegisterInfo(282, UINT16, UnitOfElectricCurrent.AMPERE, -10), - "battery_history_averagedischarge": RegisterInfo(283, UINT16, UnitOfElectricCurrent.AMPERE, -10), + "battery_alarm": RegisterInfo( + register=267, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_lowvoltage": RegisterInfo( + register=268, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_highvoltage": RegisterInfo( + register=269, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_lowstartervoltage": RegisterInfo( + register=270, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_highstartervoltage": RegisterInfo( + register=271, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_lowsoc": RegisterInfo( + register=272, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_lowtemperature": RegisterInfo( + register=273, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_hightemperature": RegisterInfo( + register=274, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_midvoltage": RegisterInfo( + register=275, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_lowfusedvoltage": RegisterInfo( + register=276, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_highfusedvoltage": RegisterInfo( + register=277, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_fuseblown": RegisterInfo( + register=278, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_highinternaltemperature": RegisterInfo( + register=279, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_relay": RegisterInfo( + register=280, dataType=UINT16, entityType=SwitchWriteType() + ), + "battery_history_deepestdischarge": RegisterInfo( + 281, UINT16, UnitOfElectricCurrent.AMPERE, -10 + ), + "battery_history_lastdischarge": RegisterInfo( + 282, UINT16, UnitOfElectricCurrent.AMPERE, -10 + ), + "battery_history_averagedischarge": RegisterInfo( + 283, UINT16, UnitOfElectricCurrent.AMPERE, -10 + ), "battery_history_chargecycles": RegisterInfo(284, UINT16), "battery_history_fulldischarges": RegisterInfo(285, UINT16), - "battery_history_totalahdrawn": RegisterInfo(286, UINT16, UnitOfElectricCurrent.AMPERE, -10), - "battery_history_minimumvoltage": RegisterInfo(287, UINT16, UnitOfElectricPotential.VOLT, 100), - "battery_history_maximumvoltage": RegisterInfo(288, UINT16, UnitOfElectricPotential.VOLT, 100), - "battery_history_timesincelastfullcharge": RegisterInfo(289, UINT16, UnitOfTime.SECONDS, 0.01), + "battery_history_totalahdrawn": RegisterInfo( + 286, UINT16, UnitOfElectricCurrent.AMPERE, -10 + ), + "battery_history_minimumvoltage": RegisterInfo( + 287, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "battery_history_maximumvoltage": RegisterInfo( + 288, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "battery_history_timesincelastfullcharge": RegisterInfo( + 289, UINT16, UnitOfTime.SECONDS, 0.01 + ), "battery_history_automaticsyncs": RegisterInfo(290, UINT16), "battery_history_lowvoltagealarms": RegisterInfo(291, UINT16), "battery_history_highvoltagealarms": RegisterInfo(292, UINT16), "battery_history_lowstartervoltagealarms": RegisterInfo(293, UINT16), "battery_history_highstartervoltagealarms": RegisterInfo(294, UINT16), - "battery_history_minimumstartervoltage": RegisterInfo(295, UINT16, UnitOfElectricPotential.VOLT, 100), - "battery_history_maximumstartervoltage": RegisterInfo(296, UINT16, UnitOfElectricPotential.VOLT, 100), + "battery_history_minimumstartervoltage": RegisterInfo( + 295, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "battery_history_maximumstartervoltage": RegisterInfo( + 296, UINT16, UnitOfElectricPotential.VOLT, 100 + ), "battery_history_lowfusedvoltagealarms": RegisterInfo(297, UINT16), "battery_history_highfusedvoltagealarms": RegisterInfo(298, UINT16), - "battery_history_minimumfusedvoltage": RegisterInfo(299, UINT16, UnitOfElectricPotential.VOLT, 100), - "battery_history_maximumfusedvoltage": RegisterInfo(300, UINT16, UnitOfElectricPotential.VOLT, 100), - "battery_history_dischargedenergy": RegisterInfo(301, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "battery_history_chargedenergy": RegisterInfo(302, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), + "battery_history_minimumfusedvoltage": RegisterInfo( + 299, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "battery_history_maximumfusedvoltage": RegisterInfo( + 300, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "battery_history_dischargedenergy": RegisterInfo( + 301, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "battery_history_chargedenergy": RegisterInfo( + 302, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), "battery_timetogo": RegisterInfo(303, UINT16, UnitOfTime.SECONDS, 0.01), "battery_soh": RegisterInfo(304, UINT16, PERCENTAGE, 10), - "battery_info_maxchargevoltage": RegisterInfo(305, UINT16, UnitOfElectricPotential.VOLT, 10), - "battery_info_batterylowvoltage": RegisterInfo(306, UINT16, UnitOfElectricPotential.VOLT, 10), - "battery_info_maxchargecurrent": RegisterInfo(307, UINT16, UnitOfElectricCurrent.AMPERE, 10), - "battery_info_maxdischargecurrent": RegisterInfo(308, UINT16, UnitOfElectricCurrent.AMPERE, 10), - "battery_capacity": RegisterInfo(309, UINT16, UnitOfElectricCurrent.AMPERE, 10), + "battery_info_maxchargevoltage": RegisterInfo( + 305, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "battery_info_batterylowvoltage": RegisterInfo( + 306, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "battery_info_maxchargecurrent": RegisterInfo( + 307, UINT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "battery_info_maxdischargecurrent": RegisterInfo( + 308, UINT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "battery_capacity": RegisterInfo(309, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 1000), "battery_diagnostics_lasterror_1_time": RegisterInfo(310, INT32, "timestamp"), "battery_diagnostics_lasterror_2_time": RegisterInfo(312, INT32, "timestamp"), "battery_diagnostics_lasterror_3_time": RegisterInfo(314, INT32, "timestamp"), "battery_diagnostics_lasterror_4_time": RegisterInfo(316, INT32, "timestamp"), - "battery_system_mincelltemperature": RegisterInfo(318, INT16, UnitOfTemperature.CELSIUS, 10), - "battery_system_maxcelltemperature": RegisterInfo(319, INT16, UnitOfTemperature.CELSIUS, 10), - "battery_alarm_higchargecurrent": RegisterInfo(register=320, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_highdischargecurrent": RegisterInfo(register=321, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_cellimbalance": RegisterInfo(register=322, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_internalfailure": RegisterInfo(register=323, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_highchargetemperature": RegisterInfo(register=324, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_lowchargetemperature": RegisterInfo(register=325, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "battery_alarm_lowcellvoltage": RegisterInfo(register=326, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)) + "battery_system_mincelltemperature": RegisterInfo( + 318, INT16, UnitOfTemperature.CELSIUS, 10 + ), + "battery_system_maxcelltemperature": RegisterInfo( + 319, INT16, UnitOfTemperature.CELSIUS, 10 + ), + "battery_alarm_higchargecurrent": RegisterInfo( + register=320, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_highdischargecurrent": RegisterInfo( + register=321, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_cellimbalance": RegisterInfo( + register=322, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_internalfailure": RegisterInfo( + register=323, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_highchargetemperature": RegisterInfo( + register=324, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_lowchargetemperature": RegisterInfo( + register=325, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "battery_alarm_lowcellvoltage": RegisterInfo( + register=326, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } + class battery_state(Enum): WAIT_START_INIT = 0 BEFORE_BOOT_INIT = 1 @@ -361,6 +709,7 @@ class battery_state(Enum): GOING_TO_RUN = 15 PRE_CHARGING = 16 + class battery_error(Enum): NONE = 0 BATTERY_INIT_ERROR = 1 @@ -400,28 +749,57 @@ class battery_error(Enum): PRE_CHARGE_TIMEOUT = 35 - battery_detail_registers = { - "battery_state": RegisterInfo(register=1282, dataType=UINT16, entityType=TextReadEntityType(battery_state)), - "battery_error": RegisterInfo(register=1283, dataType=UINT16, entityType=TextReadEntityType(battery_error)), - "battery_system_switch": RegisterInfo(register=1284, dataType=UINT16, entityType=BoolReadEntityType()), - "battery_balancing": RegisterInfo(register=1285, dataType=UINT16, entityType=BoolReadEntityType()), + "battery_state": RegisterInfo( + register=1282, dataType=UINT16, entityType=TextReadEntityType(battery_state) + ), + "battery_error": RegisterInfo( + register=1283, dataType=UINT16, entityType=TextReadEntityType(battery_error) + ), + "battery_system_switch": RegisterInfo( + register=1284, dataType=UINT16, entityType=BoolReadEntityType() + ), + "battery_balancing": RegisterInfo( + register=1285, dataType=UINT16, entityType=BoolReadEntityType() + ), "battery_system_numberofbatteries": RegisterInfo(1286, UINT16), "battery_system_batteriesparallel": RegisterInfo(1287, UINT16), "battery_system_batteriesseries": RegisterInfo(1288, UINT16), "battery_system_numberofcellsperbattery": RegisterInfo(1289, UINT16), - "battery_system_mincellvoltage": RegisterInfo(1290, UINT16, UnitOfElectricPotential.VOLT, 100), - "battery_system_maxcellvoltage": RegisterInfo(1291, UINT16, UnitOfElectricPotential.VOLT, 100), + "battery_system_mincellvoltage": RegisterInfo( + 1290, UINT16, UnitOfElectricPotential.VOLT, 1000 + ), + "battery_system_maxcellvoltage": RegisterInfo( + 1291, UINT16, UnitOfElectricPotential.VOLT, 1000 + ), "battery_diagnostics_shutdownsdueerror": RegisterInfo(1292, UINT16), - "battery_diagnostics_lasterror_1": RegisterInfo(register=1293, dataType=UINT16, entityType=TextReadEntityType(battery_error)), - "battery_diagnostics_lasterror_2": RegisterInfo(register=1294, dataType=UINT16, entityType=TextReadEntityType(battery_error)), - "battery_diagnostics_lasterror_3": RegisterInfo(register=1295, dataType=UINT16, entityType=TextReadEntityType(battery_error)), - "battery_diagnostics_lasterror_4": RegisterInfo(register=1296, dataType=UINT16, entityType=TextReadEntityType(battery_error)), - "battery_io_allowtocharge": RegisterInfo(register=1297, dataType=UINT16, entityType=BoolReadEntityType()), - "battery_io_allowtodischarge": RegisterInfo(register=1298, dataType=UINT16, entityType=BoolReadEntityType()), - "battery_io_externalrelay": RegisterInfo(register=1299, dataType=UINT16, entityType=BoolReadEntityType()), - "battery_history_minimumcellvoltage": RegisterInfo(1300, UINT16, UnitOfElectricPotential.VOLT, 100), - "battery_history_maximumcellvoltage": RegisterInfo(1301, UINT16, UnitOfElectricPotential.VOLT, 100), + "battery_diagnostics_lasterror_1": RegisterInfo( + register=1293, dataType=UINT16, entityType=TextReadEntityType(battery_error) + ), + "battery_diagnostics_lasterror_2": RegisterInfo( + register=1294, dataType=UINT16, entityType=TextReadEntityType(battery_error) + ), + "battery_diagnostics_lasterror_3": RegisterInfo( + register=1295, dataType=UINT16, entityType=TextReadEntityType(battery_error) + ), + "battery_diagnostics_lasterror_4": RegisterInfo( + register=1296, dataType=UINT16, entityType=TextReadEntityType(battery_error) + ), + "battery_io_allowtocharge": RegisterInfo( + register=1297, dataType=UINT16, entityType=BoolReadEntityType() + ), + "battery_io_allowtodischarge": RegisterInfo( + register=1298, dataType=UINT16, entityType=BoolReadEntityType() + ), + "battery_io_externalrelay": RegisterInfo( + register=1299, dataType=UINT16, entityType=BoolReadEntityType() + ), + "battery_history_minimumcellvoltage": RegisterInfo( + 1300, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "battery_history_maximumcellvoltage": RegisterInfo( + 1301, UINT16, UnitOfElectricPotential.VOLT, 100 + ), "battery_system_numberofmodulesoffline": RegisterInfo(1302, UINT16), "battery_system_numberofmodulesonline": RegisterInfo(1303, UINT16), "battery_system_numberofmodulesblockingcharge": RegisterInfo(1304, UINT16), @@ -429,13 +807,15 @@ class battery_error(Enum): "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_maxtemperaturecellid": RegisterInfo(1318, STRING(4)), } + class solarcharger_mode(Enum): ON = 1 OFF = 4 + class solarcharger_state(Enum): OFF = 0 FAULT = 2 @@ -448,12 +828,14 @@ class solarcharger_state(Enum): WAKE_UP = 245 EXTERNAL_CONTROL = 252 + class solarcharger_equalization_pending(Enum): NO = 0 YES = 1 ERROR = 2 UNAVAILABLE = 3 + class generic_charger_errorcode(Enum): NONE = 0 TEMPERATURE_HIGH = 1 @@ -473,103 +855,231 @@ class generic_charger_errorcode(Enum): CHARGER_TEMPERATURE_SENSOR_DISCONNECTED = 23 INPUT_CURRENT_TOO_HIGH = 34 + class generic_mppoperationmode(Enum): OFF = 0 LIMITED = 1 ACTIVE = 2 UNAVAILABLE = 255 + solarcharger_registers = { - "solarcharger_battery_voltage": RegisterInfo(771, UINT16, UnitOfElectricPotential.VOLT, 100), - "solarcharger_battery_current": RegisterInfo(772, INT16, UnitOfElectricCurrent.AMPERE, 10), - "solarcharger_battery_temperature": RegisterInfo(773, INT16, UnitOfTemperature.CELSIUS, 10), - "solarcharger_mode": RegisterInfo(register=774, dataType=UINT16, entityType=SelectWriteType(solarcharger_mode)), - "solarcharger_state": RegisterInfo(register=775, dataType=UINT16, entityType=TextReadEntityType(solarcharger_state)), - "solarcharger_pv_voltage": RegisterInfo(776, UINT16, UnitOfElectricPotential.VOLT, 100), - "solarcharger_pv_current": RegisterInfo(777, INT16, UnitOfElectricCurrent.AMPERE, 10), - "solarcharger_equallization_pending": RegisterInfo(register=778, dataType=UINT16, entityType=TextReadEntityType(solarcharger_equalization_pending)), - "solarcharger_equalization_time_remaining": RegisterInfo(779, UINT16, UnitOfTime.SECONDS, 10), - "solarcharger_relay": RegisterInfo(register=780, dataType=UINT16, entityType=BoolReadEntityType()), - "solarcharger_alarm": RegisterInfo(register=781, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "solarcharger_alarm_lowvoltage": RegisterInfo(register=782, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "solarcharger_alarm_highvoltage": RegisterInfo(register=783, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "solarcharger_yield_today": RegisterInfo(784, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), + "solarcharger_battery_voltage": RegisterInfo( + 771, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "solarcharger_battery_current": RegisterInfo( + 772, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "solarcharger_battery_temperature": RegisterInfo( + 773, INT16, UnitOfTemperature.CELSIUS, 10 + ), + "solarcharger_mode": RegisterInfo( + register=774, dataType=UINT16, entityType=SelectWriteType(solarcharger_mode) + ), + "solarcharger_state": RegisterInfo( + register=775, dataType=UINT16, entityType=TextReadEntityType(solarcharger_state) + ), + "solarcharger_pv_voltage": RegisterInfo( + 776, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "solarcharger_pv_current": RegisterInfo( + 777, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "solarcharger_equallization_pending": RegisterInfo( + register=778, + dataType=UINT16, + entityType=TextReadEntityType(solarcharger_equalization_pending), + ), + "solarcharger_equalization_time_remaining": RegisterInfo( + 779, UINT16, UnitOfTime.SECONDS, 10 + ), + "solarcharger_relay": RegisterInfo( + register=780, dataType=UINT16, entityType=BoolReadEntityType() + ), + "solarcharger_alarm": RegisterInfo( + register=781, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "solarcharger_alarm_lowvoltage": RegisterInfo( + register=782, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "solarcharger_alarm_highvoltage": RegisterInfo( + register=783, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "solarcharger_yield_today": RegisterInfo( + 784, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), "solarcharger_maxpower_today": RegisterInfo(785, UINT16, UnitOfPower.WATT), - "solarcharger_yield_yesterday": RegisterInfo(786, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), + "solarcharger_yield_yesterday": RegisterInfo( + 786, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), "solarcharger_maxpower_yesterday": RegisterInfo(787, UINT16, UnitOfPower.WATT), - "solarcharger_errorcode": RegisterInfo(register=788, dataType=UINT16, entityType=TextReadEntityType(generic_charger_errorcode)), + "solarcharger_errorcode": RegisterInfo( + register=788, + dataType=UINT16, + entityType=TextReadEntityType(generic_charger_errorcode), + ), "solarcharger_yield_power": RegisterInfo(789, UINT16, UnitOfPower.WATT, 10), - "solarcharger_yield_user": RegisterInfo(790, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_mppoperationmode": RegisterInfo(register=791, dataType=UINT16, entityType=TextReadEntityType(generic_mppoperationmode)) + "solarcharger_yield_user": RegisterInfo( + 790, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_mppoperationmode": RegisterInfo( + register=791, + dataType=UINT16, + entityType=TextReadEntityType(generic_mppoperationmode), + ), } solarcharger_tracker_voltage_registers = { - "solarcharger_tracker_0_voltage": RegisterInfo(3700, UINT16, UnitOfElectricPotential.VOLT, 100), - "solarcharger_tracker_1_voltage": RegisterInfo(3701, UINT16, UnitOfElectricPotential.VOLT, 100), - "solarcharger_tracker_2_voltage": RegisterInfo(3702, UINT16, UnitOfElectricPotential.VOLT, 100), - "solarcharger_tracker_3_voltage": RegisterInfo(3703, UINT16, UnitOfElectricPotential.VOLT, 100) + "solarcharger_tracker_0_voltage": RegisterInfo( + 3700, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "solarcharger_tracker_1_voltage": RegisterInfo( + 3701, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "solarcharger_tracker_2_voltage": RegisterInfo( + 3702, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "solarcharger_tracker_3_voltage": RegisterInfo( + 3703, UINT16, UnitOfElectricPotential.VOLT, 100 + ), } solarcharger_tracker_registers = { - "solarcharger_tracker_0_yield_today": RegisterInfo(3708, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_tracker_1_yield_today": RegisterInfo(3709, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_tracker_2_yield_today": RegisterInfo(3710, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_tracker_3_yield_today": RegisterInfo(3711, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_tracker_0_yield_yesterday": RegisterInfo(3712, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_tracker_1_yield_yesterday": RegisterInfo(3713, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_tracker_2_yield_yesterday": RegisterInfo(3714, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_tracker_3_yield_yesterday": RegisterInfo(3715, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "solarcharger_tracker_0_maxpower_today": RegisterInfo(3716, UINT16, UnitOfPower.WATT), - "solarcharger_tracker_1_maxpower_today": RegisterInfo(3717, UINT16, UnitOfPower.WATT), - "solarcharger_tracker_2_maxpower_today": RegisterInfo(3718, UINT16, UnitOfPower.WATT), - "solarcharger_tracker_3_maxpower_today": RegisterInfo(3719, UINT16, UnitOfPower.WATT), - "solarcharger_tracker_0_maxpower_yesterday": RegisterInfo(3720, UINT16, UnitOfPower.WATT), - "solarcharger_tracker_1_maxpower_yesterday": RegisterInfo(3721, UINT16, UnitOfPower.WATT), - "solarcharger_tracker_2_maxpower_yesterday": RegisterInfo(3722, UINT16, UnitOfPower.WATT), - "solarcharger_tracker_3_maxpower_yesterday": RegisterInfo(3723, UINT16, UnitOfPower.WATT), + "solarcharger_tracker_0_yield_today": RegisterInfo( + 3708, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_tracker_1_yield_today": RegisterInfo( + 3709, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_tracker_2_yield_today": RegisterInfo( + 3710, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_tracker_3_yield_today": RegisterInfo( + 3711, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_tracker_0_yield_yesterday": RegisterInfo( + 3712, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_tracker_1_yield_yesterday": RegisterInfo( + 3713, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_tracker_2_yield_yesterday": RegisterInfo( + 3714, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_tracker_3_yield_yesterday": RegisterInfo( + 3715, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "solarcharger_tracker_0_maxpower_today": RegisterInfo( + 3716, UINT16, UnitOfPower.WATT + ), + "solarcharger_tracker_1_maxpower_today": RegisterInfo( + 3717, UINT16, UnitOfPower.WATT + ), + "solarcharger_tracker_2_maxpower_today": RegisterInfo( + 3718, UINT16, UnitOfPower.WATT + ), + "solarcharger_tracker_3_maxpower_today": RegisterInfo( + 3719, UINT16, UnitOfPower.WATT + ), + "solarcharger_tracker_0_maxpower_yesterday": RegisterInfo( + 3720, UINT16, UnitOfPower.WATT + ), + "solarcharger_tracker_1_maxpower_yesterday": RegisterInfo( + 3721, UINT16, UnitOfPower.WATT + ), + "solarcharger_tracker_2_maxpower_yesterday": RegisterInfo( + 3722, UINT16, UnitOfPower.WATT + ), + "solarcharger_tracker_3_maxpower_yesterday": RegisterInfo( + 3723, UINT16, UnitOfPower.WATT + ), "solarcharger_tracker_0_pv_power": RegisterInfo(3724, UINT16, UnitOfPower.WATT), "solarcharger_tracker_1_pv_power": RegisterInfo(3725, UINT16, UnitOfPower.WATT), "solarcharger_tracker_2_pv_power": RegisterInfo(3726, UINT16, UnitOfPower.WATT), "solarcharger_tracker_3_pv_power": RegisterInfo(3727, UINT16, UnitOfPower.WATT), } + class generic_position(Enum): - AC_INPUT_1 = 0 - AC_OUTPUT = 1 - AC_INPUT_2 = 2 + MANUAL = 0 + AUTO = 1 + SCHEDULED = 2 + pvinverter_registers = { - "pvinverter_position": RegisterInfo(register=1026, dataType=UINT16, entityType=TextReadEntityType(generic_position)), - "pvinverter_L1_voltage": RegisterInfo(1027, UINT16, UnitOfElectricPotential.VOLT, 10), - "pvinverter_L1_current": RegisterInfo(1028, INT16, UnitOfElectricCurrent.AMPERE, 10), + "pvinverter_position": RegisterInfo( + register=1026, dataType=UINT16, entityType=TextReadEntityType(generic_position) + ), + "pvinverter_L1_voltage": RegisterInfo( + 1027, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "pvinverter_L1_current": RegisterInfo( + 1028, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), "pvinverter_L1_power": RegisterInfo(1029, UINT16, UnitOfPower.WATT), - "pvinverter_L1_energy_forward": RegisterInfo(1030, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), - "pvinverter_L2_voltage": RegisterInfo(1031, UINT16, UnitOfElectricPotential.VOLT, 10), - "pvinverter_L2_current": RegisterInfo(1032, INT16, UnitOfElectricCurrent.AMPERE, 10), + "pvinverter_L1_energy_forward": RegisterInfo( + 1030, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "pvinverter_L2_voltage": RegisterInfo( + 1031, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "pvinverter_L2_current": RegisterInfo( + 1032, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), "pvinverter_L2_power": RegisterInfo(1033, UINT16, UnitOfPower.WATT), - "pvinverter_L2_energy_forward": RegisterInfo(1034, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), - "pvinverter_L3_voltage": RegisterInfo(1035, UINT16, UnitOfElectricPotential.VOLT, 10), - "pvinverter_L3_current": RegisterInfo(1036, INT16, UnitOfElectricCurrent.AMPERE, 10), + "pvinverter_L2_energy_forward": RegisterInfo( + 1034, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "pvinverter_L3_voltage": RegisterInfo( + 1035, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "pvinverter_L3_current": RegisterInfo( + 1036, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), "pvinverter_L3_power": RegisterInfo(1037, UINT16, UnitOfPower.WATT), - "pvinverter_L3_energy_forward": RegisterInfo(1038, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100), + "pvinverter_L3_energy_forward": RegisterInfo( + 1038, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), "pvinverter_serial": RegisterInfo(1039, STRING(7)), - "pvinverter_L1_energy_forward_total": RegisterInfo(1046, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "pvinverter_L2_energy_forward_total": RegisterInfo(1048, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "pvinverter_L3_energy_forward_total": RegisterInfo(1050, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), + "pvinverter_L1_energy_forward_total": RegisterInfo( + 1046, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "pvinverter_L2_energy_forward_total": RegisterInfo( + 1048, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "pvinverter_L3_energy_forward_total": RegisterInfo( + 1050, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), "pvinverter_power_total": RegisterInfo(1052, INT32, UnitOfPower.WATT), "pvinverter_power_max_capacity": RegisterInfo(1054, UINT32, UnitOfPower.WATT), - "pvinverter_powerlimit": RegisterInfo(register=1056, dataType=UINT32, unit=UnitOfPower.WATT, entityType=SliderWriteType("AC", False)) + "pvinverter_powerlimit": RegisterInfo( + register=1056, + dataType=UINT32, + unit=UnitOfPower.WATT, + entityType=SliderWriteType("AC", False), + ), } motordrive_registers = { "motordrive_rpm": RegisterInfo(2048, INT16, REVOLUTIONS_PER_MINUTE), - "motordrive_motor_temperature": RegisterInfo(2049, INT16, UnitOfTemperature.CELSIUS, 10), + "motordrive_motor_temperature": RegisterInfo( + 2049, INT16, UnitOfTemperature.CELSIUS, 10 + ), "motordrive_voltage": RegisterInfo(2050, UINT16, UnitOfElectricPotential.VOLT, 100), "motordrive_current": RegisterInfo(2051, INT16, UnitOfElectricCurrent.AMPERE, 10), "motordrive_power": RegisterInfo(2052, INT16, UnitOfPower.WATT, 10), - "motordrive_controller_temperature": RegisterInfo(2053, INT16, UnitOfTemperature.CELSIUS, 10) + "motordrive_controller_temperature": RegisterInfo( + 2053, INT16, UnitOfTemperature.CELSIUS, 10 + ), } + class charger_mode(Enum): OFF = 0 ON = 1 @@ -578,36 +1088,107 @@ class charger_mode(Enum): charger_registers = { - "charger_voltage_output_1": RegisterInfo(2307, UINT16, UnitOfElectricPotential.VOLT, 100), - "charger_current_output_1": RegisterInfo(2308, INT16, UnitOfElectricCurrent.AMPERE, 10), + "charger_voltage_output_1": RegisterInfo( + 2307, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "charger_current_output_1": RegisterInfo( + 2308, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), "charger_temperature": RegisterInfo(2309, INT16, UnitOfTemperature.CELSIUS, 10), - "charger_voltage_output_2": RegisterInfo(2310, UINT16, UnitOfElectricPotential.VOLT, 100), - "charger_current_output_2": RegisterInfo(2311, INT16, UnitOfElectricCurrent.AMPERE, 10), - "charger_voltage_output_3": RegisterInfo(2312, UINT16, UnitOfElectricPotential.VOLT, 100), - "charger_current_output_3": RegisterInfo(2313, INT16, UnitOfElectricCurrent.AMPERE, 10), + "charger_voltage_output_2": RegisterInfo( + 2310, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "charger_current_output_2": RegisterInfo( + 2311, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "charger_voltage_output_3": RegisterInfo( + 2312, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "charger_current_output_3": RegisterInfo( + 2313, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), "charger_L1_current": RegisterInfo(2314, INT16, UnitOfElectricCurrent.AMPERE, 10), "charger_L1_power": RegisterInfo(2315, UINT16, UnitOfPower.WATT), - "charger_current_limit": RegisterInfo(2316, INT16, UnitOfElectricCurrent.AMPERE, 10, entityType=SliderWriteType("AC", True)), - "charger_mode": RegisterInfo(register=2317, dataType=UINT16, entityType=SelectWriteType(charger_mode)), - "charger_state": RegisterInfo(register=2318, dataType=UINT16, entityType=TextReadEntityType(generic_charger_state)), - "charger_errorcode": RegisterInfo(register=2319, dataType=UINT16, entityType=TextReadEntityType(generic_charger_errorcode)), - "charger_relay": RegisterInfo(register=2320, dataType=UINT16, entityType=BoolReadEntityType()), - "charger_alarm_lowvoltage": RegisterInfo(register=2321, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "charger_alarm_highvoltage": RegisterInfo(register=2322, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)) + "charger_current_limit": RegisterInfo( + 2316, + INT16, + UnitOfElectricCurrent.AMPERE, + 10, + entityType=SliderWriteType("AC", True), + ), + "charger_mode": RegisterInfo( + register=2317, dataType=UINT16, entityType=SelectWriteType(charger_mode) + ), + "charger_state": RegisterInfo( + register=2318, + dataType=UINT16, + entityType=TextReadEntityType(generic_charger_state), + ), + "charger_errorcode": RegisterInfo( + register=2319, + dataType=UINT16, + entityType=TextReadEntityType(generic_charger_errorcode), + ), + "charger_relay": RegisterInfo( + register=2320, dataType=UINT16, entityType=BoolReadEntityType() + ), + "charger_alarm_lowvoltage": RegisterInfo( + register=2321, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "charger_alarm_highvoltage": RegisterInfo( + register=2322, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } settings_registers = { - "settings_ess_acpowersetpoint": RegisterInfo(register=2700, dataType=INT16, unit=UnitOfPower.WATT, entityType=SliderWriteType("AC", True)), - "settings_ess_maxchargepercentage": RegisterInfo(register=2701, dataType=UINT16, unit=PERCENTAGE, entityType=SliderWriteType()), - "settings_ess_maxdischargepercentage": RegisterInfo(register=2702, dataType=UINT16, unit=PERCENTAGE, entityType=SliderWriteType()), - "settings_ess_acpowersetpoint2": RegisterInfo(2703, INT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", True)), # NOTE: Duplicate register exposed by victron - "settings_ess_maxdischargepower": RegisterInfo(2704, UINT16, UnitOfPower.WATT, 0.1, SliderWriteType("DC", False), 50), - "settings_ess_maxchargecurrent": RegisterInfo(register=2705, dataType=INT16, unit=UnitOfElectricCurrent.AMPERE, entityType=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()), - "settings_ess_preventfeedback": RegisterInfo(register=2708, dataType=INT16, entityType=SwitchWriteType()), - "settings_ess_feedinpowerlimit": RegisterInfo(register=2709, dataType=INT16, entityType=BoolReadEntityType()), - "settings_systemsetup_maxchargevoltage": RegisterInfo(2710, UINT16, UnitOfElectricPotential.VOLT, 10, SliderWriteType("DC", False), 0.1) + "settings_ess_acpowersetpoint": RegisterInfo( + register=2700, + dataType=INT16, + unit=UnitOfPower.WATT, + entityType=SliderWriteType("AC", True), + ), + "settings_ess_maxchargepercentage": RegisterInfo( + register=2701, dataType=UINT16, unit=PERCENTAGE, entityType=SliderWriteType() + ), + "settings_ess_maxdischargepercentage": RegisterInfo( + register=2702, dataType=UINT16, unit=PERCENTAGE, entityType=SliderWriteType() + ), + "settings_ess_acpowersetpoint2": RegisterInfo( + 2703, INT16, UnitOfPower.WATT, 0.01, SliderWriteType("AC", True) + ), # NOTE: Duplicate register exposed by victron + "settings_ess_maxdischargepower": RegisterInfo( + 2704, UINT16, UnitOfPower.WATT, 0.1, SliderWriteType("DC", False), 50 + ), + "settings_ess_maxchargecurrent": RegisterInfo( + register=2705, + dataType=INT16, + unit=UnitOfElectricCurrent.AMPERE, + entityType=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() + ), + "settings_ess_preventfeedback": RegisterInfo( + register=2708, dataType=INT16, entityType=SwitchWriteType() + ), + "settings_ess_feedinpowerlimit": RegisterInfo( + register=2709, dataType=INT16, entityType=BoolReadEntityType() + ), + "settings_systemsetup_maxchargevoltage": RegisterInfo( + 2710, + UINT16, + UnitOfElectricPotential.VOLT, + 10, + SliderWriteType("DC", False), + 0.1, + ), } gps_registers = { @@ -615,11 +1196,14 @@ class charger_mode(Enum): "gps_longitude": RegisterInfo(2802, INT32, "", 10000000), "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()), + "gps_fix": RegisterInfo( + register=2806, dataType=UINT16, entityType=BoolReadEntityType() + ), "gps_numberofsatellites": RegisterInfo(2807, UINT16), - "gps_altitude": RegisterInfo(2808, INT32, UnitOfLength.METERS, 10) + "gps_altitude": RegisterInfo(2808, INT32, UnitOfLength.METERS, 10), } + class ess_batterylife_state(Enum): BL_DISABLED_DUPLICATE_1 = 0 RESTARTING = 1 @@ -635,19 +1219,30 @@ class ess_batterylife_state(Enum): BL_DISABLED_LOW_SOC = 11 BL_DISABLED_LOC_SOC_RECHARGE = 12 + class ess_mode(Enum): SELF_CONSUMPTION_WITH_BATTERY_LIFE = 0 SELF_CONSUMPTION = 1 KEEP_CHARGED = 2 EXTERNAL_CONTROL = 3 + settings_ess_registers = { - "settings_ess_batterylife_state": RegisterInfo(register=2900, dataType=UINT16, entityType=SelectWriteType(ess_batterylife_state)), - "settings_ess_batterylife_minimumsoc": RegisterInfo(2901, UINT16, PERCENTAGE, 10, SliderWriteType(), 5), - "settings_ess_mode": RegisterInfo(register=2902, dataType=UINT16, entityType=SelectWriteType(ess_mode)), + "settings_ess_batterylife_state": RegisterInfo( + register=2900, + dataType=UINT16, + entityType=SelectWriteType(ess_batterylife_state), + ), + "settings_ess_batterylife_minimumsoc": RegisterInfo( + 2901, UINT16, PERCENTAGE, 10, SliderWriteType(), 5 + ), + "settings_ess_mode": RegisterInfo( + register=2902, dataType=UINT16, entityType=SelectWriteType(ess_mode) + ), "settings_ess_batterylife_soclimit": RegisterInfo(2903, UINT16, PERCENTAGE, 10), } + class tank_fluidtype(Enum): FUEL = 0 FRESH_WATER = 1 @@ -662,6 +1257,7 @@ class tank_fluidtype(Enum): HYDRAULIC_OIL = 10 RAW_WATER = 11 + class tank_status(Enum): OK = 0 DISCONNECTED = 1 @@ -670,89 +1266,189 @@ class tank_status(Enum): UNKNOWN = 4 ERROR = 5 + tank_registers = { "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)), + "tank_fluidtype": RegisterInfo( + register=3003, dataType=UINT16, entityType=TextReadEntityType(tank_fluidtype) + ), "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)) + "tank_status": RegisterInfo( + register=3007, dataType=UINT16, entityType=TextReadEntityType(tank_status) + ), } inverter_output_registers = { - "inverter_output_L1_current": RegisterInfo(3100, INT16, UnitOfElectricCurrent.AMPERE, 10), - "inverter_output_L1_voltage": RegisterInfo(3101, UINT16, UnitOfElectricPotential.VOLT, 10), + "inverter_output_L1_current": RegisterInfo( + 3100, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "inverter_output_L1_voltage": RegisterInfo( + 3101, UINT16, UnitOfElectricPotential.VOLT, 10 + ), "inverter_output_L1_power": RegisterInfo(3102, INT16, UnitOfPower.WATT, 0.1), } inverter_battery_registers = { - "inverter_battery_voltage": RegisterInfo(3105, UINT16, UnitOfElectricPotential.VOLT, 100), - "inverter_battery_current": RegisterInfo(3106, INT16, UnitOfElectricCurrent.AMPERE, 10), + "inverter_battery_voltage": RegisterInfo( + 3105, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "inverter_battery_current": RegisterInfo( + 3106, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), } inverter_alarm_registers = { - "inverter_alarm_hightemperature": RegisterInfo(register=3110, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "inverter_alarm_highbatteryvoltage": RegisterInfo(register=3111, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "inverter_alarm_highacoutvoltage": RegisterInfo(register=3112, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "inverter_alarm_lowtemperature": RegisterInfo(register=3113, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "inverter_alarm_lowbatteryvoltage": RegisterInfo(register=3114, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "inverter_alarm_lowacoutvoltage": RegisterInfo(register=3115, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "inverter_alarm_overload": RegisterInfo(register=3116, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "inverter_alarm_ripple": RegisterInfo(register=3117, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), + "inverter_alarm_hightemperature": RegisterInfo( + register=3110, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "inverter_alarm_highbatteryvoltage": RegisterInfo( + register=3111, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "inverter_alarm_highacoutvoltage": RegisterInfo( + register=3112, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "inverter_alarm_lowtemperature": RegisterInfo( + register=3113, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "inverter_alarm_lowbatteryvoltage": RegisterInfo( + register=3114, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "inverter_alarm_lowacoutvoltage": RegisterInfo( + register=3115, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "inverter_alarm_overload": RegisterInfo( + register=3116, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "inverter_alarm_ripple": RegisterInfo( + register=3117, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } + class inverter_mode(Enum): ON = 2 OFF = 4 ECO = 5 + inverter_info_registers = { "inverter_info_firmwareversion": RegisterInfo(3125, UINT16), - "inverter_info_mode": RegisterInfo(register=3126, dataType=UINT16, entityType=SelectWriteType(inverter_mode)), + "inverter_info_mode": RegisterInfo( + register=3126, dataType=UINT16, entityType=SelectWriteType(inverter_mode) + ), "inverter_info_productid": RegisterInfo(3127, UINT16), - "inverter_info_state": RegisterInfo(register=3128, dataType=UINT16, entityType=TextReadEntityType(generic_charger_state)), + "inverter_info_state": RegisterInfo( + register=3128, + dataType=UINT16, + entityType=TextReadEntityType(generic_charger_state), + ), } -#PV voltage is present here due to poor register id selection by victron +# PV voltage is present here due to poor register id selection by victron inverter_energy_registers = { - "inverter_energy_invertertoacout": RegisterInfo(3130, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "inverter_energy_outtoinverter": RegisterInfo(3132, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "inverter_energy_solartoacout": RegisterInfo(3134, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "inverter_energy_solartobattery": RegisterInfo(3136, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "inverter_pv_voltage_single_tracker": RegisterInfo(3138, UINT16, UnitOfElectricPotential.VOLT, 10) + "inverter_energy_invertertoacout": RegisterInfo( + 3130, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "inverter_energy_outtoinverter": RegisterInfo( + 3132, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "inverter_energy_solartoacout": RegisterInfo( + 3134, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "inverter_energy_solartobattery": RegisterInfo( + 3136, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "inverter_pv_voltage_single_tracker": RegisterInfo( + 3138, UINT16, UnitOfElectricPotential.VOLT, 10 + ), } inverter_tracker_registers = { - "inverter_tracker_0_voltage": RegisterInfo(3140, UINT16, UnitOfElectricPotential.VOLT, 10), - "inverter_tracker_1_voltage": RegisterInfo(3141, UINT16, UnitOfElectricPotential.VOLT, 10), - "inverter_tracker_2_voltage": RegisterInfo(3142, UINT16, UnitOfElectricPotential.VOLT, 10), - "inverter_tracker_3_voltage": RegisterInfo(3143, UINT16, UnitOfElectricPotential.VOLT, 10), + "inverter_tracker_0_voltage": RegisterInfo( + 3140, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "inverter_tracker_1_voltage": RegisterInfo( + 3141, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "inverter_tracker_2_voltage": RegisterInfo( + 3142, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "inverter_tracker_3_voltage": RegisterInfo( + 3143, UINT16, UnitOfElectricPotential.VOLT, 10 + ), } inverter_tracker_statistics_registers = { - "inverter_tracker_0_yield_today": RegisterInfo(3148, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "inverter_tracker_1_yield_today": RegisterInfo(3149, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "inverter_tracker_2_yield_today": RegisterInfo(3150, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "inverter_tracker_3_yield_today": RegisterInfo(3151, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "inverter_tracker_0_yield_yesterday": RegisterInfo(3152, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "inverter_tracker_1_yield_yesterday": RegisterInfo(3153, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "inverter_tracker_2_yield_yesterday": RegisterInfo(3154, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "inverter_tracker_3_yield_yesterday": RegisterInfo(3155, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), + "inverter_tracker_0_yield_today": RegisterInfo( + 3148, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "inverter_tracker_1_yield_today": RegisterInfo( + 3149, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "inverter_tracker_2_yield_today": RegisterInfo( + 3150, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "inverter_tracker_3_yield_today": RegisterInfo( + 3151, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "inverter_tracker_0_yield_yesterday": RegisterInfo( + 3152, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "inverter_tracker_1_yield_yesterday": RegisterInfo( + 3153, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "inverter_tracker_2_yield_yesterday": RegisterInfo( + 3154, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "inverter_tracker_3_yield_yesterday": RegisterInfo( + 3155, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), "inverter_tracker_0_maxpower_today": RegisterInfo(3156, UINT16, UnitOfPower.WATT), "inverter_tracker_1_maxpower_today": RegisterInfo(3157, UINT16, UnitOfPower.WATT), "inverter_tracker_2_maxpower_today": RegisterInfo(3158, UINT16, UnitOfPower.WATT), - "inverter_tracker_3_maxpower_today": RegisterInfo(3159, UINT16, UnitOfPower.WATT), - "inverter_tracker_0_maxpower_yesterday": RegisterInfo(3160, UINT16, UnitOfPower.WATT), - "inverter_tracker_1_maxpower_yesterday": RegisterInfo(3161, UINT16, UnitOfPower.WATT), - "inverter_tracker_2_maxpower_yesterday": RegisterInfo(3162, UINT16, UnitOfPower.WATT), - "inverter_tracker_3_maxpower_yesterday": RegisterInfo(3163, UINT16, UnitOfPower.WATT), + "inverter_tracker_3_maxpower_today": RegisterInfo(3159, UINT16, UnitOfPower.WATT), + "inverter_tracker_0_maxpower_yesterday": RegisterInfo( + 3160, UINT16, UnitOfPower.WATT + ), + "inverter_tracker_1_maxpower_yesterday": RegisterInfo( + 3161, UINT16, UnitOfPower.WATT + ), + "inverter_tracker_2_maxpower_yesterday": RegisterInfo( + 3162, UINT16, UnitOfPower.WATT + ), + "inverter_tracker_3_maxpower_yesterday": RegisterInfo( + 3163, UINT16, UnitOfPower.WATT + ), "inverter_tracker_0_power": RegisterInfo(3164, UINT16, UnitOfPower.WATT), "inverter_tracker_1_power": RegisterInfo(3165, UINT16, UnitOfPower.WATT), "inverter_tracker_2_power": RegisterInfo(3166, UINT16, UnitOfPower.WATT), "inverter_tracker_3_power": RegisterInfo(3167, UINT16, UnitOfPower.WATT), - "inverter_alarm_lowsoc": RegisterInfo(register=3168, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)) + "inverter_alarm_lowsoc": RegisterInfo( + register=3168, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } + class genset_status(Enum): STANDBY = 0 STARTUP_1 = 1 @@ -766,6 +1462,7 @@ class genset_status(Enum): STOPPING = 9 ERROR = 10 + class genset_errorcode(Enum): NONE = 0 AC_L1_VOLTAGE_TOO_LOW = 1 @@ -810,20 +1507,20 @@ class genset_errorcode(Enum): OIL_PRESSURE_TOO_HIGH = 71 ENGINE_TEMPERATURE_TOO_HIGH = 72 WINDING_TEMPERATURE_TOO_HIGH = 73 - EXHAUST_TEMPERATURE_TOO_HIGH = 74 #NOTE modbustcp spec says it should be too low but that is already specified in the low grouping therefore assuming this state is used for HIGH temp - STARTER_CURRENT_TOO_HIGH = 77 #NOTE same as 74 applies here + EXHAUST_TEMPERATURE_TOO_HIGH = 74 # NOTE modbustcp spec says it should be too low but that is already specified in the low grouping therefore assuming this state is used for HIGH temp + STARTER_CURRENT_TOO_HIGH = 77 # NOTE same as 74 applies here GLOW_CURRENT_TOO_HIGH = 78 GLOW_CURRENT_TOO_HIGH_DUPLICATE_1 = 79 FUEL_HOLDING_MAGNET_CURRENT_TOO_HIGH = 80 STOP_SOLENOID_HOLD_COIL_CURRENT_TOO_HIGH = 81 STOP_SOLENOID_PULL_COIL_CURRENT_TOO_HIGH = 82 - OPTIONAL_DC_OUT_CURRENT_TOO_HIGH = 83 + OPTIONAL_DC_OUT_CURRENT_TOO_HIGH = 83 OUTPUT_5V_TOO_HIGH = 84 BOOST_OUTPUT_CURRENT_TOO_HIGH = 85 STARTER_BATTERY_VOLTAGE_TOO_HIGH = 89 ROTATION_TOO_HIGH_STARTUP_ABORTED = 90 ROTATION_TOO_HIGH = 92 - POWER_CONTACTER_CURRENT_TOO_HIGH = 93 + POWER_CONTACTER_CURRENT_TOO_HIGH = 93 AC_L2_VOLTAGE_TOO_HIGH = 94 AC_L2_FREQUENCY_TOO_HIGH = 95 AC_L2_CURRENT_TOO_HIGH = 96 @@ -843,7 +1540,7 @@ class genset_errorcode(Enum): INTAKE_AIRFILTER = 137 LOST_SYNC_MODULE = 139 LOAD_BALANCE_FAILED = 140 - SYNC_MODE_DEACTIVATED = 141 + SYNC_MODE_DEACTIVATED = 141 ENGINE_CONTROLLER = 142 ROTATING_FIELD_WRONG = 148 FUEL_LEVEL_SENSOR_LOST = 149 @@ -854,7 +1551,7 @@ class genset_errorcode(Enum): OUTAGE_CYCLE_HEAD = 154 INVERTER_OVER_TEMPERATURE = 155 INVERTER_OVERLOAD = 156 - INVERTER_COMMMUNICATION_LOST = 157 + INVERTER_COMMMUNICATION_LOST = 157 INVERTER_SYNC_FAILED = 158 CAN_COMMUNICATION_LOST = 159 L1_OVERLOAD = 160 @@ -865,6 +1562,7 @@ class genset_errorcode(Enum): EMERGENCY_STOP_DUPLICATE_1 = 165 NO_CONNECTION = 166 + genset_registers = { "genset_L1_voltage": RegisterInfo(3200, UINT16, UnitOfElectricPotential.VOLT, 10), "genset_L2_voltage": RegisterInfo(3201, UINT16, UnitOfElectricPotential.VOLT, 10), @@ -879,24 +1577,44 @@ class genset_errorcode(Enum): "genset_L2_frequency": RegisterInfo(3210, UINT16, UnitOfFrequency.HERTZ, 100), "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)), - "genset_errorcode": RegisterInfo(register=3214, dataType=UINT16, entityType=TextReadEntityType(genset_errorcode)), - "genset_autostart": RegisterInfo(register=3215, dataType=UINT16, entityType=BoolReadEntityType()), + "genset_statuscode": RegisterInfo( + register=3213, dataType=UINT16, entityType=TextReadEntityType(genset_status) + ), + "genset_errorcode": RegisterInfo( + register=3214, dataType=UINT16, entityType=TextReadEntityType(genset_errorcode) + ), + "genset_autostart": RegisterInfo( + register=3215, dataType=UINT16, entityType=BoolReadEntityType() + ), "genset_engine_load": RegisterInfo(3216, UINT16, PERCENTAGE), "genset_engine_speed": RegisterInfo(3217, UINT16, REVOLUTIONS_PER_MINUTE), - "genset_engine_operatinghours": RegisterInfo(3218, UINT16, UnitOfTime.SECONDS, 0.01), - "genset_engine_coolanttemperature": RegisterInfo(3219, INT16, UnitOfTemperature.CELSIUS, 10), - "genset_engine_windingtemperature": RegisterInfo(3220, INT16, UnitOfTemperature.CELSIUS, 10), - "genset_engine_exhausttemperature": RegisterInfo(3221, INT16, UnitOfTemperature.CELSIUS, 10), - "genset_startervoltage": RegisterInfo(3222, UINT16, UnitOfElectricPotential.VOLT, 100), - "genset_start": RegisterInfo(register=3223, dataType=UINT16, entityType=SwitchWriteType()) + "genset_engine_operatinghours": RegisterInfo( + 3218, UINT16, UnitOfTime.SECONDS, 0.01 + ), + "genset_engine_coolanttemperature": RegisterInfo( + 3219, INT16, UnitOfTemperature.CELSIUS, 10 + ), + "genset_engine_windingtemperature": RegisterInfo( + 3220, INT16, UnitOfTemperature.CELSIUS, 10 + ), + "genset_engine_exhausttemperature": RegisterInfo( + 3221, INT16, UnitOfTemperature.CELSIUS, 10 + ), + "genset_startervoltage": RegisterInfo( + 3222, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "genset_start": RegisterInfo( + register=3223, dataType=UINT16, entityType=SwitchWriteType() + ), } + class temperature_type(Enum): BATTERY = 0 FRIDGE = 1 GENERIC = 2 + class temperature_status(Enum): OK = 0 DISCONNECTED = 1 @@ -905,23 +1623,35 @@ class temperature_status(Enum): UNKNOWN = 4 LOW_BATTERY = 5 + temperature_registers = { "temperature_productid": RegisterInfo(3300, UINT16), "temperature_scale": RegisterInfo(3301, UINT16, "", 100), - "temperature_offset": RegisterInfo(3302, INT16, "",100), - "temperature_type": RegisterInfo(register=3303, dataType=UINT16, entityType=TextReadEntityType(temperature_type)), - "temperature_temperature": RegisterInfo(3304, INT16, UnitOfTemperature.CELSIUS, 100), - "temperature_status": RegisterInfo(register=3305, dataType=UINT16, entityType=TextReadEntityType(temperature_status)), + "temperature_offset": RegisterInfo(3302, INT16, "", 100), + "temperature_type": RegisterInfo( + register=3303, dataType=UINT16, entityType=TextReadEntityType(temperature_type) + ), + "temperature_temperature": RegisterInfo( + 3304, INT16, UnitOfTemperature.CELSIUS, 100 + ), + "temperature_status": RegisterInfo( + register=3305, + dataType=UINT16, + entityType=TextReadEntityType(temperature_status), + ), "temperature_humidity": RegisterInfo(3306, UINT16, PERCENTAGE, 10), - "temperature_batteryvoltage": RegisterInfo(3307, UINT16, UnitOfElectricPotential.VOLT, 100), - "temperature_pressure": RegisterInfo(3308, UINT16, UnitOfPressure.HPA) + "temperature_batteryvoltage": RegisterInfo( + 3307, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "temperature_pressure": RegisterInfo(3308, UINT16, UnitOfPressure.HPA), } pulsemeter_registers = { "pulsemeter_aggregate": RegisterInfo(3400, UINT32, UnitOfVolume.CUBIC_METERS), - "pulsemeter_count": RegisterInfo(3402, UINT32) + "pulsemeter_count": RegisterInfo(3402, UINT32), } + class digitalinput_state(Enum): LOW = 0 HIGH = 1 @@ -936,6 +1666,7 @@ class digitalinput_state(Enum): RUNNING = 10 STOPPED = 11 + class digitalinput_type(Enum): DOOR = 2 BILGE_PUMP = 3 @@ -945,13 +1676,25 @@ class digitalinput_type(Enum): FIRE_ALARM = 7 CO2_ALARM = 8 + digitalinput_registers = { "digitalinput_count": RegisterInfo(3420, UINT32), - "digitalinput_state": RegisterInfo(register=3422, dataType=UINT16, entityType=TextReadEntityType(digitalinput_state)), - "digitalinput_alarm": RegisterInfo(register=3423, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "digitalinput_type": RegisterInfo(register=3424, dataType=UINT16, entityType=TextReadEntityType(digitalinput_type)) + "digitalinput_state": RegisterInfo( + register=3422, + dataType=UINT16, + entityType=TextReadEntityType(digitalinput_state), + ), + "digitalinput_alarm": RegisterInfo( + register=3423, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "digitalinput_type": RegisterInfo( + register=3424, dataType=UINT16, entityType=TextReadEntityType(digitalinput_type) + ), } + class generator_runningbyconditioncode(Enum): STOPPED = 0 MANUAL = 1 @@ -965,45 +1708,70 @@ class generator_runningbyconditioncode(Enum): INVERTER_OVERLOAD = 9 STOP_ON_AC1 = 10 + class generator_state(Enum): STOPPED = 0 RUNNING = 1 ERROR = 10 + class generator_error(Enum): NONE = 0 REMOTE_DISABLED = 1 REMOTE_FAULT = 2 + generator_registers = { - "generator_manualstart": RegisterInfo(register=3500, dataType=UINT16, entityType=SwitchWriteType()), - "generator_runningbyconditioncode": RegisterInfo(register=3501, dataType=UINT16, entityType=TextReadEntityType(generator_runningbyconditioncode)), + "generator_manualstart": RegisterInfo( + register=3500, dataType=UINT16, entityType=SwitchWriteType() + ), + "generator_runningbyconditioncode": RegisterInfo( + register=3501, + dataType=UINT16, + entityType=TextReadEntityType(generator_runningbyconditioncode), + ), "generator_runtime": RegisterInfo(3502, UINT16, UnitOfTime.SECONDS), - "generator_quiethours": RegisterInfo(register=3503, dataType=UINT16, entityType=BoolReadEntityType()), + "generator_quiethours": RegisterInfo( + register=3503, dataType=UINT16, entityType=BoolReadEntityType() + ), "generator_runtime_2": RegisterInfo(3504, UINT32, UnitOfTime.SECONDS), - "generator_state": RegisterInfo(register=3506, dataType=UINT16, entityType=TextReadEntityType(generator_state)), - "generator_error": RegisterInfo(register=3507, dataType=UINT16, entityType=TextReadEntityType(generator_error)), - "generator_alarm_nogeneratoratacin": RegisterInfo(register=3508, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "generator_autostartenabled": RegisterInfo(register=3509, dataType=UINT16, entityType=SwitchWriteType()) + "generator_state": RegisterInfo( + register=3506, dataType=UINT16, entityType=TextReadEntityType(generator_state) + ), + "generator_error": RegisterInfo( + register=3507, dataType=UINT16, entityType=TextReadEntityType(generator_error) + ), + "generator_alarm_nogeneratoratacin": RegisterInfo( + register=3508, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "generator_autostartenabled": RegisterInfo( + register=3509, dataType=UINT16, entityType=SwitchWriteType() + ), } -#not processed yet +# not processed yet meteo_registers = { - "meteo_irradiance": RegisterInfo(3600, UINT16, UnitOfIrradiance.WATTS_PER_SQUARE_METER, 10), + "meteo_irradiance": RegisterInfo( + 3600, UINT16, UnitOfIrradiance.WATTS_PER_SQUARE_METER, 10 + ), "meteo_windspeed": RegisterInfo(3601, UINT16, UnitOfSpeed.METERS_PER_SECOND, 10), "meteo_celltemperature": RegisterInfo(3602, INT16, UnitOfTemperature.CELSIUS, 10), - "meteo_externaltemperature": RegisterInfo(3603, INT16, UnitOfTemperature.CELSIUS, 10) + "meteo_externaltemperature": RegisterInfo( + 3603, INT16, UnitOfTemperature.CELSIUS, 10 + ), } -evcharger_productid_registers = { - "evcharger_productid": RegisterInfo(3800, UINT16) -} +evcharger_productid_registers = {"evcharger_productid": RegisterInfo(3800, UINT16)} + class evcharger_mode(Enum): AC_INPUT_1 = 0 AC_OUTPUT = 1 AC_INPUT_2 = 2 + class evcharger_status(Enum): DISCONNECTED = 0 CONNECTED = 1 @@ -1021,23 +1789,44 @@ class evcharger_status(Enum): OVERVOLTAGE_DETECTED = 13 OVERHEATING_DETECTED = 14 + evcharger_registers = { "evcharger_firmwareversion": RegisterInfo(3802, UINT32), "evcharger_serial": RegisterInfo(3804, STRING(6)), "evcharger_model": RegisterInfo(3810, STRING(4)), - "evcharger_maxcurrent": RegisterInfo(register=3814, dataType=UINT16, unit=UnitOfElectricCurrent.AMPERE, entityType=SliderWriteType("AC", False)), - "evcharger_mode": RegisterInfo(register=3815, dataType=UINT16, entityType=SelectWriteType(evcharger_mode)), - "evcharger_energy_forward": RegisterInfo(3816, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), + "evcharger_maxcurrent": RegisterInfo( + register=3814, + dataType=UINT16, + unit=UnitOfElectricCurrent.AMPERE, + entityType=SliderWriteType("AC", False), + ), + "evcharger_mode": RegisterInfo( + register=3815, dataType=UINT16, entityType=SelectWriteType(evcharger_mode) + ), + "evcharger_energy_forward": RegisterInfo( + 3816, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), "evcharger_L1_power": RegisterInfo(3818, UINT16, UnitOfPower.WATT), "evcharger_L2_power": RegisterInfo(3819, UINT16, UnitOfPower.WATT), "evcharger_L3_power": RegisterInfo(3820, UINT16, UnitOfPower.WATT), "evcharger_total_power": RegisterInfo(3821, UINT16, UnitOfPower.WATT), "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)), - "evcharger_setcurrent": RegisterInfo(register=3825, dataType=UINT16, unit=UnitOfElectricCurrent.AMPERE, entityType=SliderWriteType("AC", False)), - "evcharger_startstop": RegisterInfo(register=3826, dataType=UINT16, entityType=SwitchWriteType()), - "evcharger_position": RegisterInfo(register=3827, dataType=UINT16, entityType=TextReadEntityType(generic_position)), + "evcharger_status": RegisterInfo( + register=3824, dataType=UINT16, entityType=TextReadEntityType(evcharger_status) + ), + "evcharger_setcurrent": RegisterInfo( + register=3825, + dataType=UINT16, + unit=UnitOfElectricCurrent.AMPERE, + entityType=SliderWriteType("AC", False), + ), + "evcharger_startstop": RegisterInfo( + register=3826, dataType=UINT16, entityType=SwitchWriteType() + ), + "evcharger_position": RegisterInfo( + register=3827, dataType=UINT16, entityType=TextReadEntityType(generic_position) + ), } acload_registers = { @@ -1051,25 +1840,64 @@ class evcharger_status(Enum): "acload_L2_current": RegisterInfo(3913, INT16, UnitOfElectricCurrent.AMPERE, 10), "acload_L3_voltage": RegisterInfo(3914, UINT16, UnitOfElectricPotential.VOLT, 10), "acload_L3_current": RegisterInfo(3915, INT16, UnitOfElectricCurrent.AMPERE, 10), - "acload_L1_energy_forward": RegisterInfo(3916, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "acload_L2_energy_forward": RegisterInfo(3918, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "acload_L3_energy_forward": RegisterInfo(3920, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100) + "acload_L1_energy_forward": RegisterInfo( + 3916, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "acload_L2_energy_forward": RegisterInfo( + 3918, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "acload_L3_energy_forward": RegisterInfo( + 3920, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), } fuelcell_registers = { - "fuelcell_battery_voltage": RegisterInfo(4000, UINT16, UnitOfElectricPotential.VOLT, 100), - "fuelcell_battery_current": RegisterInfo(4001, INT16, UnitOfElectricCurrent.AMPERE, 10), - "fuelcell_starter_voltage": RegisterInfo(4002, UINT16, UnitOfElectricPotential.VOLT, 100), + "fuelcell_battery_voltage": RegisterInfo( + 4000, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "fuelcell_battery_current": RegisterInfo( + 4001, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "fuelcell_starter_voltage": RegisterInfo( + 4002, UINT16, UnitOfElectricPotential.VOLT, 100 + ), "fuelcell_temperature": RegisterInfo(4003, INT16, UnitOfTemperature.CELSIUS, 10), - "fuelcell_history_energyout": RegisterInfo(4004, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "fuelcell_alarm_lowvoltage": RegisterInfo(register=4006, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "fuelcell_alarm_highvoltage": RegisterInfo(register=4007, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "fuelcell_alarm_lowstartervoltage": RegisterInfo(register=4008, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "fuelcell_alarm_highstartervoltage": RegisterInfo(register=4009, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "fuelcell_alarm_lowtemperature": RegisterInfo(register=4010, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "fuelcell_alarm_hightemperature": RegisterInfo(register=4011, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)) + "fuelcell_history_energyout": RegisterInfo( + 4004, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "fuelcell_alarm_lowvoltage": RegisterInfo( + register=4006, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "fuelcell_alarm_highvoltage": RegisterInfo( + register=4007, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "fuelcell_alarm_lowstartervoltage": RegisterInfo( + register=4008, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "fuelcell_alarm_highstartervoltage": RegisterInfo( + register=4009, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "fuelcell_alarm_lowtemperature": RegisterInfo( + register=4010, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "fuelcell_alarm_hightemperature": RegisterInfo( + register=4011, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } + class alternator_state(Enum): OFF = 0 FAULT = 2 @@ -1080,6 +1908,7 @@ class alternator_state(Enum): EQUALIZE = 7 EXTERNAL_CONTROL = 252 + class alternator_errorcode(Enum): HIGH_BATTERY_TEMPERATURE = 12 HIGH_BATTERY_VOLTAGE = 13 @@ -1088,7 +1917,7 @@ class alternator_errorcode(Enum): HIGH_ALTERNATOR_TEMPERATURE = 21 ALTERNATOR_OVERSPEED = 22 INTERNAL_ERROR = 24 - HIGH_FIELD_FET_TEMPERATURE = 41 + HIGH_FIELD_FET_TEMPERATURE = 41 SENSOR_MISSING = 42 LOW_VALT = 43 HIGH_VOLTAGE_OFFSET = 44 @@ -1113,173 +1942,479 @@ class alternator_errorcode(Enum): DCDC_ERROR_DUPLICATE_4 = 206 DCDC_ERROR_DUPLICATE_5 = 207 + alternator_registers = { - "alternator_battery_voltage": RegisterInfo(4100, UINT16, UnitOfElectricPotential.VOLT, 100), - "alternator_battery_current": RegisterInfo(4101, INT16, UnitOfElectricCurrent.AMPERE, 10), - "alternator_startervoltage": RegisterInfo(4102, UINT16, UnitOfElectricPotential.VOLT, 100), + "alternator_battery_voltage": RegisterInfo( + 4100, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "alternator_battery_current": RegisterInfo( + 4101, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "alternator_startervoltage": RegisterInfo( + 4102, UINT16, UnitOfElectricPotential.VOLT, 100 + ), "alternator_temperature": RegisterInfo(4103, INT16, UnitOfTemperature.CELSIUS, 10), - "alternator_history_energyout": RegisterInfo(4104, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "alternator_alarm_lowvoltage": RegisterInfo(register=4106, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "alternator_alarm_highvoltage": RegisterInfo(register=4107, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "alternator_alarm_lowstartervoltage": RegisterInfo(register=4108, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "alternator_alarm_highstartervoltage": RegisterInfo(register=4109, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "alternator_alarm_lowtemperature": RegisterInfo(register=4110, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "alternator_alarm_hightemperature": RegisterInfo(register=4111, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "alternator_state": RegisterInfo(register=4112, dataType=UINT16, entityType=TextReadEntityType(alternator_state)), - "alternator_errorcode": RegisterInfo(register=4113, dataType=UINT16, entityType=TextReadEntityType(alternator_errorcode)), + "alternator_history_energyout": RegisterInfo( + 4104, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "alternator_alarm_lowvoltage": RegisterInfo( + register=4106, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "alternator_alarm_highvoltage": RegisterInfo( + register=4107, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "alternator_alarm_lowstartervoltage": RegisterInfo( + register=4108, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "alternator_alarm_highstartervoltage": RegisterInfo( + register=4109, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "alternator_alarm_lowtemperature": RegisterInfo( + register=4110, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "alternator_alarm_hightemperature": RegisterInfo( + register=4111, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "alternator_state": RegisterInfo( + register=4112, dataType=UINT16, entityType=TextReadEntityType(alternator_state) + ), + "alternator_errorcode": RegisterInfo( + register=4113, + dataType=UINT16, + entityType=TextReadEntityType(alternator_errorcode), + ), "alternator_engine_speed": RegisterInfo(4114, UINT16, REVOLUTIONS_PER_MINUTE), "alternator_alternator_speed": RegisterInfo(4115, UINT16, REVOLUTIONS_PER_MINUTE), - "alternator_fielddrive": RegisterInfo(4116, UINT16, PERCENTAGE) + "alternator_fielddrive": RegisterInfo(4116, UINT16, PERCENTAGE), } dcsource_registers = { - "dcsource_battery_voltage": RegisterInfo(4200, UINT16, UnitOfElectricPotential.VOLT, 100), - "dcsource_battery_current": RegisterInfo(4201, INT16, UnitOfElectricCurrent.AMPERE, 10), - "dcsource_starter_voltage": RegisterInfo(4202, UINT16, UnitOfElectricPotential.VOLT, 10), + "dcsource_battery_voltage": RegisterInfo( + 4200, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "dcsource_battery_current": RegisterInfo( + 4201, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "dcsource_starter_voltage": RegisterInfo( + 4202, UINT16, UnitOfElectricPotential.VOLT, 10 + ), "dcsource_temperature": RegisterInfo(4203, INT16, UnitOfTemperature.CELSIUS, 10), - "dcsource_history_energyout": RegisterInfo(4204, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "dcsource_alarm_lowvoltage": RegisterInfo(register=4206, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsource_alarm_highvoltage": RegisterInfo(register=4207, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsource_alarm_lowstartervoltage": RegisterInfo(register=4208, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsource_alarm_highstartervoltage": RegisterInfo(register=4209, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsource_alarm_lowtemperature": RegisterInfo(register=4210, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsource_alarm_hightemperature": RegisterInfo(register=4211, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), + "dcsource_history_energyout": RegisterInfo( + 4204, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "dcsource_alarm_lowvoltage": RegisterInfo( + register=4206, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsource_alarm_highvoltage": RegisterInfo( + register=4207, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsource_alarm_lowstartervoltage": RegisterInfo( + register=4208, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsource_alarm_highstartervoltage": RegisterInfo( + register=4209, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsource_alarm_lowtemperature": RegisterInfo( + register=4210, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsource_alarm_hightemperature": RegisterInfo( + register=4211, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } dcload_registers = { - "dcload_battery_voltage": RegisterInfo(4300, UINT16, UnitOfElectricPotential.VOLT, 100), - "dcload_battery_current": RegisterInfo(4301, INT16, UnitOfElectricCurrent.AMPERE, 10), - "dcload_starter_voltage": RegisterInfo(4302, UINT16, UnitOfElectricPotential.VOLT, 100), + "dcload_battery_voltage": RegisterInfo( + 4300, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "dcload_battery_current": RegisterInfo( + 4301, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "dcload_starter_voltage": RegisterInfo( + 4302, UINT16, UnitOfElectricPotential.VOLT, 100 + ), "dcload_temperature": RegisterInfo(4303, INT16, UnitOfTemperature.CELSIUS, 10), - "dcload_history_energyin": RegisterInfo(4304, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "dcload_alarm_lowvoltage": RegisterInfo(register=4306, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcload_alarm_highvoltage": RegisterInfo(register=4307, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcload_alarm_lowstartervoltage": RegisterInfo(register=4308, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcload_alarm_highstartervoltage": RegisterInfo(register=4309, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcload_alarm_lowtemperature": RegisterInfo(register=4310, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcload_alarm_hightemperature": RegisterInfo(register=4311, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)) + "dcload_history_energyin": RegisterInfo( + 4304, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "dcload_alarm_lowvoltage": RegisterInfo( + register=4306, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcload_alarm_highvoltage": RegisterInfo( + register=4307, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcload_alarm_lowstartervoltage": RegisterInfo( + register=4308, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcload_alarm_highstartervoltage": RegisterInfo( + register=4309, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcload_alarm_lowtemperature": RegisterInfo( + register=4310, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcload_alarm_hightemperature": RegisterInfo( + register=4311, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } dcsystem_registers = { - "dcsystem_battery_voltage": RegisterInfo(4400, UINT16, UnitOfElectricPotential.VOLT, 100), - "dcsystem_battery_current": RegisterInfo(4401, INT16, UnitOfElectricCurrent.AMPERE, 10), - "dcsystem_starter_voltage": RegisterInfo(4402, UINT16, UnitOfElectricPotential.VOLT, 100), + "dcsystem_battery_voltage": RegisterInfo( + 4400, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "dcsystem_battery_current": RegisterInfo( + 4401, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "dcsystem_starter_voltage": RegisterInfo( + 4402, UINT16, UnitOfElectricPotential.VOLT, 100 + ), "dcsystem_temperature": RegisterInfo(4403, INT16, UnitOfTemperature.CELSIUS, 10), - "dcsystem_history_energyout": RegisterInfo(4404, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "dcsystem_history_energyin": RegisterInfo(4406, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "dcsystem_alarm_lowvoltage": RegisterInfo(register=4408, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsystem_alarm_highvoltage": RegisterInfo(register=4409, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsystem_alarm_lowstartervoltage": RegisterInfo(register=4410, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsystem_alarm_highstartervoltage": RegisterInfo(register=4411, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsystem_alarm_lowtemperature": RegisterInfo(register=4412, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "dcsystem_alarm_hightemperature": RegisterInfo(register=4413, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)) + "dcsystem_history_energyout": RegisterInfo( + 4404, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "dcsystem_history_energyin": RegisterInfo( + 4406, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "dcsystem_alarm_lowvoltage": RegisterInfo( + register=4408, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsystem_alarm_highvoltage": RegisterInfo( + register=4409, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsystem_alarm_lowstartervoltage": RegisterInfo( + register=4410, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsystem_alarm_highstartervoltage": RegisterInfo( + register=4411, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsystem_alarm_lowtemperature": RegisterInfo( + register=4412, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "dcsystem_alarm_hightemperature": RegisterInfo( + register=4413, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } + class multi_mode(Enum): CHARGER = 1 INVERTER = 2 ON = 3 OFF = 4 + class multi_input_type(Enum): UNUSED = 0 GRID = 1 GENSET = 2 SHORE = 3 + multi_registers = { - "multi_input_L1_voltage": RegisterInfo(4500, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_input_L2_voltage": RegisterInfo(4501, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_input_L3_voltage": RegisterInfo(4502, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_input_L1_current": RegisterInfo(4503, UINT16, UnitOfElectricCurrent.AMPERE, 10), - "multi_input_L2_current": RegisterInfo(4504, UINT16, UnitOfElectricCurrent.AMPERE, 10), - "multi_input_L3_current": RegisterInfo(4505, UINT16, UnitOfElectricCurrent.AMPERE, 10), + "multi_input_L1_voltage": RegisterInfo( + 4500, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_input_L2_voltage": RegisterInfo( + 4501, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_input_L3_voltage": RegisterInfo( + 4502, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_input_L1_current": RegisterInfo( + 4503, UINT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "multi_input_L2_current": RegisterInfo( + 4504, UINT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "multi_input_L3_current": RegisterInfo( + 4505, UINT16, UnitOfElectricCurrent.AMPERE, 10 + ), "multi_input_L1_power": RegisterInfo(4506, INT16, UnitOfPower.WATT, 0.1), "multi_input_L2_power": RegisterInfo(4507, INT16, UnitOfPower.WATT, 0.1), "multi_input_L3_power": RegisterInfo(4508, INT16, UnitOfPower.WATT, 0.1), "multi_input_L1_frequency": RegisterInfo(4509, UINT16, UnitOfFrequency.HERTZ, 100), - "multi_output_L1_voltage": RegisterInfo(4510, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_output_L2_voltage": RegisterInfo(4511, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_output_L3_voltage": RegisterInfo(4512, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_output_L1_current": RegisterInfo(4513, UINT16, UnitOfElectricCurrent.AMPERE, 10), - "multi_output_L2_current": RegisterInfo(4514, UINT16, UnitOfElectricCurrent.AMPERE, 10), - "multi_output_L3_current": RegisterInfo(4515, UINT16, UnitOfElectricCurrent.AMPERE, 10), + "multi_output_L1_voltage": RegisterInfo( + 4510, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_output_L2_voltage": RegisterInfo( + 4511, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_output_L3_voltage": RegisterInfo( + 4512, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_output_L1_current": RegisterInfo( + 4513, UINT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "multi_output_L2_current": RegisterInfo( + 4514, UINT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "multi_output_L3_current": RegisterInfo( + 4515, UINT16, UnitOfElectricCurrent.AMPERE, 10 + ), "multi_output_L1_power": RegisterInfo(4516, INT16, UnitOfPower.WATT, 0.1), "multi_output_L2_power": RegisterInfo(4517, INT16, UnitOfPower.WATT, 0.1), "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)), - "multi_input_2_type": RegisterInfo(register=4521, dataType=UINT16, entityType=TextReadEntityType(multi_input_type)), - "multi_input_1_currentlimit": RegisterInfo(4522, UINT16, UnitOfElectricCurrent.AMPERE, 10, SliderWriteType("AC", False)), - "multi_input_2_currentlimit": RegisterInfo(4523, UINT16, UnitOfElectricCurrent.AMPERE, 10, SliderWriteType("AC", False)), + "multi_input_1_type": RegisterInfo( + register=4520, dataType=UINT16, entityType=TextReadEntityType(multi_input_type) + ), + "multi_input_2_type": RegisterInfo( + register=4521, dataType=UINT16, entityType=TextReadEntityType(multi_input_type) + ), + "multi_input_1_currentlimit": RegisterInfo( + 4522, UINT16, UnitOfElectricCurrent.AMPERE, 10, SliderWriteType("AC", False) + ), + "multi_input_2_currentlimit": RegisterInfo( + 4523, UINT16, UnitOfElectricCurrent.AMPERE, 10, SliderWriteType("AC", False) + ), "multi_numberofphases": RegisterInfo(4524, UINT16), - "multi_activein_activeinput": RegisterInfo(register=4525, dataType=UINT16, entityType=TextReadEntityType(generic_activeinput)), - "multi_battery_voltage": RegisterInfo(4526, UINT16, UnitOfElectricPotential.VOLT, 100), - "multi_battery_current": RegisterInfo(4527, INT16, UnitOfElectricCurrent.AMPERE, 10), - "multi_battery_temperature": RegisterInfo(4528, INT16, UnitOfTemperature.CELSIUS, 10), + "multi_activein_activeinput": RegisterInfo( + register=4525, + dataType=UINT16, + entityType=TextReadEntityType(generic_activeinput), + ), + "multi_battery_voltage": RegisterInfo( + 4526, UINT16, UnitOfElectricPotential.VOLT, 100 + ), + "multi_battery_current": RegisterInfo( + 4527, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "multi_battery_temperature": RegisterInfo( + 4528, INT16, UnitOfTemperature.CELSIUS, 10 + ), "multi_battery_soc": RegisterInfo(4529, UINT16, PERCENTAGE, 10), - "multi_state": RegisterInfo(register=4530, dataType=UINT16, entityType=TextReadEntityType(generic_charger_state)), - "multi_mode": RegisterInfo(register=4531, dataType=UINT16, entityType=SelectWriteType(multi_mode)), - "multi_alarm_hightemperature": RegisterInfo(register=4532, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "multi_alarm_highvoltage": RegisterInfo(register=4533, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "multi_alarm_highvoltageacout": RegisterInfo(register=4534, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "multi_alarm_lowtemperature": RegisterInfo(register=4535, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "multi_alarm_lowvoltage": RegisterInfo(register=4536, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "multi_alarm_lowvoltageacout": RegisterInfo(register=4537, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "multi_alarm_overload": RegisterInfo(register=4538, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), - "multi_alarm_ripple": RegisterInfo(register=4539, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)), + "multi_state": RegisterInfo( + register=4530, + dataType=UINT16, + entityType=TextReadEntityType(generic_charger_state), + ), + "multi_mode": RegisterInfo( + register=4531, dataType=UINT16, entityType=SelectWriteType(multi_mode) + ), + "multi_alarm_hightemperature": RegisterInfo( + register=4532, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "multi_alarm_highvoltage": RegisterInfo( + register=4533, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "multi_alarm_highvoltageacout": RegisterInfo( + register=4534, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "multi_alarm_lowtemperature": RegisterInfo( + register=4535, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "multi_alarm_lowvoltage": RegisterInfo( + register=4536, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "multi_alarm_lowvoltageacout": RegisterInfo( + register=4537, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "multi_alarm_overload": RegisterInfo( + register=4538, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), + "multi_alarm_ripple": RegisterInfo( + register=4539, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), "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()), - "multi_mppoperationmode": RegisterInfo(register=4543, dataType=UINT16, entityType=TextReadEntityType(generic_mppoperationmode)), + "multi_relay": RegisterInfo( + register=4542, dataType=UINT16, entityType=BoolReadEntityType() + ), + "multi_mppoperationmode": RegisterInfo( + register=4543, + dataType=UINT16, + entityType=TextReadEntityType(generic_mppoperationmode), + ), "multi_pv_voltage": RegisterInfo(4544, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_errorcode": RegisterInfo(register=4545, dataType=UINT16, entityType=TextReadEntityType(generic_charger_errorcode)), - "multi_energy_acin1toacout": RegisterInfo(4546, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_acin1toinverter": RegisterInfo(4548, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_acin2toacout": RegisterInfo(4550, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_acin2toinverter": RegisterInfo(4552, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_acouttoacin1": RegisterInfo(4554, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_acouttoacin2": RegisterInfo(4556, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_invertertoacin1": RegisterInfo(4558, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_invertertoacin2": RegisterInfo(4560, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_invertertoacout": RegisterInfo(4562, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_outtoinverter": RegisterInfo(4564, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_solartoacin1": RegisterInfo(4566, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_solartoacin2": RegisterInfo(4568, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_energy_solartoacout": RegisterInfo(4570, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "mutli_energy_solartobattery": RegisterInfo(4572, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100), - "multi_history_yield_today": RegisterInfo(4574, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), + "multi_errorcode": RegisterInfo( + register=4545, + dataType=UINT16, + entityType=TextReadEntityType(generic_charger_errorcode), + ), + "multi_energy_acin1toacout": RegisterInfo( + 4546, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_acin1toinverter": RegisterInfo( + 4548, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_acin2toacout": RegisterInfo( + 4550, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_acin2toinverter": RegisterInfo( + 4552, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_acouttoacin1": RegisterInfo( + 4554, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_acouttoacin2": RegisterInfo( + 4556, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_invertertoacin1": RegisterInfo( + 4558, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_invertertoacin2": RegisterInfo( + 4560, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_invertertoacout": RegisterInfo( + 4562, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_outtoinverter": RegisterInfo( + 4564, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_solartoacin1": RegisterInfo( + 4566, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_solartoacin2": RegisterInfo( + 4568, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_energy_solartoacout": RegisterInfo( + 4570, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "mutli_energy_solartobattery": RegisterInfo( + 4572, UINT32, UnitOfEnergy.KILO_WATT_HOUR, 100 + ), + "multi_history_yield_today": RegisterInfo( + 4574, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), "multi_history_maxpower_today": RegisterInfo(4575, UINT16, UnitOfPower.WATT), - "multi_history_yield_yesterday": RegisterInfo(4576, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), + "multi_history_yield_yesterday": RegisterInfo( + 4576, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), "multi_history_maxpower_yesterday": RegisterInfo(4577, UINT16, UnitOfPower.WATT), - "multi_history_tracker_0_yield_today": RegisterInfo(4578, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "multi_history_tracker_1_yield_today": RegisterInfo(4579, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "multi_history_tracker_2_yield_today": RegisterInfo(4580, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "multi_history_tracker_3_yield_today": RegisterInfo(4581, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "multi_history_tracker_0_yield_yesterday": RegisterInfo(4582, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "multi_history_tracker_1_yield_yesterday": RegisterInfo(4583, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "multi_history_tracker_2_yield_yesterday": RegisterInfo(4584, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "multi_history_tracker_3_yield_yesterday": RegisterInfo(4585, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10), - "multi_history_tracker_0_maxpower_today": RegisterInfo(4586, UINT16, UnitOfPower.WATT), - "multi_history_tracker_1_maxpower_today": RegisterInfo(4587, UINT16, UnitOfPower.WATT), - "multi_history_tracker_2_maxpower_today": RegisterInfo(4588, UINT16, UnitOfPower.WATT), - "multi_history_tracker_3_maxpower_today": RegisterInfo(4589, UINT16, UnitOfPower.WATT), - "multi_history_tracker_0_maxpower_yesterday": RegisterInfo(4590, UINT16, UnitOfPower.WATT), - "multi_history_tracker_1_maxpower_yesterday": RegisterInfo(4591, UINT16, UnitOfPower.WATT), - "multi_history_tracker_2_maxpower_yesterday": RegisterInfo(4592, UINT16, UnitOfPower.WATT), - "multi_history_tracker_3_maxpower_yesterday": RegisterInfo(4593, UINT16, UnitOfPower.WATT), - "multi_tracker_0_voltage": RegisterInfo(4594, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_tracker_1_voltage": RegisterInfo(4595, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_tracker_2_voltage": RegisterInfo(4596, UINT16, UnitOfElectricPotential.VOLT, 10), - "multi_tracker_3_voltage": RegisterInfo(4597, UINT16, UnitOfElectricPotential.VOLT, 10), + "multi_history_tracker_0_yield_today": RegisterInfo( + 4578, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "multi_history_tracker_1_yield_today": RegisterInfo( + 4579, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "multi_history_tracker_2_yield_today": RegisterInfo( + 4580, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "multi_history_tracker_3_yield_today": RegisterInfo( + 4581, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "multi_history_tracker_0_yield_yesterday": RegisterInfo( + 4582, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "multi_history_tracker_1_yield_yesterday": RegisterInfo( + 4583, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "multi_history_tracker_2_yield_yesterday": RegisterInfo( + 4584, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "multi_history_tracker_3_yield_yesterday": RegisterInfo( + 4585, UINT16, UnitOfEnergy.KILO_WATT_HOUR, 10 + ), + "multi_history_tracker_0_maxpower_today": RegisterInfo( + 4586, UINT16, UnitOfPower.WATT + ), + "multi_history_tracker_1_maxpower_today": RegisterInfo( + 4587, UINT16, UnitOfPower.WATT + ), + "multi_history_tracker_2_maxpower_today": RegisterInfo( + 4588, UINT16, UnitOfPower.WATT + ), + "multi_history_tracker_3_maxpower_today": RegisterInfo( + 4589, UINT16, UnitOfPower.WATT + ), + "multi_history_tracker_0_maxpower_yesterday": RegisterInfo( + 4590, UINT16, UnitOfPower.WATT + ), + "multi_history_tracker_1_maxpower_yesterday": RegisterInfo( + 4591, UINT16, UnitOfPower.WATT + ), + "multi_history_tracker_2_maxpower_yesterday": RegisterInfo( + 4592, UINT16, UnitOfPower.WATT + ), + "multi_history_tracker_3_maxpower_yesterday": RegisterInfo( + 4593, UINT16, UnitOfPower.WATT + ), + "multi_tracker_0_voltage": RegisterInfo( + 4594, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_tracker_1_voltage": RegisterInfo( + 4595, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_tracker_2_voltage": RegisterInfo( + 4596, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "multi_tracker_3_voltage": RegisterInfo( + 4597, UINT16, UnitOfElectricPotential.VOLT, 10 + ), "multi_tracker_0_power": RegisterInfo(4598, UINT16, UnitOfPower.WATT), "multi_tracker_1_power": RegisterInfo(4599, UINT16, UnitOfPower.WATT), "multi_tracker_2_power": RegisterInfo(4600, UINT16, UnitOfPower.WATT), "multi_tracker_3_power": RegisterInfo(4601, UINT16, UnitOfPower.WATT), - "multi_alarm_lowsoc": RegisterInfo(register=4602, dataType=UINT16, entityType=TextReadEntityType(generic_alarm_ledger)) - + "multi_alarm_lowsoc": RegisterInfo( + register=4602, + dataType=UINT16, + entityType=TextReadEntityType(generic_alarm_ledger), + ), } + class register_input_source(Enum): UNKNOWN = 0 GRID = 1 @@ -1287,10 +2422,15 @@ class register_input_source(Enum): SHORE = 3 NOT_CONNECTED = 240 + system_registers = { "system_serial": RegisterInfo(800, STRING(6)), - "system_relay_0": RegisterInfo(register=806, dataType=UINT16, entityType=SwitchWriteType()), - "system_relay_1": RegisterInfo(register=807, dataType=UINT16, entityType=SwitchWriteType()), + "system_relay_0": RegisterInfo( + register=806, dataType=UINT16, entityType=SwitchWriteType() + ), + "system_relay_1": RegisterInfo( + register=807, dataType=UINT16, entityType=SwitchWriteType() + ), "system_pvonoutput_L1": RegisterInfo(808, UINT16, UnitOfPower.WATT), "system_pvonoutput_L2": RegisterInfo(809, UINT16, UnitOfPower.WATT), "system_pvonoutput_L3": RegisterInfo(810, UINT16, UnitOfPower.WATT), @@ -1309,27 +2449,43 @@ class register_input_source(Enum): "system_genset_L1": RegisterInfo(823, INT16, UnitOfPower.WATT), "system_genset_L2": RegisterInfo(824, INT16, UnitOfPower.WATT), "system_genset_L3": RegisterInfo(825, INT16, UnitOfPower.WATT), - "system_input_source": RegisterInfo(register=826, dataType=INT16, entityType=TextReadEntityType(register_input_source)) + "system_input_source": RegisterInfo( + register=826, + dataType=INT16, + entityType=TextReadEntityType(register_input_source), + ), } + class system_battery_state(Enum): IDLE = 0 CHARGING = 1 DISCHARGING = 2 + system_battery_registers = { - "system_battery_voltage": RegisterInfo(840, UINT16, UnitOfElectricPotential.VOLT, 10), - "system_battery_current": RegisterInfo(841, INT16, UnitOfElectricCurrent.AMPERE, 10), + "system_battery_voltage": RegisterInfo( + 840, UINT16, UnitOfElectricPotential.VOLT, 10 + ), + "system_battery_current": RegisterInfo( + 841, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), "system_battery_power": RegisterInfo(842, INT16, UnitOfPower.WATT), "system_battery_soc": RegisterInfo(843, UINT16, PERCENTAGE), - "system_battery_state": RegisterInfo(register=844, dataType=UINT16, entityType=TextReadEntityType(system_battery_state)), - "system_battery_amphours": RegisterInfo(845, UINT16, UnitOfElectricCurrent.AMPERE, -10), # NOTE should be amp hours - "system_battery_time_to_go": RegisterInfo(846, UINT16, UnitOfTime.SECONDS, 0.01) + "system_battery_state": RegisterInfo( + register=844, + dataType=UINT16, + entityType=TextReadEntityType(system_battery_state), + ), + "system_battery_amphours": RegisterInfo( + 845, UINT16, UnitOfElectricCurrent.AMPERE, -10 + ), # NOTE should be amp hours + "system_battery_time_to_go": RegisterInfo(846, UINT16, UnitOfTime.SECONDS, 0.01), } system_dc_registers = { "system_dc_pv_power": RegisterInfo(850, UINT16, UnitOfPower.WATT), - "system_dc_pv_current": RegisterInfo(851, INT16, UnitOfElectricCurrent.AMPERE, 10) + "system_dc_pv_current": RegisterInfo(851, INT16, UnitOfElectricCurrent.AMPERE, 10), } system_charger_registers = { @@ -1341,61 +2497,139 @@ class system_battery_state(Enum): } system_bus_registers = { - "system_bus_charge_current": RegisterInfo(865, INT16, UnitOfElectricCurrent.AMPERE, 10), - "system_bus_charge_power": RegisterInfo(866, INT16, UnitOfPower.WATT) + "system_bus_charge_current": RegisterInfo( + 865, INT16, UnitOfElectricCurrent.AMPERE, 10 + ), + "system_bus_charge_power": RegisterInfo(866, INT16, UnitOfPower.WATT), } -valid_unit_ids = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, - 11, 12, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, - 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, - 44, 45, 46, 100, 101, 204, 205, 206, 207, 208, 209, - 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, - 221, 222, 223, 224, 225, 226, 227, 228, 229, 230, 231, - 232, 233, 234, 235, 236, 237, 238, 239, 242, 243, 245, - 246, 247 - ] - -register_info_dict = { +valid_unit_ids = [ + 0, + 1, + 2, + 3, + 4, + 5, + 6, + 7, + 8, + 9, + 10, + 11, + 12, + 20, + 21, + 22, + 23, + 24, + 25, + 26, + 27, + 28, + 29, + 30, + 31, + 32, + 33, + 34, + 35, + 36, + 37, + 38, + 39, + 40, + 41, + 42, + 43, + 44, + 45, + 46, + 100, + 101, + 204, + 205, + 206, + 207, + 208, + 209, + 210, + 211, + 212, + 213, + 214, + 215, + 216, + 217, + 218, + 219, + 220, + 221, + 222, + 223, + 224, + 225, + 226, + 227, + 228, + 229, + 230, + 231, + 232, + 233, + 234, + 235, + 236, + 237, + 238, + 239, + 242, + 243, + 245, + 246, + 247, +] + +register_info_dict = { "gavazi_grid_registers": gavazi_grid_registers, - "vebus_registers": vebus_registers, - "battery_registers": battery_registers, - "battery_detail_registers": battery_detail_registers, + "vebus_registers": vebus_registers, + "battery_registers": battery_registers, + "battery_detail_registers": battery_detail_registers, "solarcharger_registers": solarcharger_registers, "solarcharger_tracker_voltage_registers": solarcharger_tracker_voltage_registers, - "solarcharger_tracker_registers": solarcharger_tracker_registers, - "pvinverter_registers": pvinverter_registers, + "solarcharger_tracker_registers": solarcharger_tracker_registers, + "pvinverter_registers": pvinverter_registers, "motordrive_registers": motordrive_registers, - "charger_registers": charger_registers, + "charger_registers": charger_registers, "settings_registers": settings_registers, - "gps_registers": gps_registers, - "settings_ess_registers": settings_ess_registers, - "tank_registers": tank_registers, + "gps_registers": gps_registers, + "settings_ess_registers": settings_ess_registers, + "tank_registers": tank_registers, "inverter_output_registers": inverter_output_registers, - "inverter_battery_registers": inverter_battery_registers, - "inverter_alarm_registers": inverter_alarm_registers, + "inverter_battery_registers": inverter_battery_registers, + "inverter_alarm_registers": inverter_alarm_registers, "inverter_info_registers": inverter_info_registers, - "inverter_energy_registers": inverter_energy_registers, - "inverter_tracker_registers": inverter_tracker_registers, + "inverter_energy_registers": inverter_energy_registers, + "inverter_tracker_registers": inverter_tracker_registers, "inverter_tracker_statistics_registers": inverter_tracker_statistics_registers, - "genset_registers": genset_registers, - "temperature_registers": temperature_registers, - "pulsemeter_registers": pulsemeter_registers, + "genset_registers": genset_registers, + "temperature_registers": temperature_registers, + "pulsemeter_registers": pulsemeter_registers, "digitalinput_registers": digitalinput_registers, - "generator_registers": generator_registers, + "generator_registers": generator_registers, "meteo_registers": meteo_registers, - "evcharger_productid_registers": evcharger_productid_registers, + "evcharger_productid_registers": evcharger_productid_registers, "evcharger_registers": evcharger_registers, - "acload_registers": acload_registers, - "fuelcell_registers": fuelcell_registers, - "alternator_registers": alternator_registers, + "acload_registers": acload_registers, + "fuelcell_registers": fuelcell_registers, + "alternator_registers": alternator_registers, "dcsource_registers": dcsource_registers, - "dcload_registers": dcload_registers, - "dcsystem_registers": dcsystem_registers, - "multi_registers": multi_registers, + "dcload_registers": dcload_registers, + "dcsystem_registers": dcsystem_registers, + "multi_registers": multi_registers, "system_registers": system_registers, - "system_battery_registers": system_battery_registers, - "system_dc_registers": system_dc_registers, + "system_battery_registers": system_battery_registers, + "system_dc_registers": system_dc_registers, "system_charger_registers": system_charger_registers, - "system_power_registers": system_power_registers, - "system_bus_registers": system_bus_registers -} + "system_power_registers": system_power_registers, + "system_bus_registers": system_bus_registers, +} diff --git a/custom_components/victron/coordinator.py b/custom_components/victron/coordinator.py index 99ff9f6..452700b 100644 --- a/custom_components/victron/coordinator.py +++ b/custom_components/victron/coordinator.py @@ -1,24 +1,32 @@ from __future__ import annotations -import logging - -from .hub import VictronHub - from collections import OrderedDict - -from homeassistant.core import HomeAssistant -from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed +from datetime import timedelta +import logging from pymodbus.constants import Endian from pymodbus.payload import BinaryPayloadDecoder -from pymodbus.register_read_message import ReadHoldingRegistersResponse +from pymodbus.pdu.register_read_message import ReadHoldingRegistersResponse -from datetime import timedelta +from homeassistant.core import HomeAssistant +from homeassistant.exceptions import HomeAssistantError +from homeassistant.helpers.update_coordinator import DataUpdateCoordinator, UpdateFailed -from .const import DOMAIN, UINT16, UINT32, INT16, INT32, STRING, RegisterInfo, register_info_dict +from .const import ( + DOMAIN, + INT16, + INT32, + STRING, + UINT16, + UINT32, + RegisterInfo, + register_info_dict, +) +from .hub import VictronHub _LOGGER = logging.getLogger(__name__) + class victronEnergyDeviceUpdateCoordinator(DataUpdateCoordinator): """Gather data for the energy device.""" @@ -31,13 +39,12 @@ def __init__( port: str, decodeInfo: OrderedDict, interval: int, - - - ) -> None: """Initialize Update Coordinator.""" - super().__init__(hass, _LOGGER, name=DOMAIN, update_interval=timedelta(seconds=interval)) + super().__init__( + hass, _LOGGER, name=DOMAIN, update_interval=timedelta(seconds=interval) + ) self.api = VictronHub(host, port) self.api.connect() self.decodeInfo = decodeInfo @@ -47,7 +54,6 @@ def __init__( # data = await self._async_update_data() # self.async_set_updated_data(data) - async def _async_update_data(self) -> dict: """Fetch all device and sensor data from api.""" data = "" @@ -59,68 +65,94 @@ async def _async_update_data(self) -> dict: unavailable_entities = OrderedDict() if self.data is None: - self.data = { "data": OrderedDict(), "availability": OrderedDict() } + self.data = {"data": OrderedDict(), "availability": OrderedDict()} for unit, registerInfo in self.decodeInfo.items(): for name in registerInfo: data = await self.fetch_registers(unit, register_info_dict[name]) - #TODO safety check if result is actual data if not unavailable + # TODO safety check if result is actual data if not unavailable if data.isError(): - #raise error - #TODO change this to work with partial updates - for key,value in register_info_dict[name].items(): + # raise error + # TODO change this to work with partial updates + for key in register_info_dict[name]: full_key = str(unit) + "." + key # self.data["data"][full_key] = None unavailable_entities[full_key] = False - _LOGGER.warning(f"no valid data returned for entities of slave: {unit} (if the device continues to no longer update) check if the device was physically removed. Before opening an issue please force a rescan to attempt to resolve this issue") + _LOGGER.warning( + "no valid data returned for entities of slave: %s (if the device continues to no longer update) check if the device was physically removed. Before opening an issue please force a rescan to attempt to resolve this issue", + unit, + ) else: - parsed_data = OrderedDict(list(parsed_data.items()) + list(self.parse_register_data(data, register_info_dict[name], unit).items())) - for key,value in register_info_dict[name].items(): + parsed_data = OrderedDict( + list(parsed_data.items()) + + list( + self.parse_register_data( + data, register_info_dict[name], unit + ).items() + ) + ) + for key in register_info_dict[name]: full_key = str(unit) + "." + key unavailable_entities[full_key] = True return { "register_set": self.decodeInfo, "data": parsed_data, - "availability": unavailable_entities + "availability": unavailable_entities, } - def parse_register_data(self, buffer: ReadHoldingRegistersResponse, registerInfo: OrderedDict(str, RegisterInfo), unit: int) -> dict: + def parse_register_data( + self, + buffer: ReadHoldingRegistersResponse, + registerInfo: OrderedDict(str, RegisterInfo), + unit: int, + ) -> dict: decoder = BinaryPayloadDecoder.fromRegisters( - buffer.registers, byteorder=Endian.BIG + buffer.registers, byteorder=Endian.BIG ) - decoded_data = OrderedDict() - for key,value in registerInfo.items(): + decoded_data = OrderedDict() + for key, value in registerInfo.items(): full_key = str(unit) + "." + key if value.dataType == UINT16: - decoded_data[full_key] = self.decode_scaling(decoder.decode_16bit_uint(), value.scale, value.unit) + decoded_data[full_key] = self.decode_scaling( + decoder.decode_16bit_uint(), value.scale, value.unit + ) elif value.dataType == INT16: - decoded_data[full_key] = self.decode_scaling(decoder.decode_16bit_int(), value.scale, value.unit) + decoded_data[full_key] = self.decode_scaling( + decoder.decode_16bit_int(), value.scale, value.unit + ) elif value.dataType == UINT32: - decoded_data[full_key] = self.decode_scaling(decoder.decode_32bit_uint(), value.scale, value.unit) + decoded_data[full_key] = self.decode_scaling( + decoder.decode_32bit_uint(), value.scale, value.unit + ) elif value.dataType == INT32: - decoded_data[full_key] = self.decode_scaling(decoder.decode_32bit_int(), value.scale, value.unit) + decoded_data[full_key] = self.decode_scaling( + decoder.decode_32bit_int(), value.scale, value.unit + ) elif isinstance(value.dataType, STRING): - decoded_data[full_key] = decoder.decode_string(value.dataType.readLength).split(b'\x00')[0].decode() + decoded_data[full_key] = ( + decoder.decode_string(value.dataType.readLength) + .split(b"\x00")[0] + .decode() + ) else: - raise DecodeDataTypeUnsupported(f'Not supported dataType: {value.dataType}') + raise DecodeDataTypeUnsupported( + f"Not supported dataType: {value.dataType}" + ) return decoded_data def decode_scaling(self, number, scale, unit): if unit == "" and scale == 1: return round(number) - else: - return number / scale + return number / scale def encode_scaling(self, value, unit, scale): if scale == 0: return value - else: - if unit == "" and scale == 1: - return int(round(value)) - else: - return int(value * scale) + if unit == "" and scale == 1: + return int(round(value)) + return int(value * scale) def get_data(self): return self.data @@ -129,7 +161,8 @@ async def async_update_local_entry(self, key, value): data = self.data data["data"][key] = value self.async_set_updated_data(data) - + """Force update data after change.""" + await self.async_request_refresh() def processed_data(self): return self.data @@ -137,39 +170,40 @@ def processed_data(self): async def fetch_registers(self, unit, registerData): try: # run api_update in async job - resp = await self.hass.async_add_executor_job( + return await self.hass.async_add_executor_job( self.api_update, unit, registerData ) - return resp - - except: - raise UpdateFailed("Fetching registers failed") + except HomeAssistantError as e: + raise UpdateFailed("Fetching registers failed") from e def write_register(self, unit, address, value): # try: - resp = self.api_write(unit, address, value) - # except: - # TODO raise specific write error - # _LOGGER.error("failed to write to option") + self.api_write(unit, address, value) + # except HomeAssistantError as e: + # TODO raise specific write error + # _LOGGER.error("failed to write to option:", e def api_write(self, unit, address, value): - #recycle connection + # recycle connection return self.api.write_register(unit=unit, address=address, value=value) def api_update(self, unit, registerInfo): - #recycle connection + # 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) + unit=unit, + address=self.api.get_first_register_id(registerInfo), + count=self.api.calculate_register_count(registerInfo), ) + class DecodeDataTypeUnsupported(Exception): pass -class DataEntry(): +class DataEntry: def __init__(self, unit, value) -> None: self.unit = unit - self.value = value \ No newline at end of file + self.value = value diff --git a/custom_components/victron/hub.py b/custom_components/victron/hub.py index 8aa8fc0..655a7dc 100644 --- a/custom_components/victron/hub.py +++ b/custom_components/victron/hub.py @@ -1,16 +1,17 @@ +from collections import OrderedDict +import logging +import threading + from pymodbus.client import ModbusTcpClient -from pymodbus.exceptions import ModbusException -import threading -from collections import OrderedDict -from .const import UINT32, INT32, STRING, register_info_dict, valid_unit_ids +from homeassistant.exceptions import HomeAssistantError -import logging +from .const import INT32, STRING, UINT32, register_info_dict, valid_unit_ids _LOGGER = logging.getLogger(__name__) -class VictronHub: +class VictronHub: def __init__(self, host: str, port: int) -> None: """Initialize.""" self.host = host @@ -23,10 +24,11 @@ def is_still_connected(self): def connect(self): return self._client.connect() - + def disconnect(self): if self._client.is_socket_open(): return self._client.close() + return None def write_register(self, unit, address, value): with self._lock: @@ -48,8 +50,9 @@ def calculate_register_count(self, registerInfoDict: OrderedDict): elif isinstance(registerInfoDict[last_key].dataType, STRING): end_correction = registerInfoDict[last_key].dataType.length - - return (registerInfoDict[last_key].register - registerInfoDict[first_key].register) + end_correction + return ( + registerInfoDict[last_key].register - registerInfoDict[first_key].register + ) + end_correction def get_first_register_id(self, registerInfoDict: OrderedDict): first_register = next(iter(registerInfoDict)) @@ -61,8 +64,8 @@ def determine_present_devices(self): for unit in valid_unit_ids: working_registers = [] for key, register_definition in register_info_dict.items(): - #VE.CAN device zero is present under unit 100. This seperates non system / settings entities into the seperate can device - if unit == 100 and not key.startswith(("settings", "system")) : + # VE.CAN device zero is present under unit 100. This seperates non system / settings entities into the seperate can device + if unit == 100 and not key.startswith(("settings", "system")): continue try: @@ -70,13 +73,19 @@ def determine_present_devices(self): count = self.calculate_register_count(register_definition) result = self.read_holding_registers(unit, address, count) if result.isError(): - _LOGGER.debug("result is error for unit: " + str(unit) + " address: " + str(address) + " count: " + str(count)) + _LOGGER.debug( + "result is error for unit: " + + str(unit) + + " address: " + + str(address) + + " count: " + + str(count) + ) else: working_registers.append(key) - except Exception as e: # pylint: disable=broad-except + except HomeAssistantError as e: _LOGGER.error(e) - if len(working_registers) > 0: valid_devices[unit] = working_registers else: diff --git a/custom_components/victron/manifest.json b/custom_components/victron/manifest.json index 28d644f..e0217bb 100644 --- a/custom_components/victron/manifest.json +++ b/custom_components/victron/manifest.json @@ -12,9 +12,9 @@ "iot_class": "local_polling", "issue_tracker": "https://github.com/sfstar/hass-victron/issues", "requirements": [ - "pymodbus>=3.5.1" + "pymodbus>=3.7.4" ], "ssdp": [], - "version": "0.0.11", + "version": "v0.4.0", "zeroconf": [] } diff --git a/custom_components/victron/number.py b/custom_components/victron/number.py index d1f7ff1..fbbb315 100644 --- a/custom_components/victron/number.py +++ b/custom_components/victron/number.py @@ -1,81 +1,97 @@ """Support for victron energy slider number entities.""" + from __future__ import annotations -from collections.abc import Callable from dataclasses import dataclass -from typing import Optional, cast +import logging from homeassistant import config_entries -from homeassistant.components.number import NumberEntity, NumberEntityDescription, NumberMode, DOMAIN as NUMBER_DOMAIN - +from homeassistant.components.number import ( + DOMAIN as NUMBER_DOMAIN, + NumberEntity, + NumberEntityDescription, + NumberMode, +) from homeassistant.const import ( PERCENTAGE, + UnitOfElectricCurrent, UnitOfElectricPotential, UnitOfPower, - UnitOfElectricCurrent, - UnitOfTime ) - -import math - -from homeassistant.core import HomeAssistant, callback +from homeassistant.core import HomeAssistant +from homeassistant.helpers import entity from homeassistant.helpers.entity import EntityCategory from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity -from .coordinator import victronEnergyDeviceUpdateCoordinator from .base import VictronWriteBaseEntityDescription -from .const import ( - DOMAIN, - register_info_dict, - SliderWriteType, - CONF_ADVANCED_OPTIONS, - UINT16_MAX, - CONF_DC_SYSTEM_VOLTAGE, - CONF_DC_CURRENT_LIMIT, +from .const import ( + CONF_AC_CURRENT_LIMIT, + CONF_AC_SYSTEM_VOLTAGE, + CONF_ADVANCED_OPTIONS, + CONF_DC_CURRENT_LIMIT, + CONF_DC_SYSTEM_VOLTAGE, CONF_NUMBER_OF_PHASES, CONF_USE_SLIDERS, - CONF_AC_SYSTEM_VOLTAGE, - CONF_AC_CURRENT_LIMIT) - -from homeassistant.helpers.typing import StateType -from homeassistant.helpers import entity - -import logging + DOMAIN, + UINT16_MAX, + SliderWriteType, + register_info_dict, +) +from .coordinator import victronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) + async def async_setup_entry( hass: HomeAssistant, config_entry: config_entries.ConfigEntry, async_add_entities: AddEntitiesCallback, ) -> None: """Set up victron switch devices.""" - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] + victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + config_entry.entry_id + ] _LOGGER.debug("attempting to setup number entities") descriptions = [] _LOGGER.debug(config_entry) - #TODO cleanup + # 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(): - _LOGGER.debug("unit == " + str(slave) + " registerLedger == " + str(registerLedger) + " registerInfo ") + _LOGGER.debug( + "unit == " + + str(slave) + + " registerLedger == " + + str(registerLedger) + + " registerInfo " + ) if isinstance(registerInfo.entityType, SliderWriteType): description = VictronEntityDescription( key=register_name, - name=register_name.replace('_', ' '), + name=register_name.replace("_", " "), slave=slave, native_unit_of_measurement=registerInfo.unit, - mode=NumberMode.SLIDER if config_entry.options[CONF_USE_SLIDERS] else NumberMode.BOX, - native_min_value=determine_min_value(registerInfo.unit, config_entry.options, registerInfo.entityType.powerType, registerInfo.entityType.negative), - native_max_value=determine_max_value(registerInfo.unit, config_entry.options, registerInfo.entityType.powerType), + mode=NumberMode.SLIDER + if config_entry.options[CONF_USE_SLIDERS] + else NumberMode.BOX, + native_min_value=determine_min_value( + registerInfo.unit, + config_entry.options, + registerInfo.entityType.powerType, + registerInfo.entityType.negative, + ), + native_max_value=determine_max_value( + registerInfo.unit, + config_entry.options, + registerInfo.entityType.powerType, + ), entity_category=EntityCategory.CONFIG, address=registerInfo.register, - scale = registerInfo.scale, - native_step = registerInfo.step + scale=registerInfo.scale, + native_step=registerInfo.step, ) _LOGGER.debug("composed description == " + str(descriptions)) descriptions.append(description) @@ -84,84 +100,119 @@ async def async_setup_entry( entity = {} for description in descriptions: entity = description - entities.append( - VictronNumber( - victron_coordinator, - entity - )) + entities.append(VictronNumber(victron_coordinator, entity)) _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: +def determine_min_value( + unit, config_entry: config_entries.ConfigEntry, powerType, negative: bool +) -> int: if unit == PERCENTAGE: return 0 - elif unit == UnitOfElectricPotential.VOLT: - series_type = int(config_entry[CONF_DC_SYSTEM_VOLTAGE]) / 3 #statically based on lifepo4 cells - min_value = series_type * 2.5 #statically based on lifepo4 cells - return min_value - elif unit == UnitOfPower.WATT: + if unit == UnitOfElectricPotential.VOLT: + series_type = ( + int(config_entry[CONF_DC_SYSTEM_VOLTAGE]) / 3 + ) # statically based on lifepo4 cells + return series_type * 2.5 # statically based on lifepo4 cells + if unit == UnitOfPower.WATT: if negative: - min_value = (int(config_entry[CONF_AC_SYSTEM_VOLTAGE]) * int(config_entry[CONF_NUMBER_OF_PHASES]) * config_entry[CONF_AC_CURRENT_LIMIT]) if powerType == "AC" else (int(config_entry[CONF_DC_SYSTEM_VOLTAGE].dc_voltage) * config_entry[CONF_DC_CURRENT_LIMIT]) - rounded_min = -round(min_value/100)*100 + min_value = ( + ( + int(config_entry[CONF_AC_SYSTEM_VOLTAGE]) + * int(config_entry[CONF_NUMBER_OF_PHASES]) + * config_entry[CONF_AC_CURRENT_LIMIT] + ) + if powerType == "AC" + else ( + int(config_entry[CONF_DC_SYSTEM_VOLTAGE].dc_voltage) + * config_entry[CONF_DC_CURRENT_LIMIT] + ) + ) + rounded_min = -round(min_value / 100) * 100 _LOGGER.debug(rounded_min) return rounded_min - else: - return 0 - elif unit == UnitOfElectricCurrent.AMPERE: + return 0 + if unit == UnitOfElectricCurrent.AMPERE: if negative: if powerType == "AC": return -config_entry[CONF_AC_CURRENT_LIMIT] - elif powerType == "DC": + if powerType == "DC": return -config_entry[CONF_DC_CURRENT_LIMIT] - else: - return 0 - else: + return None return 0 + return 0 + -def determine_max_value(unit, config_entry:config_entries.ConfigEntry, powerType) -> int: +def determine_max_value( + unit, config_entry: config_entries.ConfigEntry, powerType +) -> int: if unit == PERCENTAGE: return 100 - elif unit == UnitOfElectricPotential.VOLT: - series_type = int(config_entry[CONF_DC_SYSTEM_VOLTAGE]) / 3 #statically based on lifepo4 cells - max_value = series_type * 3.65 #statically based on lifepo4 cells - return max_value - elif unit == UnitOfPower.WATT: - max_value = (int(config_entry[CONF_AC_SYSTEM_VOLTAGE]) * int(config_entry[CONF_NUMBER_OF_PHASES]) * config_entry[CONF_AC_CURRENT_LIMIT]) if powerType == "AC" else (int(config_entry[CONF_DC_SYSTEM_VOLTAGE]) * config_entry[CONF_DC_CURRENT_LIMIT]) - rounded_max = round(max_value/100)*100 - return rounded_max - elif unit == UnitOfElectricCurrent.AMPERE: + if unit == UnitOfElectricPotential.VOLT: + series_type = ( + int(config_entry[CONF_DC_SYSTEM_VOLTAGE]) / 3 + ) # statically based on lifepo4 cells + return series_type * 3.65 # statically based on lifepo4 cells + if unit == UnitOfPower.WATT: + max_value = ( + ( + int(config_entry[CONF_AC_SYSTEM_VOLTAGE]) + * int(config_entry[CONF_NUMBER_OF_PHASES]) + * config_entry[CONF_AC_CURRENT_LIMIT] + ) + if powerType == "AC" + else ( + int(config_entry[CONF_DC_SYSTEM_VOLTAGE]) + * config_entry[CONF_DC_CURRENT_LIMIT] + ) + ) + return round(max_value / 100) * 100 + if unit == UnitOfElectricCurrent.AMPERE: if powerType == "AC": return config_entry[CONF_AC_CURRENT_LIMIT] - elif powerType == "DC": + if powerType == "DC": return config_entry[CONF_DC_CURRENT_LIMIT] - else: - return 0 + return None + return 0 @dataclass class VictronNumberMixin: """A class that describes number entities.""" - scale: int | None = None - mode: bool | None = None + + scale: int | None = None + mode: bool | None = None + @dataclass class VictronNumberStep: native_step: float = 0 + @dataclass -class VictronEntityDescription(NumberEntityDescription, VictronWriteBaseEntityDescription, VictronNumberMixin, VictronNumberStep): - #Overwrite base entitydescription property to resolve automatic property ordering issues when a mix of non-default and default properties are used - key: str | None = None +class VictronEntityDescription( + NumberEntityDescription, + VictronWriteBaseEntityDescription, + VictronNumberMixin, + VictronNumberStep, +): + # Overwrite base entitydescription property to resolve automatic property ordering issues when a mix of non-default and default properties are used + key: str | None = None """Describes victron number entity.""" + class VictronNumber(NumberEntity): """Victron number.""" description: VictronEntityDescription - def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription) -> None: + def __init__( + self, + coordinator: victronEnergyDeviceUpdateCoordinator, + description: VictronEntityDescription, + ) -> None: """Initialize the entity.""" self.coordinator = coordinator self.description = description @@ -169,7 +220,11 @@ def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, descriptio self.data_key = str(self.description.slave) + "." + str(self.description.key) - self._attr_native_value = self.description.value_fn(self.coordinator.processed_data(), self.description.slave, self.description.key) + self._attr_native_value = self.description.value_fn( + self.coordinator.processed_data(), + self.description.slave, + self.description.key, + ) self._attr_unique_id = f"{self.description.slave}_{self.description.key}" if self.description.slave not in (100, 225): @@ -178,42 +233,54 @@ def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, descriptio self.entity_id = f"{NUMBER_DOMAIN}.{DOMAIN}_{self.description.key}" self._attr_mode = self.description.mode - - async def async_set_native_value(self, value: float) -> None: """Update the current value.""" - #TODO convert float to int again with scale respected + # TODO convert float to int again with scale respected if value < 0: value = UINT16_MAX + value - self.coordinator.write_register(unit=self.description.slave, address=self.description.address, value=self.coordinator.encode_scaling(value, self.description.native_unit_of_measurement, self.description.scale)) + self.coordinator.write_register( + unit=self.description.slave, + address=self.description.address, + value=self.coordinator.encode_scaling( + value, + self.description.native_unit_of_measurement, + self.description.scale, + ), + ) await self.coordinator.async_update_local_entry(self.data_key, int(value)) - @property def native_value(self) -> float: """Return the state of the entity.""" - value = self.description.value_fn(data=self.coordinator.processed_data(), slave=self.description.slave, key=self.description.key) - if value > round(UINT16_MAX/2): #Half of the UINT16 is reserved for positive and half for negative values + value = self.description.value_fn( + data=self.coordinator.processed_data(), + slave=self.description.slave, + key=self.description.key, + ) + if value > round( + UINT16_MAX / 2 + ): # Half of the UINT16 is reserved for positive and half for negative values value = value - UINT16_MAX return value @property def native_step(self) -> float | None: - if not self.description.mode == NumberMode.SLIDER: # allow users to skip stepping in case of box mode + if ( + self.description.mode != NumberMode.SLIDER + ): # allow users to skip stepping in case of box mode return None if self.description.native_step > 0: return self.description.native_step - max = self.native_max_value - min = self.native_min_value - gap = len(list(range(int(min), int(max), 1))) - #TODO optimize gap step selection + _max = self.native_max_value + _min = self.native_min_value + gap = len(list(range(int(_min), int(_max), 1))) + # TODO optimize gap step selection if gap >= 3000: return 100 - elif gap < 3000 and gap > 100: + if 3000 > gap > 100: return 10 - else: - return 1 + return 1 @property def native_min_value(self) -> float: @@ -232,10 +299,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]) - }, - name=self.unique_id.split('_')[1], - model=self.unique_id.split('_')[0], + identifiers={(DOMAIN, self.unique_id.split("_")[0])}, + name=self.unique_id.split("_")[1], + model=self.unique_id.split("_")[0], manufacturer="victron", ) diff --git a/custom_components/victron/select.py b/custom_components/victron/select.py index 7c20222..056c464 100644 --- a/custom_components/victron/select.py +++ b/custom_components/victron/select.py @@ -1,52 +1,60 @@ """Support for Victron energy switches.""" -from __future__ import annotations -from enum import Enum +from __future__ import annotations from dataclasses import dataclass +from datetime import timedelta +from enum import Enum +import logging -from homeassistant.components.select import SelectEntity, SelectEntityDescription, DOMAIN as SELECT_DOMAIN +from homeassistant.components.select import ( + DOMAIN as SELECT_DOMAIN, + SelectEntity, + SelectEntityDescription, +) from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant, HassJob +from homeassistant.core import HassJob, HomeAssistant +from homeassistant.helpers import entity, event from homeassistant.helpers.entity_platform import AddEntitiesCallback - -from .coordinator import victronEnergyDeviceUpdateCoordinator from homeassistant.helpers.update_coordinator import CoordinatorEntity -from homeassistant.helpers import entity - -from .const import DOMAIN, register_info_dict, SelectWriteType, CONF_ADVANCED_OPTIONS -from .base import VictronWriteBaseEntityDescription - -from collections.abc import Callable -from homeassistant.helpers.typing import StateType - -from datetime import timedelta from homeassistant.util import utcnow -from homeassistant.helpers import event, entity -import logging +from .base import VictronWriteBaseEntityDescription +from .const import CONF_ADVANCED_OPTIONS, DOMAIN, SelectWriteType, register_info_dict +from .coordinator import victronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) + async def async_setup_entry( - hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, ) -> None: """Set up victron select devices.""" - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] + victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + config_entry.entry_id + ] _LOGGER.debug("attempting to setup select entities") descriptions = [] - #TODO cleanup + # 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): - _LOGGER.debug("unit == " + str(slave) + " registerLedger == " + str(registerLedger) + " registerInfo ") - + _LOGGER.debug( + "unit == " + + str(slave) + + " registerLedger == " + + str(registerLedger) + + " registerInfo " + ) + description = VictronEntityDescription( key=register_name, - name=register_name.replace('_', ' '), + name=register_name.replace("_", " "), slave=slave, options=registerInfo.entityType.options, address=registerInfo.register, @@ -59,30 +67,37 @@ async def async_setup_entry( entity = {} for description in descriptions: entity = description - entities.append( - VictronSelect( - hass, - victron_coordinator, - entity - )) + entities.append(VictronSelect(hass, victron_coordinator, entity)) _LOGGER.debug("adding selects") _LOGGER.debug(entities) async_add_entities(entities) @dataclass -class VictronEntityDescription(SelectEntityDescription, VictronWriteBaseEntityDescription): +class VictronEntityDescription( + SelectEntityDescription, VictronWriteBaseEntityDescription +): """Describes victron sensor entity.""" + options: Enum = None + class VictronSelect(CoordinatorEntity, SelectEntity): - """Representation of an Victron switch.""" + """Representation of a Victron switch.""" + + description: VictronEntityDescription - def __init__(self, hass: HomeAssistant, coordinator: victronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription) -> None: + def __init__( + self, + hass: HomeAssistant, + coordinator: victronEnergyDeviceUpdateCoordinator, + description: VictronEntityDescription, + ) -> None: + self._attr_native_value = None _LOGGER.debug("select init") self.coordinator = coordinator self.description: VictronEntityDescription = description - #this needs to be changed to allow multiple of the same type + # this needs to be changed to allow multiple of the same type self._attr_name = f"{description.name}" self._attr_unique_id = f"{self.description.slave}_{self.description.key}" @@ -99,7 +114,11 @@ 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.coordinator.processed_data(), self.description.slave, self.description.key) + self._attr_native_value = self.description.value_fn( + self.coordinator.processed_data(), + self.description.slave, + self.description.key, + ) except (TypeError, IndexError): _LOGGER.debug("failed to retrieve value") # No data available @@ -117,10 +136,15 @@ async def async_update(self) -> None: utcnow() + timedelta(seconds=self.coordinator.interval), ) - @property def current_option(self) -> str: - return self.description.options(self.description.value_fn(self.coordinator.processed_data(), self.description.slave, self.description.key)).name + return self.description.options( + self.description.value_fn( + self.coordinator.processed_data(), + self.description.slave, + self.description.key, + ) + ).name @property def options(self) -> list: @@ -128,8 +152,15 @@ def options(self) -> list: async def async_select_option(self, option: str) -> None: """Change the selected option.""" - self.coordinator.write_register(unit=self.description.slave, address=self.description.address, value=self.coordinator.encode_scaling(int(self.description.options[option].value), "", 0)) - #TODO extract these type of property definitions to base class + self.coordinator.write_register( + unit=self.description.slave, + address=self.description.address, + value=self.coordinator.encode_scaling( + int(self.description.options[option].value), "", 0 + ), + ) + + # TODO extract these type of property definitions to base class @property def available(self) -> bool: full_key = str(self.description.slave) + "." + self.description.key @@ -139,10 +170,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]) - }, - name=self.unique_id.split('_')[1], - model=self.unique_id.split('_')[0], + identifiers={(DOMAIN, self.unique_id.split("_")[0])}, + name=self.unique_id.split("_")[1], + model=self.unique_id.split("_")[0], manufacturer="victron", - ) \ No newline at end of file + ) diff --git a/custom_components/victron/sensor.py b/custom_components/victron/sensor.py index 9c4019d..c0853f5 100644 --- a/custom_components/victron/sensor.py +++ b/custom_components/victron/sensor.py @@ -1,41 +1,47 @@ """Support for Victron energy sensors.""" from dataclasses import dataclass - import logging -from datetime import timedelta -from homeassistant.util import utcnow -from homeassistant.helpers import event, entity -from homeassistant.core import HomeAssistant, HassJob, callback -from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity +from homeassistant.components.sensor import ( + DOMAIN as SENSOR_DOMAIN, + SensorDeviceClass, + SensorEntity, + SensorEntityDescription, +) from homeassistant.config_entries import ConfigEntry -from homeassistant.components.sensor import SensorEntityDescription, SensorDeviceClass, SensorEntity, DOMAIN as SENSOR_DOMAIN - -from .coordinator import victronEnergyDeviceUpdateCoordinator -from .base import VictronBaseEntityDescription -from .const import DOMAIN, register_info_dict, CONF_ADVANCED_OPTIONS, ReadEntityType, TextReadEntityType, BoolReadEntityType - from homeassistant.const import ( - PERCENTAGE, - UnitOfEnergy, - UnitOfPower, - UnitOfElectricPotential, + PERCENTAGE, UnitOfElectricCurrent, + UnitOfElectricPotential, + UnitOfEnergy, UnitOfFrequency, - UnitOfTime, + UnitOfPower, + UnitOfPressure, + UnitOfSpeed, UnitOfTemperature, + UnitOfTime, UnitOfVolume, - UnitOfSpeed, - UnitOfPressure ) +from homeassistant.core import HassJob, HomeAssistant, callback +from homeassistant.helpers import entity +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity -from collections.abc import Callable -from homeassistant.helpers.typing import StateType +from .base import VictronBaseEntityDescription +from .const import ( + CONF_ADVANCED_OPTIONS, + DOMAIN, + BoolReadEntityType, + ReadEntityType, + TextReadEntityType, + register_info_dict, +) +from .coordinator import victronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) + async def async_setup_entry( hass: HomeAssistant, config_entry: ConfigEntry, @@ -43,73 +49,86 @@ 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][config_entry.entry_id] + victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + config_entry.entry_id + ] _LOGGER.debug(victron_coordinator.processed_data()["register_set"]) _LOGGER.debug(victron_coordinator.processed_data()["data"]) descriptions = [] - #TODO cleanup + # 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(): - _LOGGER.debug("unit == " + str(slave) + " registerLedger == " + str(registerLedger) + " registerInfo ") + _LOGGER.debug( + "unit == " + + str(slave) + + " registerLedger == " + + str(registerLedger) + + " registerInfo " + ) if config_entry.options[CONF_ADVANCED_OPTIONS]: - if not isinstance(registerInfo.entityType, ReadEntityType) or isinstance(registerInfo.entityType, BoolReadEntityType): + if not isinstance( + registerInfo.entityType, ReadEntityType + ) or isinstance(registerInfo.entityType, BoolReadEntityType): continue - + description = VictronEntityDescription( key=register_name, - name=register_name.replace('_', ' '), + name=register_name.replace("_", " "), native_unit_of_measurement=registerInfo.unit, state_class=registerInfo.determine_stateclass(), slave=slave, - device_class=determine_victron_device_class(register_name, registerInfo.unit), - entity_type=registerInfo.entityType if isinstance(registerInfo.entityType, TextReadEntityType) else None + device_class=determine_victron_device_class( + register_name, registerInfo.unit + ), + entity_type=registerInfo.entityType + if isinstance(registerInfo.entityType, TextReadEntityType) + else None, ) _LOGGER.debug("composed description == " + str(description)) descriptions.append(description) - + entities = [] entity = {} for description in descriptions: entity = description - entities.append( - VictronSensor( - victron_coordinator, - entity - )) + entities.append(VictronSensor(victron_coordinator, entity)) # Add an entity for each sensor type async_add_entities(entities, True) + def determine_victron_device_class(name, unit): if unit == PERCENTAGE and "soc" in name: return SensorDeviceClass.BATTERY - elif unit == PERCENTAGE: - return None #Device classes aren't supported for voltage deviation and other % based entities that do not report SOC, moisture or humidity - elif unit in [member.value for member in UnitOfPower]: + 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 + if unit in [member.value for member in UnitOfPower]: return SensorDeviceClass.POWER - elif unit in [member.value for member in UnitOfEnergy]: + if unit in [member.value for member in UnitOfEnergy]: _LOGGER.debug("unit of energy") return SensorDeviceClass.ENERGY - elif unit == UnitOfFrequency.HERTZ: + if unit == UnitOfFrequency.HERTZ: return SensorDeviceClass.FREQUENCY - elif unit == UnitOfTime.SECONDS: + if unit == UnitOfTime.SECONDS: return SensorDeviceClass.DURATION - elif unit in [member.value for member in UnitOfTemperature]: - return SensorDeviceClass.TEMPERATURE - elif unit in [member.value for member in UnitOfVolume]: - return SensorDeviceClass.VOLUME_STORAGE # Perhaps change this to water if only water is measured in volume units - elif unit in [member.value for member in UnitOfSpeed]: + if unit in [member.value for member in UnitOfTemperature]: + return SensorDeviceClass.TEMPERATURE + if unit in [member.value for member in UnitOfVolume]: + return ( + 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: return SensorDeviceClass.WIND_SPEED return SensorDeviceClass.SPEED - elif unit in [member.value for member in UnitOfPressure]: + if unit in [member.value for member in UnitOfPressure]: return SensorDeviceClass.PRESSURE - elif unit == UnitOfElectricPotential.VOLT: + if unit == UnitOfElectricPotential.VOLT: return SensorDeviceClass.VOLTAGE - elif unit == UnitOfElectricCurrent.AMPERE: + if unit == UnitOfElectricCurrent.AMPERE: return SensorDeviceClass.CURRENT return None @@ -117,12 +136,18 @@ def determine_victron_device_class(name, unit): @dataclass class VictronEntityDescription(SensorEntityDescription, VictronBaseEntityDescription): """Describes victron sensor entity.""" + entity_type: ReadEntityType = None + class VictronSensor(CoordinatorEntity, SensorEntity): """Representation of a Victron energy sensor.""" - def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription) -> None: + def __init__( + self, + coordinator: victronEnergyDeviceUpdateCoordinator, + description: VictronEntityDescription, + ) -> None: """Initialize the sensor.""" self.description: VictronEntityDescription = description self._attr_device_class = description.device_class @@ -133,12 +158,12 @@ def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, descriptio self._attr_unique_id = f"{description.slave}_{self.description.key}" if description.slave not in (0, 100, 225): - self.entity_id = f"{SENSOR_DOMAIN}.{DOMAIN}_{self.description.key}_{description.slave}" + self.entity_id = ( + f"{SENSOR_DOMAIN}.{DOMAIN}_{self.description.key}_{description.slave}" + ) else: self.entity_id = f"{SENSOR_DOMAIN}.{DOMAIN}_{self.description.key}" - - self._update_job = HassJob(self.async_schedule_update_ha_state) self._unsub_update = None @@ -146,19 +171,32 @@ def __init__(self, coordinator: victronEnergyDeviceUpdateCoordinator, descriptio @callback def _handle_coordinator_update(self) -> None: - """Get the latest data and updates the states.""" + """Get the latest data and updates the states.""" try: if self.available: - data = self.description.value_fn(self.coordinator.processed_data(), self.description.slave, self.description.key) - if self.entity_type is not None and isinstance(self.entity_type, TextReadEntityType): - if data in set(item.value for item in self.entity_type.decodeEnum): - self._attr_native_value = self.entity_type.decodeEnum(data).name.split("_DUPLICATE")[0] + data = self.description.value_fn( + self.coordinator.processed_data(), + self.description.slave, + self.description.key, + ) + 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( + data + ).name.split("_DUPLICATE")[0] else: self._attr_native_value = "NONDECODABLE" - _LOGGER.error("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) + _LOGGER.error( + "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, + ) else: self._attr_native_value = data - + self.async_write_ha_state() except (TypeError, IndexError): _LOGGER.debug("failed to retrieve value") @@ -174,10 +212,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]) - }, - name=self.unique_id.split('_')[1], - model=self.unique_id.split('_')[0], - manufacturer="victron", # to be dynamically set for gavazzi and redflow + identifiers={(DOMAIN, self.unique_id.split("_")[0])}, + name=self.unique_id.split("_")[1], + model=self.unique_id.split("_")[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 8369e4b..a2cd59e 100644 --- a/custom_components/victron/switch.py +++ b/custom_components/victron/switch.py @@ -1,48 +1,58 @@ """Support for victron energy switches.""" -from __future__ import annotations -from typing import Any, cast +from __future__ import annotations from dataclasses import dataclass +import logging +from typing import Any, cast -from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription, DOMAIN as SWITCH_DOMAIN +from homeassistant.components.switch import ( + DOMAIN as SWITCH_DOMAIN, + SwitchEntity, + SwitchEntityDescription, +) from homeassistant.config_entries import ConfigEntry -from homeassistant.core import HomeAssistant, HassJob +from homeassistant.core import HassJob, HomeAssistant +from homeassistant.helpers import entity from homeassistant.helpers.entity_platform import AddEntitiesCallback - -from .coordinator import victronEnergyDeviceUpdateCoordinator from homeassistant.helpers.update_coordinator import CoordinatorEntity -from homeassistant.helpers import entity -from .const import DOMAIN, register_info_dict, SwitchWriteType, CONF_ADVANCED_OPTIONS from .base import VictronWriteBaseEntityDescription - -from collections.abc import Callable -from homeassistant.helpers.typing import StateType - -import logging +from .const import CONF_ADVANCED_OPTIONS, DOMAIN, SwitchWriteType, register_info_dict +from .coordinator import victronEnergyDeviceUpdateCoordinator _LOGGER = logging.getLogger(__name__) + async def async_setup_entry( - hass: HomeAssistant, config_entry: ConfigEntry, async_add_entities: AddEntitiesCallback + hass: HomeAssistant, + config_entry: ConfigEntry, + async_add_entities: AddEntitiesCallback, ) -> None: """Set up victron switch devices.""" - victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][config_entry.entry_id] + victron_coordinator: victronEnergyDeviceUpdateCoordinator = hass.data[DOMAIN][ + config_entry.entry_id + ] _LOGGER.debug("attempting to setup switch entities") descriptions = [] - #TODO cleanup + # 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(): - _LOGGER.debug("unit == " + str(slave) + " registerLedger == " + str(registerLedger) + " registerInfo ") + _LOGGER.debug( + "unit == " + + str(slave) + + " registerLedger == " + + str(registerLedger) + + " registerInfo " + ) if isinstance(registerInfo.entityType, SwitchWriteType): description = VictronEntityDescription( key=register_name, - name=register_name.replace('_', ' '), + name=register_name.replace("_", " "), slave=slave, address=registerInfo.register, ) @@ -53,25 +63,28 @@ async def async_setup_entry( entity = {} for description in descriptions: entity = description - entities.append( - VictronSwitch( - hass, - victron_coordinator, - entity - )) + entities.append(VictronSwitch(hass, victron_coordinator, entity)) _LOGGER.debug("adding switches") _LOGGER.debug(entities) async_add_entities(entities) @dataclass -class VictronEntityDescription(SwitchEntityDescription, VictronWriteBaseEntityDescription): +class VictronEntityDescription( + SwitchEntityDescription, VictronWriteBaseEntityDescription +): """Describes victron sensor entity.""" -class VictronSwitch(CoordinatorEntity, SwitchEntity): - """Representation of an Victron switch.""" - def __init__(self, hass: HomeAssistant, coordinator: victronEnergyDeviceUpdateCoordinator, description: VictronEntityDescription) -> None: +class VictronSwitch(CoordinatorEntity, SwitchEntity): + """Representation of a Victron switch.""" + + def __init__( + self, + hass: HomeAssistant, + coordinator: victronEnergyDeviceUpdateCoordinator, + description: VictronEntityDescription, + ) -> None: self.coordinator = coordinator self.description: VictronEntityDescription = description self._attr_name = f"{description.name}" @@ -79,7 +92,9 @@ def __init__(self, hass: HomeAssistant, coordinator: victronEnergyDeviceUpdateCo self._attr_unique_id = f"{description.slave}_{self.description.key}" if description.slave not in (100, 225): - self.entity_id = f"{SWITCH_DOMAIN}.{DOMAIN}_{self.description.key}_{description.slave}" + self.entity_id = ( + f"{SWITCH_DOMAIN}.{DOMAIN}_{self.description.key}_{description.slave}" + ) else: self.entity_id = f"{SWITCH_DOMAIN}.{DOMAIN}_{self.description.key}" @@ -87,20 +102,27 @@ def __init__(self, hass: HomeAssistant, coordinator: victronEnergyDeviceUpdateCo self._unsub_update = None super().__init__(coordinator) - async def async_turn_on(self, **kwargs: Any) -> None: """Turn on the device.""" - self.coordinator.write_register(unit=self.description.slave, address=self.description.address, value=1) + self.coordinator.write_register( + unit=self.description.slave, address=self.description.address, value=1 + ) await self.coordinator.async_update_local_entry(self.data_key, 1) async def async_turn_off(self, **kwargs: Any) -> None: """Turn off the device.""" - self.coordinator.write_register(unit=self.description.slave, address=self.description.address, value=0) + self.coordinator.write_register( + unit=self.description.slave, address=self.description.address, value=0 + ) await self.coordinator.async_update_local_entry(self.data_key, 0) @property def is_on(self) -> bool: - data = self.description.value_fn( self.coordinator.processed_data(), self.description.slave, self.description.key) + data = self.description.value_fn( + self.coordinator.processed_data(), + self.description.slave, + self.description.key, + ) """Return true if switch is on.""" return cast(bool, data) @@ -113,10 +135,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]) - }, - name=self.unique_id.split('_')[1], - model=self.unique_id.split('_')[0], + identifiers={(DOMAIN, self.unique_id.split("_")[0])}, + name=self.unique_id.split("_")[1], + model=self.unique_id.split("_")[0], manufacturer="victron", - ) \ No newline at end of file + )