From e5bced4a82cbbe393b197d46a36c331a7b916f6a Mon Sep 17 00:00:00 2001 From: David Rapan Date: Wed, 10 Jul 2024 19:50:23 +0200 Subject: [PATCH 01/39] fix: documentation and issue_tracker links --- custom_components/solarman/manifest.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/custom_components/solarman/manifest.json b/custom_components/solarman/manifest.json index 8ae60e1..65f2092 100644 --- a/custom_components/solarman/manifest.json +++ b/custom_components/solarman/manifest.json @@ -4,10 +4,10 @@ "codeowners": ["@davidrapan"], "config_flow": true, "dependencies": ["network", "dhcp"], - "documentation": "https://github.com/davidrapan/ha_solarman/", + "documentation": "https://github.com/davidrapan/ha-solarman/", "integration_type": "device", "iot_class": "local_polling", - "issue_tracker": "https://github.com/davidrapan/ha_solarman/issues", + "issue_tracker": "https://github.com/davidrapan/ha-solarman/issues", "requirements": ["ipaddress","pyyaml","pysolarmanv5>=3.0.2"], "version": "24.07.04" } From 1a4a063273da22486344489f942420416f1526d9 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 11 Jul 2024 00:45:17 +0200 Subject: [PATCH 02/39] feat: readme.md - added Miscellaneous --- custom_components/solarman/manifest.json | 2 +- readme.md | 25 +++++++++++++++++++++++- 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/custom_components/solarman/manifest.json b/custom_components/solarman/manifest.json index 65f2092..21f0126 100644 --- a/custom_components/solarman/manifest.json +++ b/custom_components/solarman/manifest.json @@ -4,7 +4,7 @@ "codeowners": ["@davidrapan"], "config_flow": true, "dependencies": ["network", "dhcp"], - "documentation": "https://github.com/davidrapan/ha-solarman/", + "documentation": "https://github.com/davidrapan/ha-solarman", "integration_type": "device", "iot_class": "local_polling", "issue_tracker": "https://github.com/davidrapan/ha-solarman/issues", diff --git a/readme.md b/readme.md index 8765eb7..9076af2 100644 --- a/readme.md +++ b/readme.md @@ -24,7 +24,7 @@ Integration for Solarman Stick Logger > Is note worthy that some names of the SG04LP3 sensors did change for different reasons (some were due to aestetics, etc.) > So look through the file and change them as you see fit manually before I'll make it available from the HA configuration. > -> One more thing.. It's not possible to use this integration side by side (with the same device) with the implementation from Stephen! It will override it. +> One more thing.. It's not possible to use this integration side by side (with the same device) with the implementation from Stephan! It will override it. > [!NOTE] > It's still work in progress but I'm now over 3 weeks of uptime so it's really stable ;) @@ -36,6 +36,29 @@ Integration for Solarman Stick Logger > [!WARNING] > TODO: Rest of the info :-D +## Miscellaneous + +Some might wonder why Energy Dashboard shows different(higher) Load Consumption than sensor like for example "Today(Daily) Load Consumption. And it's because the Energy Dashboard does it's own calculations by summing up Imported(Bought) and Produced energy which also includes consumption of the inverter itself + some AC/DC losses along the way." + +_So for those curious enough here is some insight..._ + +#### Inverter power losses calculation [W]: +``` +Power losses = Battery Power + PV1 Power + PV2 Power - Inverter Power +``` + +#### Total losses calculation [kWh]: +``` +Total losses = Total Energy Imported(Bought) + Total Production + Total Battery Discharge - Total Energy Exported(Sold) - Total Battery Charge - Total Load Consumption +``` + +#### Today(Daily) losses calculation [kWh]: +``` +Today(Daily) losses = Today(Daily) Energy Imported(Bought) + Today(Daily) Production + Today(Daily) Battery Discharge - Today(Daily) Energy Exported(Sold) - Today(Daily) Battery Charge - Today(Daily) Load Consumption +``` + +_To get value which is in Energy Dashboard as "Home Consumption" remove subtraction of Load Consumption from the above._ + ## Diagnostics I was using during the development also this sensor bundle: From 90c9401bbe168364999119c44dfb0b766f89142a Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 16:00:08 +0200 Subject: [PATCH 03/39] fix/feat: Register reading/parsing and timings... Due to security reasons: - Temporarily removed some custom sensor *templating (Battery State, Battery SOH..) - Reworked some simple custom sensors like additions and subtracting to work directly with registers (PV Power, Power losses, Total Losses and Today Losses..) Extended signed integer reading: - Added Solarman Smart Meter profile Updated some inverter profiles according to the changes, etc. Asynchronous file open using aiofiles Asynchronous directory listing using asyncio Sorting inverter profiles Discovery attempts from global value --- custom_components/solarman/api.py | 91 +- custom_components/solarman/common.py | 6 + custom_components/solarman/config_flow.py | 13 +- custom_components/solarman/const.py | 27 +- custom_components/solarman/coordinator.py | 4 +- custom_components/solarman/discovery.py | 9 +- .../afore_BNTxxxKTL-2mppt.yaml | 10 +- .../inverter_definitions/deye_2mppt.yaml | 758 ++++---- .../inverter_definitions/deye_4mppt.yaml | 495 ++--- .../inverter_definitions/deye_hybrid.yaml | 1639 +++++++++-------- .../inverter_definitions/deye_sg01hp3.yaml | 103 +- .../inverter_definitions/deye_sg04lp3.yaml | 124 ++ .../deye_sun-12k-sg04lp3.yaml | 139 +- .../solarman_dtsd422-d3.yaml | 456 +++++ custom_components/solarman/parser.py | 193 +- custom_components/solarman/sensor.py | 188 +- custom_components/solarman/services.py | 6 +- 17 files changed, 2506 insertions(+), 1755 deletions(-) create mode 100644 custom_components/solarman/inverter_definitions/solarman_dtsd422-d3.yaml diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index 63827e1..e7d8fc3 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -1,7 +1,7 @@ -import socket import time import yaml import struct +import socket import logging import asyncio import aiofiles @@ -18,16 +18,11 @@ _LOGGER = logging.getLogger(__name__) -def read_file(filepath): - with open(filepath) as file: - return file.read() - class InverterApi(PySolarmanV5Async): def __init__(self, address, serial, port, mb_slave_id): - super().__init__(address, serial, port = port, mb_slave_id = mb_slave_id, logger = _LOGGER, auto_reconnect = True, socket_timeout = COORDINATOR_TIMEOUT) - self._last_frame: bytes = b"" - self.status = -1 + super().__init__(address, serial, port = port, mb_slave_id = mb_slave_id, logger = _LOGGER, auto_reconnect = True, socket_timeout = TIMINGS_SOCKET_TIMEOUT) self.status_lastUpdate = "N/A" + self.status = -1 def is_connecting(self): return self.status == 0 @@ -53,7 +48,7 @@ async def reconnect(self) -> None: self.writer.write(self._last_frame) await self.writer.drain() except Exception as e: - self.log.exception(format_exception(e)) + self.log.exception(f"Cannot open connection to {self.address}. [{format_exception(e)}]") async def _send_receive_v5_frame(self, data_logging_stick_frame): """ @@ -70,14 +65,14 @@ async def _send_receive_v5_frame(self, data_logging_stick_frame): v5_response = await asyncio.wait_for(self.data_queue.get(), self.socket_timeout) if v5_response == b"": raise NoSocketAvailableError("Connection closed on read. Retry if auto-reconnect is enabled") - except AttributeError as exc: - raise NoSocketAvailableError("Connection already closed") from exc + except AttributeError as e: + raise NoSocketAvailableError("Connection already closed") from e except NoSocketAvailableError: raise except TimeoutError: raise - except Exception as exc: - self.log.exception("[%s] Send/Receive error: %s", self.serial, exc) + except Exception as e: + self.log.exception("[%s] Send/Receive error: %s", self.serial, e) raise finally: self.data_wanted_ev.clear() @@ -88,11 +83,10 @@ async def _send_receive_v5_frame(self, data_logging_stick_frame): async def async_connect(self) -> None: if self.reader_task: _LOGGER.debug(f"Reader Task done: {self.reader_task.done()}, cancelled: {self.reader_task.cancelled()}.") - #if not self.reader_task or self.reader_task.done() or self.reader_task.cancelled(): - if not self.reader_task: + if not self.reader_task: #if not self.reader_task or self.reader_task.done() or self.reader_task.cancelled(): _LOGGER.info(f"Connecting to {self.address}:{self.port}") await self.connect() - elif not self.is_connected(): + elif not self.status > 0: await self.reconnect() async def async_disconnect(self, loud = True) -> None: @@ -112,14 +106,11 @@ async def async_disconnect(self, loud = True) -> None: self.writer.close() await self.writer.wait_closed() - async def async_reconnect(self) -> None: - await self.async_disconnect(False) - loop = asyncio.get_running_loop() - loop.create_task(self.reconnect()) - - async def _read_registers(self, code, params, start, end) -> None: + async def async_read(self, params, code, start, end) -> None: length = end - start + 1 + await self.async_connect() + match code: case 3: response = await self.read_holding_registers(register_addr = start, quantity = length) @@ -128,24 +119,17 @@ async def _read_registers(self, code, params, start, end) -> None: params.parse(response, start, length) - async def async_read(self, code, params, start, end) -> None: - await self.async_connect() - await self._read_registers(code, params, start, end) - class Inverter(InverterApi): - def __init__(self, address, mac, serial, port, mb_slave_id, lookup_path, lookup_file): + def __init__(self, address, serial, port, mb_slave_id, name, mac, lookup_path, lookup_file): super().__init__(address, serial, port, mb_slave_id) + self.name = name self.mac = mac self.lookup_path = lookup_path self.lookup_file = lookup_file if lookup_file and not lookup_file == "parameters.yaml" else "deye_hybrid.yaml" - async def async_load(self): - loop = asyncio.get_running_loop() - self.parameter_definition = await loop.run_in_executor(None, lambda: yaml.safe_load(read_file(self.path + self.lookup_file))) - async def get_sensors(self): async with aiofiles.open(self.lookup_path + self.lookup_file) as f: - self.parameter_definition = await f.read() + self.parameter_definition = yaml.safe_load(await f.read()) if self.parameter_definition: params = ParameterParser(self.parameter_definition) return params.get_sensors() @@ -162,9 +146,7 @@ def get_result(self, middleware = None): self.status_lastUpdate = datetime.now().strftime("%m/%d/%Y, %H:%M:%S") self.status = 1 - result = middleware.get_result() if middleware else {} - result["Connection Status"] = self.get_connection_status() - return result + return middleware.get_result() if middleware else {} async def async_get_failed(self, message): _LOGGER.debug(f"Request failed. [Previous Status: {self.get_connection_status()}]") @@ -181,30 +163,30 @@ async def async_get(self, runtime = 0): requests_count = len(requests) result = 0 - _LOGGER.debug(f"Scheduling {requests_count} query requests. #{runtime}") + _LOGGER.debug(f"Scheduling {requests_count} query requests. #{runtime}") try: for request in requests: - code = request['mb_functioncode'] - start = request['start'] - end = request['end'] + code = request["mb_functioncode"] + start = request["start"] + end = request["end"] _LOGGER.debug(f"Querying ({start} - {end}) ...") - attempts_left = COORDINATOR_QUERY_RETRY_ATTEMPTS + attempts_left = ACTION_RETRY_ATTEMPTS while attempts_left > 0: attempts_left -= 1 try: - await self.async_read(code, params, start, end) + await self.async_read(params, code, start, end) result = 1 except (V5FrameError, TimeoutError, Exception) as e: result = 0 - if not isinstance(e, TimeoutError) or not attempts_left > 0 or _LOGGER.isEnabledFor(logging.DEBUG): + if not isinstance(e, TimeoutError) or not attempts_left >= 1 or _LOGGER.isEnabledFor(logging.DEBUG): _LOGGER.warning(f"Querying ({start} - {end}) failed. #{runtime} [{format_exception(e)}]") - await asyncio.sleep(COORDINATOR_ERROR_SLEEP) + await asyncio.sleep(TIMINGS_QUERY_EXCEPT_SLEEP) _LOGGER.debug(f"Querying {'succeeded.' if result == 1 else f'attempts left: {attempts_left}{'' if attempts_left > 0 else ', aborting.'}'}") @@ -222,27 +204,28 @@ async def async_get(self, runtime = 0): except UpdateFailed: raise except Exception as e: - await self.async_get_failed(f"Querying {self.serial} at {self.address}:{self.port} failed during connection start. [{format_exception(e)}]") + await self.async_get_failed(f"Querying {self.serial} at {self.address}:{self.port} failed. [{format_exception(e)}]") return self.get_result() -# Service calls - async def service_write_holding_register(self, register, value): - _LOGGER.debug(f'Service Call: write_holding_register : [{register}], value : [{value}]') + async def service_write_holding_register(self, register, value) -> bool: + _LOGGER.debug(f"service_write_holding_register: {register}, value: {value}") try: await self.async_connect() await self.write_holding_register(register, value) except Exception as e: - _LOGGER.warning(f"Service Call: write_holding_register : [{register}], value : [{value}] failed. [{format_exception(e)}]") + _LOGGER.warning(f"service_write_holding_register: {register}, value: {value} failed. [{format_exception(e)}]") await self.async_disconnect() - return + return False + return True - async def service_write_multiple_holding_registers(self, register, values): - _LOGGER.debug(f'Service Call: write_multiple_holding_registers: [{register}], values : [{values}]') + async def service_write_multiple_holding_registers(self, registers, values) -> bool: + _LOGGER.debug(f"service_write_multiple_holding_registers: {registers}, values: {values}") try: await self.async_connect() - await self.write_multiple_holding_registers(register, values) + await self.write_multiple_holding_registers(registers, values) except Exception as e: - _LOGGER.warning(f"Service Call: write_multiple_holding_registers: [{register}], values : [{values}] failed. [{format_exception(e)}]") + _LOGGER.warning(f"service_write_multiple_holding_registers: {registers}, values: {values} failed. [{format_exception(e)}]") await self.async_disconnect() - return + return False + return True diff --git a/custom_components/solarman/common.py b/custom_components/solarman/common.py index 1d3dd49..8c71d1b 100644 --- a/custom_components/solarman/common.py +++ b/custom_components/solarman/common.py @@ -1,3 +1,9 @@ +import asyncio + +async def async_execute(x): + loop = asyncio.get_running_loop() + return await loop.run_in_executor(None, x) + def group_when(iterable, predicate): i, x, size = 0, 0, len(iterable) while i < size - 1: diff --git a/custom_components/solarman/config_flow.py b/custom_components/solarman/config_flow.py index a2fe960..c2f8585 100644 --- a/custom_components/solarman/config_flow.py +++ b/custom_components/solarman/config_flow.py @@ -17,6 +17,7 @@ from homeassistant.exceptions import HomeAssistantError from .const import * +from .common import * from .discovery import InverterDiscovery _LOGGER = logging.getLogger(__name__) @@ -31,8 +32,8 @@ async def step_user_data_process(discovery): _LOGGER.debug(f"step_user_data_process: discovery: {discovery}") return { CONF_NAME: DEFAULT_NAME, CONF_INVERTER_DISCOVERY: DEFAULT_DISCOVERY, CONF_INVERTER_HOST: await discovery.get_ip(), CONF_INVERTER_SERIAL: await discovery.get_serial(), CONF_INVERTER_PORT: DEFAULT_PORT_INVERTER, CONF_INVERTER_MB_SLAVE_ID: DEFAULT_INVERTER_MB_SLAVE_ID, CONF_LOOKUP_FILE: DEFAULT_LOOKUP_FILE, CONF_BATTERY_NOMINAL_VOLTAGE: DEFAULT_BATTERY_NOMINAL_VOLTAGE, CONF_BATTERY_LIFE_CYCLE_RATING: DEFAULT_BATTERY_LIFE_CYCLE_RATING, CONF_DISABLE_TEMPLATING: DEFAULT_DISABLE_TEMPLATING } -def step_user_data_schema(hass: HomeAssistant, data: dict[str, Any] = { CONF_NAME: DEFAULT_NAME, CONF_INVERTER_DISCOVERY: DEFAULT_DISCOVERY, CONF_INVERTER_PORT: DEFAULT_PORT_INVERTER, CONF_INVERTER_MB_SLAVE_ID: DEFAULT_INVERTER_MB_SLAVE_ID, CONF_LOOKUP_FILE: DEFAULT_LOOKUP_FILE, CONF_BATTERY_NOMINAL_VOLTAGE: DEFAULT_BATTERY_NOMINAL_VOLTAGE, CONF_BATTERY_LIFE_CYCLE_RATING: DEFAULT_BATTERY_LIFE_CYCLE_RATING, CONF_DISABLE_TEMPLATING: DEFAULT_DISABLE_TEMPLATING }) -> Schema: - lookup_files = [f for f in os.listdir(hass.config.path(LOOKUP_DIRECTORY_PATH)) if os.path.isfile(LOOKUP_DIRECTORY_PATH + f)] +async def step_user_data_schema(hass: HomeAssistant, data: dict[str, Any] = { CONF_NAME: DEFAULT_NAME, CONF_INVERTER_DISCOVERY: DEFAULT_DISCOVERY, CONF_INVERTER_PORT: DEFAULT_PORT_INVERTER, CONF_INVERTER_MB_SLAVE_ID: DEFAULT_INVERTER_MB_SLAVE_ID, CONF_LOOKUP_FILE: DEFAULT_LOOKUP_FILE, CONF_BATTERY_NOMINAL_VOLTAGE: DEFAULT_BATTERY_NOMINAL_VOLTAGE, CONF_BATTERY_LIFE_CYCLE_RATING: DEFAULT_BATTERY_LIFE_CYCLE_RATING, CONF_DISABLE_TEMPLATING: DEFAULT_DISABLE_TEMPLATING }) -> Schema: + lookup_files = sorted([f for f in await async_execute(lambda: os.listdir(hass.config.path(LOOKUP_DIRECTORY_PATH))) if os.path.isfile(LOOKUP_DIRECTORY_PATH + f)]) _LOGGER.debug(f"step_user_data_schema: data: {data}, {LOOKUP_DIRECTORY_PATH}: {lookup_files}") STEP_USER_DATA_SCHEMA = vol.Schema( { @@ -90,7 +91,7 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Con _LOGGER.debug(f"ConfigFlowHandler.async_step_user: {user_input}") if user_input is None: discovery_options = await step_user_data_process(InverterDiscovery(self.hass)) - return self.async_show_form(step_id = "user", data_schema = step_user_data_schema(self.hass, discovery_options)) + return self.async_show_form(step_id = "user", data_schema = await step_user_data_schema(self.hass, discovery_options)) errors = {} @@ -112,7 +113,7 @@ async def async_step_user(self, user_input: dict[str, Any] | None = None) -> Con _LOGGER.debug(f"ConfigFlowHandler.async_step_user: validation failed: {user_input}") - return self.async_show_form(step_id = "user", data_schema = step_user_data_schema(self.hass, user_input), errors = errors) + return self.async_show_form(step_id = "user", data_schema = await step_user_data_schema(self.hass, user_input), errors = errors) @staticmethod @callback @@ -133,7 +134,7 @@ async def async_step_init(self, user_input: dict[str, Any] | None = None) -> Con """Handle options flow.""" _LOGGER.debug(f"OptionsFlowHandler.async_step_init: {user_input}") if user_input is None: - return self.async_show_form(step_id = "init", data_schema = step_user_data_schema(self.hass, self.entry.options)) + return self.async_show_form(step_id = "init", data_schema = await step_user_data_schema(self.hass, self.entry.options)) errors = {} @@ -149,7 +150,7 @@ async def async_step_init(self, user_input: dict[str, Any] | None = None) -> Con else: return self.async_create_entry(title = info["title"], data = user_input) - return self.async_show_form(step_id = "init", data_schema = step_user_data_schema(self.hass, user_input), errors = errors) + return self.async_show_form(step_id = "init", data_schema = await step_user_data_schema(self.hass, user_input), errors = errors) class InvalidHost(HomeAssistantError): """Error to indicate there is invalid hostname or IP address.""" diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index 50ec447..9186070 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -4,12 +4,14 @@ PLATFORMS: list[str] = ["sensor"] SENSOR_PREFIX = "Solarman" -DISCOVERY_MESSAGE = "WIFIKIT-214028-READ" DISCOVERY_PORT = 48899 +DISCOVERY_MESSAGE = "WIFIKIT-214028-READ" DISCOVERY_RECV_MESSAGE_SIZE = 1024 +COMPONENTS_DIRECTORY = "custom_components" + LOOKUP_DIRECTORY = "inverter_definitions" -LOOKUP_DIRECTORY_PATH = f"custom_components/{DOMAIN}/{LOOKUP_DIRECTORY}/" +LOOKUP_DIRECTORY_PATH = f"{COMPONENTS_DIRECTORY}/{DOMAIN}/{LOOKUP_DIRECTORY}/" CONF_INVERTER_DISCOVERY = "inverter_discovery" CONF_INVERTER_HOST = "inverter_host" @@ -25,21 +27,18 @@ DEFAULT_DISCOVERY = True DEFAULT_PORT_INVERTER = 8899 DEFAULT_INVERTER_MB_SLAVE_ID = 1 -DEFAULT_LOOKUP_FILE = "deye_sg04lp3.yaml" +DEFAULT_LOOKUP_FILE = "deye_hybrid.yaml" DEFAULT_BATTERY_NOMINAL_VOLTAGE = 48 DEFAULT_BATTERY_LIFE_CYCLE_RATING = 6000 DEFAULT_DISABLE_TEMPLATING = False -COORDINATOR_INTERVAL = 5 -COORDINATOR_INTERVAL_DEFAULT = 60 -COORDINATOR_UPDATE_INTERVAL = td(seconds = COORDINATOR_INTERVAL) -COORDINATOR_TIMEOUT = 15 -COORDINATOR_TIMEOUT2 = 30 -COORDINATOR_ERROR_SLEEP = 4 +ACTION_RETRY_ATTEMPTS = 5 -COORDINATOR_SOCKET_TIMEOUT = 30 / 2 -COORDINATOR_QUERY_INTERVAL_DEFAULT = 60 -COORDINATOR_QUERY_RETRY_ATTEMPTS = 4 -COORDINATOR_QUERY_ERROR_SLEEP = 4 +TIMINGS_INTERVAL = 5 +TIMINGS_COORDINATOR = td(seconds = TIMINGS_INTERVAL) +TIMINGS_COORDINATOR_TIMEOUT = TIMINGS_INTERVAL * 6 +TIMINGS_SOCKET_TIMEOUT = TIMINGS_INTERVAL * 3 - 1 +TIMINGS_QUERY_INTERVAL_DEFAULT = 60 +TIMINGS_QUERY_EXCEPT_SLEEP = 4 -FLOAT_ROUND_TO = 6 \ No newline at end of file +DIGITS_DEFAULT = 6 \ No newline at end of file diff --git a/custom_components/solarman/coordinator.py b/custom_components/solarman/coordinator.py index 22a3928..68f8fbd 100644 --- a/custom_components/solarman/coordinator.py +++ b/custom_components/solarman/coordinator.py @@ -14,7 +14,7 @@ class InverterCoordinator(DataUpdateCoordinator[dict[str, Any]]): def __init__(self, hass: HomeAssistant, inverter): - super().__init__(hass, _LOGGER, name = SENSOR_PREFIX, update_interval = COORDINATOR_UPDATE_INTERVAL, always_update = False) + super().__init__(hass, _LOGGER, name = SENSOR_PREFIX, update_interval = TIMINGS_COORDINATOR, always_update = False) self.inverter = inverter self.counter = -1 @@ -29,7 +29,7 @@ def _accounting(self): return int(self.counter * self._update_interval_seconds) async def _async_update_data(self) -> dict[str, Any]: - async with asyncio.timeout(COORDINATOR_TIMEOUT2): + async with asyncio.timeout(TIMINGS_COORDINATOR_TIMEOUT): return await self.inverter.async_get(self._accounting()) #async def _reload(self): diff --git a/custom_components/solarman/discovery.py b/custom_components/solarman/discovery.py index 79febcf..3c92d41 100644 --- a/custom_components/solarman/discovery.py +++ b/custom_components/solarman/discovery.py @@ -15,6 +15,7 @@ _LOGGER = logging.getLogger(__name__) class InverterDiscovery: + _port = DISCOVERY_PORT _message = DISCOVERY_MESSAGE.encode() def __init__(self, hass: HomeAssistant, address = None): @@ -24,7 +25,7 @@ def __init__(self, hass: HomeAssistant, address = None): self._mac = None self._serial = None - async def _discover(self, address = ""): + async def _discover(self, address = "", source = "0.0.0.0"): loop = asyncio.get_running_loop() try: @@ -33,8 +34,9 @@ async def _discover(self, address = ""): sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.setblocking(False) sock.settimeout(1.0) + #sock.bind((source, 0)) - await loop.sock_sendto(sock, self._message, (address, DISCOVERY_PORT)) + await loop.sock_sendto(sock, self._message, (address, self._port)) while True: try: @@ -62,6 +64,7 @@ async def _discover_all(self): _LOGGER.debug(f"_discover_all: Broadcasting on {net.with_prefixlen}") await self._discover(str(IPv4Network(net, False).broadcast_address)) + #await self._discover("", ipv4["address"]) if self._ip is not None: return None @@ -70,7 +73,7 @@ async def discover(self): if self._address: await self._discover(self._address) - attempts_left = COORDINATOR_QUERY_RETRY_ATTEMPTS + attempts_left = ACTION_RETRY_ATTEMPTS while self._ip is None and attempts_left > 0: attempts_left -= 1 diff --git a/custom_components/solarman/inverter_definitions/afore_BNTxxxKTL-2mppt.yaml b/custom_components/solarman/inverter_definitions/afore_BNTxxxKTL-2mppt.yaml index 627761f..1589d74 100644 --- a/custom_components/solarman/inverter_definitions/afore_BNTxxxKTL-2mppt.yaml +++ b/custom_components/solarman/inverter_definitions/afore_BNTxxxKTL-2mppt.yaml @@ -1,5 +1,9 @@ # To use modbus function in Afore BNTxxxKTL inverters, You first need to change protocol from RS485 to MODBUS in inverter menu +default: + update_interval: 60 + digits: 6 + requests: - start: 0x0000 end: 0x001A @@ -8,7 +12,7 @@ requests: - start: 0x0000 end: 0x000F mb_functioncode: 0x03 - + parameters: - group: solar items: @@ -165,6 +169,6 @@ parameters: uom: "°C" scale: 0.1 rule: 1 - + registers: [0x000D] - icon: "mdi:thermometer" \ No newline at end of file + icon: "mdi:thermometer" diff --git a/custom_components/solarman/inverter_definitions/deye_2mppt.yaml b/custom_components/solarman/inverter_definitions/deye_2mppt.yaml index afa5980..5b67fe2 100644 --- a/custom_components/solarman/inverter_definitions/deye_2mppt.yaml +++ b/custom_components/solarman/inverter_definitions/deye_2mppt.yaml @@ -2,393 +2,397 @@ # Latest update: 08.09.2023 # Microinverter SUN600G3 (DEYE/VESDAS) # 2x MPPT, 2x inverter -# 1x Logger, 2x Module, +# 1x Logger, 2x Module, + +default: + update_interval: 60 + digits: 6 requests: - start: 0x0001 - end: 0x007D + end: 0x007D mb_functioncode: 0x03 parameters: - group: solar - items: - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x006D] - icon: 'mdi:solar-power' - - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x006F] - icon: 'mdi:solar-power' - - - name: "PV1 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x006E] - icon: 'mdi:solar-power' - - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x0070] - icon: 'mdi:solar-power' - - - name: "Daily Production" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x003C] - icon: 'mdi:solar-power' - - - name: "Daily Production 1" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x0041] - icon: 'mdi:solar-power' - - - name: "Daily Production 2" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x0042] - icon: 'mdi:solar-power' - - - name: "Total Production" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x003F,0x0040] - icon: 'mdi:solar-power' - validation: - min: 0.1 - - - name: "Total Production 1" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x0045] - icon: 'mdi:solar-power' - - - name: "Total Production 2" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x0047] - icon: 'mdi:solar-power' - - - name: "Active Power Regulations" - class: "" - state_class: "" - uom: "%" - scale: 1 - rule: 1 - registers: [0x0028] - icon: 'mdi:solar-power' + items: + - name: "PV1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x006D] + icon: "mdi:solar-power" + + - name: "PV2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x006F] + icon: "mdi:solar-power" + + - name: "PV1 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x006E] + icon: "mdi:solar-power" + + - name: "PV2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x0070] + icon: "mdi:solar-power" + + - name: "Daily Production" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x003C] + icon: "mdi:solar-power" + + - name: "Daily Production 1" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x0041] + icon: "mdi:solar-power" + + - name: "Daily Production 2" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x0042] + icon: "mdi:solar-power" + + - name: "Total Production" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x003F, 0x0040] + icon: "mdi:solar-power" + validation: + min: 0.1 + + - name: "Total Production 1" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x0045] + icon: "mdi:solar-power" + + - name: "Total Production 2" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x0047] + icon: "mdi:solar-power" + + - name: "Active Power Regulations" + class: "" + state_class: "" + uom: "%" + scale: 1 + rule: 1 + registers: [0x0028] + icon: "mdi:solar-power" - group: Grid items: - - name: "AC Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0049] - icon: 'mdi:transmission-tower' - - - name: "Grid Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 2 - registers: [0x004C] - icon: 'mdi:home-lightning-bolt' - - - name: "AC Output Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x004F] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid Voltage Upp Limit" - class: "voltage" - state_class: "" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x001B] - icon: 'mdi:transmission-tower' - - - name: "Grid Voltage Lower Limit" - class: "voltage" - state_class: "" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x001C] - icon: 'mdi:transmission-tower' - - - name: "Grid Frequency Upper Limit" - class: "frequency" - state_class: "" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x001D] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid Frequency Lower Limit" - class: "frequency" - state_class: "" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x001E] - icon: 'mdi:home-lightning-bolt' - - - name: "Overfrequency And Load Reduction Starting Point" - class: "frequency" - state_class: "" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x0022] - icon: 'mdi:home-lightning-bolt' - - - name: "Overfrequency And Load Reduction Percentage" - class: "" - state_class: "" - uom: "%" - scale: 1 - rule: 1 - registers: [0x0023] - icon: '' - - - name: "ON-OFF Enable" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x002B] - isstr: true - lookup: - - key: 0 - value: "OFF" - - key: 1 - value: "ON" - icon: 'mdi:toggle-switch' - - - name: "Island Protection Enable" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x002E] - isstr: true - lookup: - - key: 0 - value: "Disabled" - - key: 1 - value: "Enabled" - icon: 'mdi:island' - - - name: "Overfrequency&Load-shedding Enable" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0031] - isstr: true - lookup: - - key: 0 - value: "Disabled" - - key: 1 - value: "Enabled" - icon: 'mdi:toggle-switch' + - name: "AC Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0049] + icon: "mdi:transmission-tower" + + - name: "Grid Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 2 + registers: [0x004C] + icon: "mdi:home-lightning-bolt" + + - name: "AC Output Frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x004F] + icon: "mdi:home-lightning-bolt" + + - name: "Grid Voltage Upp Limit" + class: "voltage" + state_class: "" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x001B] + icon: "mdi:transmission-tower" + + - name: "Grid Voltage Lower Limit" + class: "voltage" + state_class: "" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x001C] + icon: "mdi:transmission-tower" + + - name: "Grid Frequency Upper Limit" + class: "frequency" + state_class: "" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x001D] + icon: "mdi:home-lightning-bolt" + + - name: "Grid Frequency Lower Limit" + class: "frequency" + state_class: "" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x001E] + icon: "mdi:home-lightning-bolt" + + - name: "Overfrequency And Load Reduction Starting Point" + class: "frequency" + state_class: "" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x0022] + icon: "mdi:home-lightning-bolt" + + - name: "Overfrequency And Load Reduction Percentage" + class: "" + state_class: "" + uom: "%" + scale: 1 + rule: 1 + registers: [0x0023] + icon: "" + + - name: "ON-OFF Enable" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x002B] + isstr: true + lookup: + - key: 0 + value: "OFF" + - key: 1 + value: "ON" + icon: "mdi:toggle-switch" + + - name: "Island Protection Enable" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x002E] + isstr: true + lookup: + - key: 0 + value: "Disabled" + - key: 1 + value: "Enabled" + icon: "mdi:island" + + - name: "Overfrequency&Load-shedding Enable" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0031] + isstr: true + lookup: + - key: 0 + value: "Disabled" + - key: 1 + value: "Enabled" + icon: "mdi:toggle-switch" - group: Inverter items: - - name: "Running Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x003B] - isstr: true - lookup: - - key: 0 - value: "Stand-by" - - key: 1 - value: "Self-check" - - key: 2 - value: "Normal" - - key: 3 - value: "Warning" - - key: 4 - value: "Fault" - icon: 'mdi:home-lightning-bolt' - - - name: "Total AC Output Power (Active)" - class: "power" - state_class: "measurement" - uom: "W" - scale: 0.1 - rule: 3 - registers: [0x0056, 0x0057] - icon: 'mdi:home-lightning-bolt' - - - name: "Radiator Temperature" - class: "temperature" - uom: "°C" - state_class: "measurement" - scale: 0.01 - rule: 1 - offset: 1000 - registers: [0x005a] - - - name: "Inverter ID" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 5 - registers: [0x0003,0x0004,0x0005,0x0006,0x0007] - isstr: true - - - name: "Hardware Version" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 7 - registers: [0x000C] - isstr: true - - - name: "DC Master Firmware Version" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 7 - registers: [0x000D] - isstr: true - - - name: "AC Version. Number" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 7 - registers: [0x000E] - isstr: true - - - name: "Rated Power" - class: "energy" - state_class: "" - uom: "W" - scale: 0.1 - rule: 1 - registers: [0x0010] - icon: 'mdi:solar-power' - - - name: "Communication Protocol Version" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 7 - registers: [0x0012] - isstr: true - - - name: "Start-up Self-checking Time " - class: "" - state_class: "" - uom: "s" - scale: 1 - rule: 1 - registers: [0x0015] - icon: 'mdi:solar-power' - - - name: "Update Time" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 8 - registers: [0x0016,0x0017,0x0018] - isstr: true - - - name: "Soft Start Enable" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x002F] - isstr: true - lookup: - - key: 0 - value: "Disabled" - - key: 1 - value: "Enabled" - icon: 'mdi:toggle-switch' - - - name: "Power Factor Regulation" - class: "" - state_class: "" - uom: "" - scale: 0.1 - rule: 2 - registers: [0x0032] - icon: '' - - - name: "Restore Factory Settings" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0036] - isstr: true - lookup: - - key: 0 - value: "Disabled" - - key: 1 - value: "Enabled" - icon: 'mdi:factory' + - name: "Running Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x003B] + isstr: true + lookup: + - key: 0 + value: "Stand-by" + - key: 1 + value: "Self-check" + - key: 2 + value: "Normal" + - key: 3 + value: "Warning" + - key: 4 + value: "Fault" + icon: "mdi:home-lightning-bolt" + + - name: "Total AC Output Power (Active)" + class: "power" + state_class: "measurement" + uom: "W" + scale: 0.1 + rule: 3 + registers: [0x0056, 0x0057] + icon: "mdi:home-lightning-bolt" + + - name: "Radiator Temperature" + class: "temperature" + uom: "°C" + state_class: "measurement" + scale: 0.01 + rule: 1 + offset: 1000 + registers: [0x005a] + + - name: "Inverter ID" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 5 + registers: [0x0003, 0x0004, 0x0005, 0x0006, 0x0007] + isstr: true + + - name: "Hardware Version" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 7 + registers: [0x000C] + isstr: true + + - name: "DC Master Firmware Version" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 7 + registers: [0x000D] + isstr: true + + - name: "AC Version. Number" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 7 + registers: [0x000E] + isstr: true + + - name: "Rated Power" + class: "energy" + state_class: "" + uom: "W" + scale: 0.1 + rule: 1 + registers: [0x0010] + icon: "mdi:solar-power" + + - name: "Communication Protocol Version" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 7 + registers: [0x0012] + isstr: true + + - name: "Start-up Self-checking Time " + class: "" + state_class: "" + uom: "s" + scale: 1 + rule: 1 + registers: [0x0015] + icon: "mdi:solar-power" + + - name: "Update Time" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 8 + registers: [0x0016, 0x0017, 0x0018] + isstr: true + + - name: "Soft Start Enable" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x002F] + isstr: true + lookup: + - key: 0 + value: "Disabled" + - key: 1 + value: "Enabled" + icon: "mdi:toggle-switch" + + - name: "Power Factor Regulation" + class: "" + state_class: "" + uom: "" + scale: 0.1 + rule: 2 + registers: [0x0032] + icon: "" + + - name: "Restore Factory Settings" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0036] + isstr: true + lookup: + - key: 0 + value: "Disabled" + - key: 1 + value: "Enabled" + icon: "mdi:factory" diff --git a/custom_components/solarman/inverter_definitions/deye_4mppt.yaml b/custom_components/solarman/inverter_definitions/deye_4mppt.yaml index ff5b4b9..1e947c2 100644 --- a/custom_components/solarman/inverter_definitions/deye_4mppt.yaml +++ b/custom_components/solarman/inverter_definitions/deye_4mppt.yaml @@ -2,250 +2,271 @@ # Latest update: 08.09.2023 # Microinverter SUN2000G3 (DEYE/VESDAS) # 4x MPPT, 4x inverter -# 1x Logger, 4x Module, +# 1x Logger, 4x Module, -requests: - - start: 0x0001 - end: 0x007D - mb_functioncode: 0x03 +default: + update_interval: 60 + digits: 6 parameters: - group: solar - items: - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x006D] - icon: 'mdi:solar-power' - - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x006F] - icon: 'mdi:solar-power' - - - name: "PV3 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0071] - icon: 'mdi:solar-power' - - - name: "PV4 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0073] - icon: 'mdi:solar-power' - - - name: "PV1 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x006E] - icon: 'mdi:solar-power' - - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x0070] - icon: 'mdi:solar-power' - - - name: "PV3 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x0072] - icon: 'mdi:solar-power' - - - name: "PV4 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x0074] - icon: 'mdi:solar-power' - - - name: "Daily Production" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x003C] - icon: 'mdi:solar-power' - - - name: "Total Production" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x003F,0x0040] - icon: 'mdi:solar-power' - validation: - min: 0.1 - invalidate_all: - - - name: "Active Power Regulations" - class: "" - state_class: "" - uom: "%" - scale: 1 - rule: 1 - registers: [0x0028] - icon: 'mdi:solar-power' + items: + - name: "PV1 Voltage" + realtime: + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x006D] + icon: "mdi:solar-power" + + - name: "PV2 Voltage" + realtime: + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x006F] + icon: "mdi:solar-power" + + - name: "PV3 Voltage" + realtime: + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0071] + icon: "mdi:solar-power" + + - name: "PV4 Voltage" + realtime: + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0073] + icon: "mdi:solar-power" + + - name: "PV1 Current" + realtime: + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x006E] + icon: "mdi:solar-power" + + - name: "PV2 Current" + realtime: + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x0070] + icon: "mdi:solar-power" + + - name: "PV3 Current" + realtime: + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x0072] + icon: "mdi:solar-power" + + - name: "PV4 Current" + realtime: + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x0074] + icon: "mdi:solar-power" + + - name: "Daily Production" + realtime: + class: "energy" + state_class: "total" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x003C] + icon: "mdi:solar-power" + + - name: "Total Production" + realtime: + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x003F, 0x0040] + icon: "mdi:solar-power" + validation: + min: 0.1 + invalidate_all: + + - name: "Active Power Regulations" + realtime: + class: "" + state_class: "" + uom: "%" + scale: 1 + rule: 1 + registers: [0x0028] + icon: "mdi:solar-power" - group: Grid items: - - name: "AC Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0049] - icon: 'mdi:transmission-tower' - - - name: "Grid Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 2 - registers: [0x004C] - icon: 'mdi:home-lightning-bolt' - - - name: "AC Output Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x004F] - icon: 'mdi:home-lightning-bolt' + - name: "AC Voltage" + realtime: + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0049] + icon: "mdi:transmission-tower" + + - name: "Grid Current" + realtime: + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 2 + registers: [0x004C] + icon: "mdi:home-lightning-bolt" + + - name: "AC Output Frequency" + realtime: + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x004F] + icon: "mdi:home-lightning-bolt" - group: Inverter items: - - name: "Running Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x003B] - isstr: true - lookup: - - key: 0 - value: "Stand-by" - - key: 1 - value: "Self-check" - - key: 2 - value: "Normal" - - key: 3 - value: "Warning" - - key: 4 - value: "Fault" - icon: 'mdi:home-lightning-bolt' - - - name: "Total AC Output Power (Active)" - class: "power" - state_class: "measurement" - uom: "W" - scale: 0.1 - rule: 3 - registers: [0x0056, 0x0057] - icon: 'mdi:home-lightning-bolt' - - - name: "Radiator Temperature" - class: "temperature" - uom: "°C" - state_class: "measurement" - scale: 0.01 - rule: 1 - offset: 1000 - registers: [0x005a] - - - name: "Inverter ID" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 5 - registers: [0x0003,0x0004,0x0005,0x0006,0x0007] - isstr: true - - - name: "Rated Power" - class: "energy" - state_class: "" - uom: "W" - scale: 0.1 - rule: 1 - registers: [0x0010] - icon: 'mdi:solar-power' - - - name: "Start-up Self-checking Time " - class: "" - state_class: "" - uom: "s" - scale: 1 - rule: 1 - registers: [0x0015] - icon: 'mdi:solar-power' - - - name: "Soft Start Enable" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x002F] - isstr: true - lookup: - - key: 0 - value: "Disabled" - - key: 1 - value: "Enabled" - icon: 'mdi:toggle-switch' - - - name: "Power Factor Regulation" - class: "" - state_class: "" - uom: "" - scale: 0.1 - rule: 2 - registers: [0x0032] - icon: '' - - - name: "Restore Factory Settings" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0036] - isstr: true - lookup: - - key: 0 - value: "Disabled" - - key: 1 - value: "Enabled" - icon: 'mdi:factory' + - name: "Running Status" + realtime: + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x003B] + isstr: true + lookup: + - key: 0 + value: "Stand-by" + - key: 1 + value: "Self-check" + - key: 2 + value: "Normal" + - key: 3 + value: "Warning" + - key: 4 + value: "Fault" + icon: "mdi:home-lightning-bolt" + + - name: "Total AC Output Power (Active)" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 0.1 + rule: 3 + registers: [0x0056, 0x0057] + icon: "mdi:home-lightning-bolt" + + - name: "Radiator Temperature" + realtime: + class: "temperature" + uom: "°C" + state_class: "measurement" + scale: 0.01 + rule: 1 + offset: 1000 + registers: [0x005a] + + - name: "Inverter ID" + realtime: + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 5 + registers: [0x0003, 0x0004, 0x0005, 0x0006, 0x0007] + isstr: true + + - name: "Rated Power" + realtime: + class: "energy" + state_class: "" + uom: "W" + scale: 0.1 + rule: 1 + registers: [0x0010] + icon: "mdi:solar-power" + + - name: "Start-up Self-checking Time " + class: "" + state_class: "" + uom: "s" + scale: 1 + rule: 1 + registers: [0x0015] + icon: "mdi:solar-power" + + - name: "Soft Start Enable" + realtime: + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x002F] + isstr: true + lookup: + - key: 0 + value: "Disabled" + - key: 1 + value: "Enabled" + icon: "mdi:toggle-switch" + + - name: "Power Factor Regulation" + realtime: + class: "" + state_class: "" + uom: "" + scale: 0.1 + rule: 2 + registers: [0x0032] + icon: "" + + - name: "Restore Factory Settings" + realtime: + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0036] + isstr: true + lookup: + - key: 0 + value: "Disabled" + - key: 1 + value: "Enabled" + icon: "mdi:factory" diff --git a/custom_components/solarman/inverter_definitions/deye_hybrid.yaml b/custom_components/solarman/inverter_definitions/deye_hybrid.yaml index bb88f1a..684251b 100644 --- a/custom_components/solarman/inverter_definitions/deye_hybrid.yaml +++ b/custom_components/solarman/inverter_definitions/deye_hybrid.yaml @@ -1,3 +1,7 @@ +default: + update_interval: 60 + digits: 6 + requests: - start: 0x0003 end: 0x0070 @@ -10,821 +14,820 @@ requests: mb_functioncode: 0x03 parameters: - - group: solar - items: - - name: "PV1 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [0x00BA] - icon: 'mdi:solar-power' - - - name: "PV2 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [0x00BB] - icon: 'mdi:solar-power' - - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x006D] - icon: 'mdi:solar-power' - - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x006F] - icon: 'mdi:solar-power' - - - name: "PV1 Current" - class: "current" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x006E] - icon: 'mdi:solar-power' - - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x0070] - icon: 'mdi:solar-power' - - - name: "Daily Production" - class: "energy" - state_class: "measurement" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x006C] - icon: 'mdi:solar-power' - - - name: "Total Production" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x0060,0x0061] - icon: 'mdi:solar-power' - - - name: "Micro-inverter Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [0x00A6] - icon: 'mdi:solar-power' - - - group: Battery - items: - - name: "Total Battery Charge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x0048,0x0049] - icon: 'mdi:battery-plus' - - - name: "Total Battery Discharge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x004A,0x004B] - icon: 'mdi:battery-minus' - - - name: "Daily Battery Charge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x0046] - icon: 'mdi:battery-plus' - - - name: "Daily Battery Discharge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x0047] - icon: 'mdi:battery-minus' - - - name: "Battery Status" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [0x00BD] - isstr: true - lookup: - - key: 0 - value: "Charge" - - key: 1 - value: "Stand-by" - - key: 2 - value: "Discharge" - icon: 'mdi:battery' - - - name: "Battery Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00BE] - icon: 'mdi:battery' - - - name: "Battery Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.01 - rule: 1 - registers: [0x00B7] - icon: 'mdi:battery' - - - name: "Battery SOC" - class: "battery" - state_class: "measurement" - uom: "%" - scale: 1 - rule: 1 - registers: [0x00B8] - icon: 'mdi:battery' - - - name: "Battery Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 2 - registers: [0x00BF] - icon: 'mdi:battery' - - - name: "Battery Temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 0.1 - rule: 1 - offset: 1000 - registers: [0x00B6] - icon: 'mdi:battery' - - - group: Grid - items: - - name: "Total Grid Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00A9] - icon: 'mdi:transmission-tower' - - - name: "Grid Voltage L1" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0096] - icon: 'mdi:transmission-tower' - - - name: "Grid Current L1" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x00A0] - icon: 'mdi:current-ac' - - name: "Grid Voltage L2" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0097] - icon: 'mdi:transmission-tower' - - - name: "Grid Current L2" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x00A1] - icon: 'mdi:current-ac' - - - name: "Internal CT L1 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00A7] - icon: 'mdi:transmission-tower' - - - name: "Internal CT L2 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00A8] - icon: 'mdi:transmission-tower' - - - name: "External CT L1 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00AA] - icon: 'mdi:transmission-tower' - - - name: "External CT L2 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00AB] - icon: 'mdi:transmission-tower' - - - name: "Daily Energy Bought" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x004C] - icon: 'mdi:transmission-tower-export' - - - name: "Total Energy Bought" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x004E,0x0050] - icon: 'mdi:transmission-tower-export' - - - name: "Daily Energy Sold" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x004D] - icon: 'mdi:transmission-tower-import' - - - name: "Total Energy Sold" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x0051,0x0052] - icon: 'mdi:transmission-tower-import' - - - - name: "Total Grid Production" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 4 - registers: [0x003F,0x0040] - icon: 'mdi:transmission-tower' - - - group: Upload - items: - - name: "Total Load Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [0x00B2] - icon: 'mdi:lightning-bolt-outline' - - - name: "Load L1 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [0x00B0] - icon: 'mdi:lightning-bolt-outline' - - - name: "Load L2 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [0x00B1] - icon: 'mdi:lightning-bolt-outline' - - - name: "Load Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x009D] - icon: 'mdi:lightning-bolt-outline' - - - name: "Daily Load Consumption" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x0054] - icon: 'mdi:lightning-bolt-outline' - - - name: "Total Load Consumption" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x0055,0x0056] - icon: 'mdi:lightning-bolt-outline' - - - name: "SmartLoad Enable Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x00C3] - isstr: true - lookup: - - key: 0 - value: "OFF" - - key: 1 - value: "ON" - icon: 'mdi:lightning-bolt-outline' - - - group: Inverter - items: - - name: "Running Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x003B] - isstr: true - lookup: - - key: 0 - value: "Stand-by" - - key: 1 - value: "Self-checking" - - key: 2 - value: "Normal" - - key: 3 - value: "FAULT" - icon: 'mdi:home-lightning-bolt' - - - name: "Total Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00AF] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x004F] - icon: 'mdi:sine-wave' - - - name: "Current L1" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 2 - registers: [0x00A4] - icon: 'mdi:home-lightning-bolt' - - - name: "Current L2" - class: "current" - uom: "A" - scale: 0.01 - rule: 2 - registers: [0x00A5] - icon: 'mdi:home-lightning-bolt' - - - name: "Inverter L1 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00AD] - icon: 'mdi:home-lightning-bolt' - - - name: "Inverter L2 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 2 - registers: [0x00AE] - icon: 'mdi:home-lightning-bolt' - - - name: "Load Frequency" - class: "" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x00C0] - icon: 'mdi:sine-wave' - - - name: "DC Temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 0.1 - rule: 2 - offset: 1000 - registers: [0x005A] - icon: 'mdi:thermometer' - - - name: "AC Temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 0.1 - rule: 2 - offset: 1000 - registers: [0x005B] - icon: 'mdi:thermometer' - - - name: "Inverter ID" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 5 - registers: [0x0003,0x0004,0x0005,0x0006,0x0007] - isstr: true - - - name: "Communication Board Version No." - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x000E] - isstr: true - - - name: "Control Board Version No." - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x000D] - isstr: true - - - name: "Grid-connected Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x00C2] - isstr: true - lookup: - - key: 0 - value: "Off-Grid" - - key: 1 - value: "On-Grid" - - - name: "Gen-connected Status" - class: "" - uom: "" - state_class: "" - scale: 1 - rule: 1 - registers: [0x00A6] - isstr: true - lookup: - - key: 0 - value: "none" - - key: 1 - value: "On" - - - name: "Gen Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [0x00A6] - - - name: "Work Mode" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 3 - registers: [0x00F4,0x00F7] - isstr: true - lookup: - - key: 0 - value: "Selling First" - - key: 1 - value: "Zero-Export to Load&Solar Sell" - - key: 2 - value: "Zero-Export to Home&Solar Sell" - - key: 3 - value: "Zero-Export to Load" - - key: 4 - value: "Zero-Export to Home" - icon: 'mdi:home-lightning-bolt' - - - group: Alert - items: - - name: "Alert" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 6 - registers: [0x0065,0x0066,0x0067,0x0068,0x0069,0x006A] - - - group: Time of Use - items: - - name: "Time of use Time 1" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 9 - registers: [0x00FA] - icon: 'mdi:timelapse' - - - name: "Time of use Time 2" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 9 - registers: [0x00FB] - icon: "mdi:timelapse" - - - name: "Time of Use Time 3" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 9 - registers: [0x00FC] - icon: 'mdi:timelapse' - - - name: "Time of Use Time 4" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 9 - registers: [0x00FD] - icon: 'mdi:timelapse' - - - name: "Time of Use Time 5" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 9 - registers: [0x00FE] - icon: "mdi:timelapse" - - - name: "Time of Use Time 6" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 9 - registers: [0x00FF] - icon: 'mdi:timelapse' - - - name: "Time of Use Power 1" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0100] - icon: "mdi:lightning-bolt-outline" - - - name: "Time of Use Power 2" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0101] - icon: 'mdi:lightning-bolt-outline' - - - name: "Time of Use Power 3" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0102] - icon: 'mdi:lightning-bolt-outline' - - - name: "Time of Use Power 4" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0103] - icon: 'mdi:lightning-bolt-outline' - - - name: "Time of Use Power 5" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0104] - icon: 'mdi:lightning-bolt-outline' - - - name: "Time of Use Power 6" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0105] - icon: 'mdi:lightning-bolt-outline' - - - name: "Time of Use SOC 1" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x010C] - icon: 'mdi:battery' - - - name: "Time of Use SOC 2" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x010D] - icon: 'mdi:battery' - - - name: "Time of Use SOC 3" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x010E] - icon: 'mdi:battery' - - - name: "Time of Use SOC 4" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x010F] - icon: 'mdi:battery' - - - name: "Time of Use SOC 5" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0110] - icon: 'mdi:battery' - - - name: "Time of Use SOC 6" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0111] - icon: 'mdi:battery' - - - name: "Time of Use Enable 1" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - mask: 1 - registers: [0x0112] - icon: 'mdi:checkbox-marked-outline' - - - name: "Time of Use Enable 2" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - mask: 1 - registers: [0x0113] - icon: 'mdi:checkbox-marked-outline' - - - name: "Time of Use Enable 3" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - mask: 1 - registers: [0x0114] - icon: 'mdi:checkbox-marked-outline' - - - name: "Time of Use Enable 4" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - mask: 1 - registers: [0x0115] - icon: 'mdi:checkbox-marked-outline' - - - name: "Time of Use Enable 5" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - mask: 1 - registers: [0x0116] - icon: 'mdi:checkbox-marked-outline' - - - name: "Time of Use Enable 6" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - mask: 1 - registers: [0x0117] - icon: 'mdi:checkbox-marked-outline' - - - name: "Time of use" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - mask: 1 - registers: [0x00F8] - icon: 'mdi:checkbox-marked-outline' - isstr: true - lookup: - - key: 0 - value: "Disable" - - key: 1 - value: "Enable" + - group: solar + items: + - name: "PV1 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [0x00BA] + icon: "mdi:solar-power" + + - name: "PV2 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [0x00BB] + icon: "mdi:solar-power" + + - name: "PV1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x006D] + icon: "mdi:solar-power" + + - name: "PV2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x006F] + icon: "mdi:solar-power" + + - name: "PV1 Current" + class: "current" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x006E] + icon: "mdi:solar-power" + + - name: "PV2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x0070] + icon: "mdi:solar-power" + + - name: "Daily Production" + class: "energy" + state_class: "measurement" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x006C] + icon: "mdi:solar-power" + + - name: "Total Production" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x0060, 0x0061] + icon: "mdi:solar-power" + + - name: "Micro-inverter Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [0x00A6] + icon: "mdi:solar-power" + + - group: Battery + items: + - name: "Total Battery Charge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x0048, 0x0049] + icon: "mdi:battery-plus" + + - name: "Total Battery Discharge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x004A, 0x004B] + icon: "mdi:battery-minus" + + - name: "Daily Battery Charge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x0046] + icon: "mdi:battery-plus" + + - name: "Daily Battery Discharge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x0047] + icon: "mdi:battery-minus" + + - name: "Battery Status" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [0x00BD] + isstr: true + lookup: + - key: 0 + value: "Charge" + - key: 1 + value: "Stand-by" + - key: 2 + value: "Discharge" + icon: "mdi:battery" + + - name: "Battery Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00BE] + icon: "mdi:battery" + + - name: "Battery Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.01 + rule: 1 + registers: [0x00B7] + icon: "mdi:battery" + + - name: "Battery SOC" + class: "battery" + state_class: "measurement" + uom: "%" + scale: 1 + rule: 1 + registers: [0x00B8] + icon: "mdi:battery" + + - name: "Battery Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 2 + registers: [0x00BF] + icon: "mdi:battery" + + - name: "Battery Temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 0.1 + rule: 1 + offset: 1000 + registers: [0x00B6] + icon: "mdi:battery" + + - group: Grid + items: + - name: "Total Grid Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00A9] + icon: "mdi:transmission-tower" + + - name: "Grid Voltage L1" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0096] + icon: "mdi:transmission-tower" + + - name: "Grid Current L1" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x00A0] + icon: "mdi:current-ac" + - name: "Grid Voltage L2" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0097] + icon: "mdi:transmission-tower" + + - name: "Grid Current L2" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x00A1] + icon: "mdi:current-ac" + + - name: "Internal CT L1 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00A7] + icon: "mdi:transmission-tower" + + - name: "Internal CT L2 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00A8] + icon: "mdi:transmission-tower" + + - name: "External CT L1 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00AA] + icon: "mdi:transmission-tower" + + - name: "External CT L2 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00AB] + icon: "mdi:transmission-tower" + + - name: "Daily Energy Bought" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x004C] + icon: "mdi:transmission-tower-export" + + - name: "Total Energy Bought" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x004E, 0x0050] + icon: "mdi:transmission-tower-export" + + - name: "Daily Energy Sold" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x004D] + icon: "mdi:transmission-tower-import" + + - name: "Total Energy Sold" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x0051, 0x0052] + icon: "mdi:transmission-tower-import" + + - name: "Total Grid Production" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 4 + registers: [0x003F, 0x0040] + icon: "mdi:transmission-tower" + + - group: Upload + items: + - name: "Total Load Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [0x00B2] + icon: "mdi:lightning-bolt-outline" + + - name: "Load L1 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [0x00B0] + icon: "mdi:lightning-bolt-outline" + + - name: "Load L2 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [0x00B1] + icon: "mdi:lightning-bolt-outline" + + - name: "Load Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x009D] + icon: "mdi:lightning-bolt-outline" + + - name: "Daily Load Consumption" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x0054] + icon: "mdi:lightning-bolt-outline" + + - name: "Total Load Consumption" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x0055, 0x0056] + icon: "mdi:lightning-bolt-outline" + + - name: "SmartLoad Enable Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x00C3] + isstr: true + lookup: + - key: 0 + value: "OFF" + - key: 1 + value: "ON" + icon: "mdi:lightning-bolt-outline" + + - group: Inverter + items: + - name: "Running Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x003B] + isstr: true + lookup: + - key: 0 + value: "Stand-by" + - key: 1 + value: "Self-checking" + - key: 2 + value: "Normal" + - key: 3 + value: "FAULT" + icon: "mdi:home-lightning-bolt" + + - name: "Total Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00AF] + icon: "mdi:home-lightning-bolt" + + - name: "Grid Frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x004F] + icon: "mdi:sine-wave" + + - name: "Current L1" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 2 + registers: [0x00A4] + icon: "mdi:home-lightning-bolt" + + - name: "Current L2" + class: "current" + uom: "A" + scale: 0.01 + rule: 2 + registers: [0x00A5] + icon: "mdi:home-lightning-bolt" + + - name: "Inverter L1 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00AD] + icon: "mdi:home-lightning-bolt" + + - name: "Inverter L2 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x00AE] + icon: "mdi:home-lightning-bolt" + + - name: "Load Frequency" + class: "" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x00C0] + icon: "mdi:sine-wave" + + - name: "DC Temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 0.1 + rule: 2 + offset: 1000 + registers: [0x005A] + icon: "mdi:thermometer" + + - name: "AC Temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 0.1 + rule: 2 + offset: 1000 + registers: [0x005B] + icon: "mdi:thermometer" + + - name: "Inverter ID" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 5 + registers: [0x0003, 0x0004, 0x0005, 0x0006, 0x0007] + isstr: true + + - name: "Communication Board Version No." + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x000E] + isstr: true + + - name: "Control Board Version No." + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x000D] + isstr: true + + - name: "Grid-connected Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x00C2] + isstr: true + lookup: + - key: 0 + value: "Off-Grid" + - key: 1 + value: "On-Grid" + + - name: "Gen-connected Status" + class: "" + uom: "" + state_class: "" + scale: 1 + rule: 1 + registers: [0x00A6] + isstr: true + lookup: + - key: 0 + value: "none" + - key: 1 + value: "On" + + - name: "Gen Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [0x00A6] + + - name: "Work Mode" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 3 + registers: [0x00F4, 0x00F7] + isstr: true + lookup: + - key: 0 + value: "Selling First" + - key: 1 + value: "Zero-Export to Load&Solar Sell" + - key: 2 + value: "Zero-Export to Home&Solar Sell" + - key: 3 + value: "Zero-Export to Load" + - key: 4 + value: "Zero-Export to Home" + icon: "mdi:home-lightning-bolt" + + - group: Alert + items: + - name: "Alert" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 6 + registers: [0x0065, 0x0066, 0x0067, 0x0068, 0x0069, 0x006A] + + - group: Time of Use + items: + - name: "Time of use Time 1" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 9 + registers: [0x00FA] + icon: "mdi:timelapse" + + - name: "Time of use Time 2" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 9 + registers: [0x00FB] + icon: "mdi:timelapse" + + - name: "Time of Use Time 3" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 9 + registers: [0x00FC] + icon: "mdi:timelapse" + + - name: "Time of Use Time 4" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 9 + registers: [0x00FD] + icon: "mdi:timelapse" + + - name: "Time of Use Time 5" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 9 + registers: [0x00FE] + icon: "mdi:timelapse" + + - name: "Time of Use Time 6" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 9 + registers: [0x00FF] + icon: "mdi:timelapse" + + - name: "Time of Use Power 1" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0100] + icon: "mdi:lightning-bolt-outline" + + - name: "Time of Use Power 2" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0101] + icon: "mdi:lightning-bolt-outline" + + - name: "Time of Use Power 3" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0102] + icon: "mdi:lightning-bolt-outline" + + - name: "Time of Use Power 4" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0103] + icon: "mdi:lightning-bolt-outline" + + - name: "Time of Use Power 5" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0104] + icon: "mdi:lightning-bolt-outline" + + - name: "Time of Use Power 6" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0105] + icon: "mdi:lightning-bolt-outline" + + - name: "Time of Use SOC 1" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x010C] + icon: "mdi:battery" + + - name: "Time of Use SOC 2" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x010D] + icon: "mdi:battery" + + - name: "Time of Use SOC 3" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x010E] + icon: "mdi:battery" + + - name: "Time of Use SOC 4" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x010F] + icon: "mdi:battery" + + - name: "Time of Use SOC 5" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0110] + icon: "mdi:battery" + + - name: "Time of Use SOC 6" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0111] + icon: "mdi:battery" + + - name: "Time of Use Enable 1" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + mask: 1 + registers: [0x0112] + icon: "mdi:checkbox-marked-outline" + + - name: "Time of Use Enable 2" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + mask: 1 + registers: [0x0113] + icon: "mdi:checkbox-marked-outline" + + - name: "Time of Use Enable 3" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + mask: 1 + registers: [0x0114] + icon: "mdi:checkbox-marked-outline" + + - name: "Time of Use Enable 4" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + mask: 1 + registers: [0x0115] + icon: "mdi:checkbox-marked-outline" + + - name: "Time of Use Enable 5" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + mask: 1 + registers: [0x0116] + icon: "mdi:checkbox-marked-outline" + + - name: "Time of Use Enable 6" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + mask: 1 + registers: [0x0117] + icon: "mdi:checkbox-marked-outline" + + - name: "Time of use" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + mask: 1 + registers: [0x00F8] + icon: "mdi:checkbox-marked-outline" + isstr: true + lookup: + - key: 0 + value: "Disable" + - key: 1 + value: "Enable" diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 7776913..1ec94cf 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -2,6 +2,10 @@ # SUN-5/6/8/10/12/15/20/25K-SG01HP3-EU-AM2 | 5-25kW | Three Phase | 2 MPPT | Hybrid Inverter | HV Battery Supported # +default: + update_interval: 60 + digits: 6 + parameters: - group: Parameters items: @@ -644,19 +648,49 @@ parameters: class: "energy" state_class: "total_increasing" uom: "kWh" - scale: 0.1 - rule: 0 - params: ["Today Energy Export", "Today Production", "Today Battery Discharge", "Today Energy Import", "Today Load Consumption", "Today Battery Charge"] - formula: "max(round({0} + {1} + {2} - {3} - {4} - {5}, 1), 0)" + rule: 1 + digits: 1 + registers: [0x0208, 0x0211, 0x0203, 0x0209, 0x020E, 0x0202] + sensors: + - scale: 0.1 + registers: [0x0208] + - scale: 0.1 + registers: [0x0211] + - scale: 0.1 + registers: [0x0203] + - subtract: + scale: 0.1 + registers: [0x0209] + - subtract: + scale: 0.1 + registers: [0x020E] + - subtract: + scale: 0.1 + registers: [0x0202] - name: "Total Losses" class: "energy" state_class: "total_increasing" uom: "kWh" - scale: 0.1 - rule: 0 - params: ["Total Energy Export", "Total Production", "Total Battery Discharge", "Total Energy Import", "Total Load Consumption", "Total Battery Charge"] - formula: "max(round({0} + {1} + {2} - {3} - {4} - {5}, 1), 0)" + rule: 3 + digits: 1 + registers: [0x020A, 0x020B, 0x0216, 0x0217, 0x0206, 0x0207, 0x020C, 0x020D, 0x020F, 0x0210, 0x0204, 0x0205] + sensors: + - scale: 0.1 + registers: [0x020A, 0x020B] + - scale: 0.1 + registers: [0x0216, 0x0217] + - scale: 0.1 + registers: [0x0206, 0x0207] + - subtract: + scale: 0.1 + registers: [0x020C, 0x020D] + - subtract: + scale: 0.1 + registers: [0x020F, 0x0210] + - subtract: + scale: 0.1 + registers: [0x0204, 0x0205] - name: "Today Production" class: "energy" @@ -756,11 +790,26 @@ parameters: state_class: "" uom: "" scale: 1 - rule: 0 - params: ["Device Relay Status enum"] - formula: "'On-grid' if {0} & 4 == 4 else 'Off-grid'" + rule: 1 + registers: [0x0228] + icon: "mdi:information" isstr: true - icon: "mdi:transmission-tower-off" + lookup_default: "X-grid" + lookup: + - key: 0x0001 + value: "Off-grid" + - key: 0x0004 + value: "On-grid" + - key: 0x0005 + value: "On-grid" + - key: 0x0008 + value: "Off-grid" + - key: 0x0009 + value: "Off-grid" + - key: 0x000C + value: "On-grid" + - key: 0x000D + value: "On-grid" # Device - Alarm message (word 1 & 2) [0, 65535] - name: "Device Alert" @@ -1244,10 +1293,20 @@ parameters: class: "power" state_class: "measurement" uom: "W" - scale: 1 - rule: 0 - params: ["Battery Power", "PV1 Power", "PV2 Power", "Inverter Power"] - formula: "max({0} + {1} + {2} - {3}, 0)" + rule: 1 + digits: 0 + registers: [0x024E, 0x02A0, 0x02A1, 0x027C, 0x02B6] + sensors: + - signed: + scale: 10 + registers: [0x024E] + - scale: 10 + registers: [0x02A0] + - scale: 10 + registers: [0x02A1] + - subtract: + signed: + registers: [0x027C, 0x02B6] # Inverter - Frequency - name: "Inverter Frequency" @@ -1380,10 +1439,14 @@ parameters: class: "power" state_class: "measurement" uom: "W" - scale: 1 - rule: 0 - params: ["PV1 Power", "PV2 Power"] - formula: "{0} + {1}" + rule: 1 + digits: 0 + registers: [0x02A0, 0x02A1] + sensors: + - scale: 10 + registers: [0x02A0] + - scale: 10 + registers: [0x02A1] icon: "mdi:solar-power-variant" # Photovoltaic - The power of Input 1 (L:1W, H:10W) diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index dee5c11..f27ada6 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -8,6 +8,10 @@ # The 500-2000 register address is a readable register type 0x03 function code. # +default: + update_interval: 60 + digits: 6 + parameters: - group: Parameters items: @@ -625,6 +629,68 @@ parameters: rule: 3 registers: [0x020F, 0x0210] + - name: "Today Losses" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + rule: 1 + digits: 1 + registers: [0x0208, 0x0211, 0x0203, 0x0209, 0x020E, 0x0202] + sensors: + - scale: 0.1 + registers: [0x0208] + - scale: 0.1 + registers: [0x0211] + - scale: 0.1 + registers: [0x0203] + - subtract: + scale: 0.1 + registers: [0x0209] + - subtract: + scale: 0.1 + registers: [0x020E] + - subtract: + scale: 0.1 + registers: [0x0202] + + - name: "Total Losses" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + rule: 3 + digits: 1 + registers: + [ + 0x020A, + 0x020B, + 0x0216, + 0x0217, + 0x0206, + 0x0207, + 0x020C, + 0x020D, + 0x020F, + 0x0210, + 0x0204, + 0x0205, + ] + sensors: + - scale: 0.1 + registers: [0x020A, 0x020B] + - scale: 0.1 + registers: [0x0216, 0x0217] + - scale: 0.1 + registers: [0x0206, 0x0207] + - subtract: + scale: 0.1 + registers: [0x020C, 0x020D] + - subtract: + scale: 0.1 + registers: [0x020F, 0x0210] + - subtract: + scale: 0.1 + registers: [0x0204, 0x0205] + - name: "Today Production" class: "energy" state_class: "total_increasing" @@ -717,6 +783,33 @@ parameters: - key: 0x000D value: "Inv-Grid-Gen" + # Device - AC Grid state + - name: "Device State" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0228] + icon: "mdi:information" + isstr: true + lookup_default: "X-grid" + lookup: + - key: 0x0001 + value: "Off-grid" + - key: 0x0004 + value: "On-grid" + - key: 0x0005 + value: "On-grid" + - key: 0x0008 + value: "Off-grid" + - key: 0x0009 + value: "Off-grid" + - key: 0x000C + value: "On-grid" + - key: 0x000D + value: "On-grid" + # Device - Alarm message (word 1 & 2) [0, 65535] - name: "Device Alert" update_interval: 30 @@ -1167,6 +1260,23 @@ parameters: rule: 4 registers: [0x027C, 0x02B6] + # Inverter - Includes consumption of the device itself aswell power losses of AC/DC conversions + - name: "Power losses" + class: "power" + state_class: "measurement" + uom: "W" + rule: 1 + digits: 0 + registers: [0x024E, 0x02A0, 0x02A1, 0x027C, 0x02B6] + sensors: + - signed: + registers: [0x024E] + - registers: [0x02A0] + - registers: [0x02A1] + - subtract: + signed: + registers: [0x027C, 0x02B6] + # Inverter output - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Inverter Frequency" realtime: @@ -1292,6 +1402,20 @@ parameters: - group: Photovoltaic items: + # Photovoltaic - The combined power of Input 1 & 2 + - name: "PV Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + rule: 1 + digits: 0 + registers: [0x02A0, 0x02A1] + sensors: + - registers: [0x02A0] + - registers: [0x02A1] + icon: "mdi:solar-power-variant" + # Photovoltaic - The power of Input 1 (L:1W, H:10W) - name: "PV1 Power" realtime: diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 736f1db..78012bb 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -10,6 +10,10 @@ # The 500-2000 register address is a readable register type 0x03 function code. # +default: + update_interval: 60 + digits: 6 + parameters: - group: Parameters items: @@ -582,7 +586,12 @@ parameters: uom: "" scale: 1 rule: 0 - params: ["Today Battery Charge", "Battery Capacity", "Battery Nominal Voltage"] + params: + [ + "Today Battery Charge", + "Battery Capacity", + "Battery Nominal Voltage", + ] formula: "round({0} / ({1} * {2} / 1000), 2)" icon: "mdi:battery-sync" @@ -592,7 +601,12 @@ parameters: uom: "" scale: 1 rule: 0 - params: ["Total Battery Charge", "Battery Capacity", "Battery Nominal Voltage"] + params: + [ + "Total Battery Charge", + "Battery Capacity", + "Battery Nominal Voltage", + ] formula: "round({0} / ({1} * {2} / 1000), 2)" icon: "mdi:battery-sync" @@ -652,19 +666,63 @@ parameters: class: "energy" state_class: "total_increasing" uom: "kWh" - scale: 0.1 - rule: 0 - params: ["Today Energy Bought", "Today Production", "Today Battery Discharge", "Today Energy Sold", "Today Load Consumption", "Today Battery Charge"] - formula: "max(round({0} + {1} + {2} - {3} - {4} - {5}, 1), 0)" + rule: 1 + digits: 1 + registers: [0x0208, 0x0211, 0x0203, 0x0209, 0x020E, 0x0202] + sensors: + - scale: 0.1 + registers: [0x0208] + - scale: 0.1 + registers: [0x0211] + - scale: 0.1 + registers: [0x0203] + - subtract: + scale: 0.1 + registers: [0x0209] + - subtract: + scale: 0.1 + registers: [0x020E] + - subtract: + scale: 0.1 + registers: [0x0202] - name: "Total Losses" class: "energy" state_class: "total_increasing" uom: "kWh" - scale: 0.1 - rule: 0 - params: ["Total Energy Bought", "Total Production", "Total Battery Discharge", "Total Energy Sold", "Total Load Consumption", "Total Battery Charge"] - formula: "max(round({0} + {1} + {2} - {3} - {4} - {5}, 1), 0)" + rule: 3 + digits: 1 + registers: + [ + 0x020A, + 0x020B, + 0x0216, + 0x0217, + 0x0206, + 0x0207, + 0x020C, + 0x020D, + 0x020F, + 0x0210, + 0x0204, + 0x0205, + ] + sensors: + - scale: 0.1 + registers: [0x020A, 0x020B] + - scale: 0.1 + registers: [0x0216, 0x0217] + - scale: 0.1 + registers: [0x0206, 0x0207] + - subtract: + scale: 0.1 + registers: [0x020C, 0x020D] + - subtract: + scale: 0.1 + registers: [0x020F, 0x0210] + - subtract: + scale: 0.1 + registers: [0x0204, 0x0205] - name: "Today Production" class: "energy" @@ -764,11 +822,26 @@ parameters: state_class: "" uom: "" scale: 1 - rule: 0 - params: ["Device Relay Status enum"] - formula: "'On-grid' if {0} & 4 == 4 else 'Off-grid'" + rule: 1 + registers: [0x0228] + icon: "mdi:information" isstr: true - icon: "mdi:transmission-tower-off" + lookup_default: "X-grid" + lookup: + - key: 0x0001 + value: "Off-grid" + - key: 0x0004 + value: "On-grid" + - key: 0x0005 + value: "On-grid" + - key: 0x0008 + value: "Off-grid" + - key: 0x0009 + value: "Off-grid" + - key: 0x000C + value: "On-grid" + - key: 0x000D + value: "On-grid" # Device - Alarm message (word 1 & 2) [0, 65535] - name: "Device Alert" @@ -882,7 +955,13 @@ parameters: uom: "%" scale: 1 rule: 0 - params: ["Total Battery Charge", "Battery Capacity", "Battery Nominal Voltage", "Battery Life Cycle Rating"] + params: + [ + "Total Battery Charge", + "Battery Capacity", + "Battery Nominal Voltage", + "Battery Life Cycle Rating", + ] formula: "round(100 - {0} / ({1} * {2} / 1000) / ({3} * 0.05), 2)" icon: "mdi:battery-heart" @@ -1146,10 +1225,7 @@ parameters: rule: 4 registers: [0x0271, 0x02B2] icon: "mdi:transmission-tower" - attributes: - [ - "Zero Export", - ] + attributes: ["Zero Export"] - group: Inverter items: @@ -1252,10 +1328,17 @@ parameters: class: "power" state_class: "measurement" uom: "W" - scale: 1 - rule: 0 - params: ["Battery Power", "PV1 Power", "PV2 Power", "Inverter Power"] - formula: "max({0} + {1} + {2} - {3}, 0)" + rule: 1 + digits: 0 + registers: [0x024E, 0x02A0, 0x02A1, 0x027C, 0x02B6] + sensors: + - signed: + registers: [0x024E] + - registers: [0x02A0] + - registers: [0x02A1] + - subtract: + signed: + registers: [0x027C, 0x02B6] # Inverter - Frequency - name: "Inverter Frequency" @@ -1388,10 +1471,12 @@ parameters: class: "power" state_class: "measurement" uom: "W" - scale: 1 - rule: 0 - params: ["PV1 Power", "PV2 Power"] - formula: "{0} + {1}" + rule: 1 + digits: 0 + registers: [0x02A0, 0x02A1] + sensors: + - registers: [0x02A0] + - registers: [0x02A1] icon: "mdi:solar-power-variant" # Photovoltaic - The power of Input 1 (L:1W, H:10W) diff --git a/custom_components/solarman/inverter_definitions/solarman_dtsd422-d3.yaml b/custom_components/solarman/inverter_definitions/solarman_dtsd422-d3.yaml new file mode 100644 index 0000000..67851dd --- /dev/null +++ b/custom_components/solarman/inverter_definitions/solarman_dtsd422-d3.yaml @@ -0,0 +1,456 @@ +# +# Solarman Smart Meter DTSD422-D3 +# + +parameters: + - group: Voltage + items: + - name: CT1 Voltage + realtime: + class: voltage + uom: V + scale: 0.1 + rule: 1 + registers: [0x0001] + + - name: CT2 Voltage + realtime: + class: voltage + uom: V + scale: 0.1 + rule: 1 + registers: [0x0002] + + - name: CT3 Voltage + realtime: + class: voltage + uom: V + scale: 0.1 + rule: 1 + registers: [0x0003] + + - name: CT4 Voltage + realtime: + class: voltage + uom: V + scale: 0.1 + rule: 1 + registers: [0x1001] + + - name: CT5 Voltage + realtime: + class: voltage + uom: V + scale: 0.1 + rule: 1 + registers: [0x1002] + + - name: CT6 Voltage + realtime: + class: voltage + uom: V + scale: 0.1 + rule: 1 + registers: [0x1003] + + - group: Current + items: + - name: CT1 Current + realtime: + class: current + state_class: measurement + uom: A + scale: 0.001 + rule: 4 + magnitude: True + registers: [0x0008, 0x0007] + + - name: CT2 Current + realtime: + class: current + state_class: measurement + uom: A + scale: 0.001 + rule: 4 + magnitude: True + registers: [0x000A, 0x0009] + + - name: CT3 Current + realtime: + class: current + state_class: measurement + uom: A + scale: 0.001 + rule: 4 + magnitude: True + registers: [0x000C, 0x000B] + + - name: CT4 Current + realtime: + class: current + state_class: measurement + uom: A + scale: 0.001 + rule: 4 + magnitude: True + registers: [0x1008, 0x1007] + + - name: CT5 Current + realtime: + class: current + state_class: measurement + uom: A + scale: 0.001 + rule: 4 + magnitude: True + registers: [0x100A, 0x1009] + + - name: CT6 Current + realtime: + class: current + state_class: measurement + uom: A + scale: 0.001 + rule: 4 + magnitude: True + registers: [0x100C, 0x100B] + + - group: Active Power + items: + - name: CT1-3 Active Power + realtime: + class: power + state_class: measurement + uom: W + scale: 1 + rule: 4 + magnitude: True + registers: [0x000E, 0x000D] + + - name: CT1 Active Power + realtime: + class: power + state_class: measurement + uom: W + scale: 1 + rule: 4 + magnitude: True + registers: [0x0010, 0x000F] + + - name: CT2 Active Power + realtime: + class: power + state_class: measurement + uom: W + scale: 1 + rule: 4 + magnitude: True + registers: [0x0012, 0x0011] + + - name: CT3 Active Power + realtime: + class: power + state_class: measurement + uom: W + scale: 1 + rule: 4 + magnitude: True + registers: [0x0014, 0x0013] + + - name: CT4-6 Active Power + realtime: + class: power + state_class: measurement + uom: W + scale: 1 + rule: 4 + magnitude: True + registers: [0x100E, 0x100D] + + - name: CT4 Active Power + realtime: + class: power + state_class: measurement + uom: W + scale: 1 + rule: 4 + magnitude: True + registers: [0x1010, 0x100F] + + - name: CT5 Active Power + realtime: + class: power + state_class: measurement + uom: W + scale: 1 + rule: 4 + magnitude: True + registers: [0x1012, 0x1011] + + - name: CT6 Active Power + realtime: + class: power + state_class: measurement + uom: W + scale: 1 + rule: 4 + magnitude: True + registers: [0x1014, 0x1013] + + - group: Reactive Power + items: + - name: CT1-3 Reactive Power + realtime: + class: reactive_power + state_class: measurement + uom: var + scale: 1 + rule: 4 + magnitude: True + registers: [0x0016, 0x0015] + + - name: CT1 Reactive Power + realtime: + class: reactive_power + state_class: measurement + uom: var + scale: 1 + rule: 4 + magnitude: True + registers: [0x0018, 0x0017] + + - name: CT2 Reactive Power + realtime: + class: reactive_power + state_class: measurement + uom: var + scale: 1 + rule: 4 + magnitude: True + registers: [0x001A, 0x0019] + + - name: CT3 Reactive Power + realtime: + class: reactive_power + state_class: measurement + uom: var + scale: 1 + rule: 4 + magnitude: True + registers: [0x001C, 0x001B] + + - name: CT4-6 Reactive Power + realtime: + class: reactive_power + state_class: measurement + uom: var + scale: 1 + rule: 4 + magnitude: True + registers: [0x1016, 0x1015] + + - name: CT4 Reactive Power + realtime: + class: reactive_power + state_class: measurement + uom: var + scale: 1 + rule: 4 + magnitude: True + registers: [0x1018, 0x1017] + + - name: CT5 Reactive Power + realtime: + class: reactive_power + state_class: measurement + uom: var + scale: 1 + rule: 4 + magnitude: True + registers: [0x101A, 0x1019] + + - name: CT6 Reactive Power + realtime: + class: reactive_power + state_class: measurement + uom: var + scale: 1 + rule: 4 + magnitude: True + registers: [0x101C, 0x101B] + + - group: Apparent Power + items: + - name: CT1-3 Apparent Power + realtime: + class: apparent_power + state_class: measurement + uom: VA + scale: 1 + rule: 4 + magnitude: True + registers: [0x001E, 0x001D] + + - name: CT1 Apparent Power + realtime: + class: apparent_power + state_class: measurement + uom: VA + scale: 1 + rule: 4 + magnitude: True + registers: [0x0020, 0x001F] + + - name: CT2 Apparent Power + realtime: + class: apparent_power + state_class: measurement + uom: VA + scale: 1 + rule: 4 + magnitude: True + registers: [0x0022, 0x0021] + + - name: CT3 Apparent Power + realtime: + class: apparent_power + state_class: measurement + uom: VA + scale: 1 + rule: 4 + magnitude: True + registers: [0x0024, 0x0023] + + - name: CT4-6 Apparent Power + realtime: + class: apparent_power + state_class: measurement + uom: VA + scale: 1 + rule: 4 + magnitude: True + registers: [0x101E, 0x101D] + + - name: CT4 Apparent Power + realtime: + class: apparent_power + state_class: measurement + uom: VA + scale: 1 + rule: 4 + magnitude: True + registers: [0x1020, 0x101F] + + - name: CT5 Apparent Power + realtime: + class: apparent_power + state_class: measurement + uom: VA + scale: 1 + rule: 4 + magnitude: True + registers: [0x1022, 0x1021] + + - name: CT6 Apparent Power + realtime: + class: apparent_power + state_class: measurement + uom: VA + scale: 1 + rule: 4 + magnitude: True + registers: [0x1024, 0x1023] + + - group: Power Factor + items: + - name: CT1-3 Power Factor + class: power_factor + state_class: measurement + uom: "" + scale: 0.001 + rule: 2 + magnitude: True + registers: [0x0025] + + - name: CT1 Power Factor + class: power_factor + state_class: measurement + uom: "" + scale: 0.001 + rule: 2 + magnitude: True + registers: [0x0026] + + - name: CT2 Power Factor + class: power_factor + state_class: measurement + uom: "" + scale: 0.001 + rule: 2 + magnitude: True + registers: [0x0027] + + - name: CT3 Power Factor + class: power_factor + state_class: measurement + uom: "" + scale: 0.001 + rule: 2 + magnitude: True + registers: [0x0028] + + - name: CT4-6 Power Factor + class: power_factor + state_class: measurement + uom: "" + scale: 0.001 + rule: 2 + magnitude: True + registers: [0x1025] + + - name: CT4 Power Factor + class: power_factor + state_class: measurement + uom: "" + scale: 0.001 + rule: 2 + magnitude: True + registers: [0x1026] + + - name: CT5 Power Factor + class: power_factor + state_class: measurement + uom: "" + scale: 0.001 + rule: 2 + magnitude: True + registers: [0x1027] + + - name: CT6 Power Factor + class: power_factor + state_class: measurement + uom: "" + scale: 0.001 + rule: 2 + magnitude: True + registers: [0x1028] + + - group: Frequency + items: + - name: CT1-3 Frequency + realtime: + class: frequency + state_class: measurement + uom: Hz + scale: 0.01 + rule: 1 + registers: [0x0029] + + - name: CT4-6 Frequency + realtime: + class: frequency + state_class: measurement + uom: Hz + scale: 0.01 + rule: 1 + registers: [0x1029] diff --git a/custom_components/solarman/parser.py b/custom_components/solarman/parser.py index 3f08e7d..8921358 100644 --- a/custom_components/solarman/parser.py +++ b/custom_components/solarman/parser.py @@ -1,21 +1,28 @@ from __future__ import annotations -import yaml import struct import logging -from itertools import groupby -from operator import itemgetter - -from .const import COORDINATOR_QUERY_INTERVAL_DEFAULT, FLOAT_ROUND_TO +from .const import * from .common import * _LOGGER = logging.getLogger(__name__) class ParameterParser: def __init__(self, parameter_definition): - self._lookups = yaml.safe_load(parameter_definition) - self.result = {} + self._lookups = parameter_definition + self._update_interval = TIMINGS_QUERY_INTERVAL_DEFAULT + self._digits = DIGITS_DEFAULT + self._result = {} + + if "default" in parameter_definition: + default = parameter_definition["default"] + if "update_interval" in default: + self._update_interval = default["update_interval"] + if "digits" in default: + self._digits = default["digits"] + + _LOGGER.debug(f"Default update_interval: {self._update_interval}, digits: {self._digits}") def lookup(self): return self._lookups["parameters"] @@ -33,7 +40,7 @@ def is_requestable(self, parameters): return self.is_valid(parameters) and self.is_enabled(parameters) and parameters["rule"] > 0 def is_scheduled(self, parameters, runtime): - return "realtime" in parameters or (runtime % (parameters["update_interval"] if "update_interval" in parameters else COORDINATOR_QUERY_INTERVAL_DEFAULT) == 0) + return "realtime" in parameters or (runtime % (parameters["update_interval"] if "update_interval" in parameters else self._update_interval) == 0) def get_sensors(self): result = [{"name": "Connection Status", "artificial": ""}] @@ -41,6 +48,7 @@ def get_sensors(self): for j in i["items"]: if self.is_sensor(j): result.append(j) + return result def get_requests(self, runtime = 0): @@ -52,7 +60,8 @@ def get_requests(self, runtime = 0): for i in self.lookup(): for j in i["items"]: if self.is_requestable(j) and self.is_scheduled(j, runtime): - self.result[j["name"]] = "" + self._result[j["name"]] = {} + self._result[j["name"]]["state"] = "" for r in j["registers"]: registers.append(r) @@ -67,10 +76,21 @@ def parse(self, rawData, start, length): for j in i["items"]: if self.is_valid(j) and self.is_enabled(j): self.try_parse(rawData, j, start, length) + return + def set_state(self, key, value): + self._result[key] = {} + self._result[key]["state"] = value + + def set_state_number(self, key, value, digits): + if isinstance(value, int) or (isinstance(value, float) and value.is_integer()): + self.set_state(key, int(value)) + else: + self.set_state(key, round(value, digits)) + def get_result(self): - return self.result + return self._result def in_range(self, value, definition): if "range" in definition: @@ -78,25 +98,27 @@ def in_range(self, value, definition): if "min" in range and "max" in range: if value < range["min"] or value > range["max"]: return False + return True def lookup_value(self, value, definition): for o in definition["lookup"]: if (o["key"] == value): return o["value"] + return value if not "lookup_default" in definition else f"{definition["lookup_default"]} [{value}]" - def do_validate(self, title, value, rule): + def do_validate(self, key, value, rule): if "min" in rule: if rule["min"] > value: if "invalidate_all" in rule: - raise ValueError(f"Invalidate complete dataset ({title} ~ {value})") + raise ValueError(f"Invalidate complete dataset ({key} ~ {value})") return False if "max" in rule: if rule["max"] < value: if "invalidate_all" in rule: - raise ValueError(f"Invalidate complete dataset ({title} ~ {value})") + raise ValueError(f"Invalidate complete dataset ({key} ~ {value})") return False return True @@ -131,19 +153,19 @@ def try_parse_field(self, rawData, definition, start, length): case 9: self.try_parse_time(rawData, definition, start, length) case 10: - self.try_parse_raw(rawData,definition, start, length) + self.try_parse_raw(rawData, definition, start, length) + return - def try_parse_unsigned(self, rawData, definition, start, length): - title = definition["name"] - scale = definition["scale"] - value = 0 + def _read_registers(self, rawData, definition, start, length): + scale = definition["scale"] if "scale" in definition else 1 found = True + value = 0 shift = 0 for r in definition["registers"]: index = r - start - if (index >= 0) and (index < length): + if index >= 0 and index < length: value += (rawData[index] & 0xFFFF) << shift shift += 16 else: @@ -151,39 +173,29 @@ def try_parse_unsigned(self, rawData, definition, start, length): if found: if not self.in_range(value, definition): - return + return None if "mask" in definition: - mask = definition["mask"] - value &= mask + value &= definition["mask"] - if "lookup" in definition: - self.result[title] = self.lookup_value(value, definition) - self.result[title + " enum"] = int(value) - else: + if "lookup" not in definition: if "offset" in definition: value = value - definition["offset"] - value = value * scale - if "validation" in definition: - if not self.do_validate(title, value, definition["validation"]): - return - - self.num_to_result(title, value) - return + return value if found else None - def try_parse_signed(self, rawData, definition, start, length): - title = definition["name"] - scale = definition["scale"] - value = 0 + def _read_registers_signed(self, rawData, definition, start, length): + magnitude = definition["magnitude"] if "magnitude" in definition else False + scale = definition["scale"] if "scale" in definition else 1 found = True - shift = 0 maxint = 0 + value = 0 + shift = 0 for r in definition["registers"]: index = r - start - if (index >= 0) and (index < length): + if index >= 0 and index < length: maxint <<= 16 maxint |= 0xFFFF value += (rawData[index] & 0xFFFF) << shift @@ -193,27 +205,67 @@ def try_parse_signed(self, rawData, definition, start, length): if found: if not self.in_range(value, definition): - return + return None if "offset" in definition: value = value - definition["offset"] - if value > maxint / 2: - value = (value - maxint) * scale + if value > (maxint >> 1): + value = (value - maxint) if not magnitude else -(value & (maxint >> 1)) + + value = value * scale + + return value if found else None + + def try_parse_unsigned(self, rawData, definition, start, length): + key = definition["name"] + value = 0 + found = True + + if "sensors" in definition: + for s in definition["sensors"]: + if (n := (self._read_registers(rawData, s, start, length) if not "signed" in s else self._read_registers_signed(rawData, s, start, length))) is not None: + if not "subtract" in s: + value += n + else: + value -= n + else: + found = False + else: + value = self._read_registers(rawData, definition, start, length) + found = value is not None + + if found: + if "lookup" in definition: + self.set_state(key, self.lookup_value(value, definition)) + self._result[key]["value"] = int(value) else: - value = value * scale + if "validation" in definition: + if not self.do_validate(key, value, definition["validation"]): + return + + self.set_state_number(key, value, definition["digits"] if "digits" in definition else self._digits) + + return + + def try_parse_signed(self, rawData, definition, start, length): + key = definition["name"] + value = self._read_registers_signed(rawData, definition, start, length) + if value is not None: if "validation" in definition: - if not self.do_validate(title, value, definition["validation"]): + if not self.do_validate(key, value, definition["validation"]): return - self.num_to_result(title, value) + self.set_state_number(key, value, definition["digits"] if "digits" in definition else self._digits) + return def try_parse_ascii(self, rawData, definition, start, length): - title = definition["name"] + key = definition["name"] found = True value = "" + for r in definition["registers"]: index = r - start if (index >= 0) and (index < length): @@ -223,13 +275,15 @@ def try_parse_ascii(self, rawData, definition, start, length): found = False if found: - self.result[title] = value + self.set_state(key, value) + return def try_parse_bits(self, rawData, definition, start, length): - title = definition["name"] + key = definition["name"] found = True value = [] + for r in definition["registers"]: index = r - start if (index >= 0) and (index < length): @@ -239,13 +293,15 @@ def try_parse_bits(self, rawData, definition, start, length): found = False if found: - self.result[title] = value + self.set_state(key, value) + return def try_parse_version(self, rawData, definition, start, length): - title = definition["name"] + key = definition["name"] found = True value = "" + for r in definition["registers"]: index = r - start if (index >= 0) and (index < length): @@ -255,14 +311,17 @@ def try_parse_version(self, rawData, definition, start, length): found = False if found: - self.result[title] = value + self.set_state(key, value) + return def try_parse_datetime(self, rawData, definition, start, length): - title = definition["name"] + key = definition["name"] found = True value = "" + print("start: ", start) + for i,r in enumerate(definition["registers"]): index = r - start print ("index: ",index) @@ -280,13 +339,15 @@ def try_parse_datetime(self, rawData, definition, start, length): found = False if found: - self.result[title] = value + self.set_state(key, value) + return def try_parse_time(self, rawData, definition, start, length): - title = definition["name"] + key = definition["name"] found = True value = "" + for r in definition["registers"]: index = r - start if (index >= 0) and (index < length): @@ -296,14 +357,16 @@ def try_parse_time(self, rawData, definition, start, length): found = False if found: - self.result[title] = value + self.set_state(key, value) + return def try_parse_raw(self, rawData, definition, start, length): - title = definition['name'] + key = definition["name"] found = True value = [] - for r in definition['registers']: + + for r in definition["registers"]: index = r - start if (index >= 0) and (index < length): temp = rawData[index] @@ -312,18 +375,6 @@ def try_parse_raw(self, rawData, definition, start, length): found = False if found: - self.result[title] = value - return + self.set_state(key, value) - def num_to_result(self, title, value): - if self.is_integer_num(value): - self.result[title] = int(value) - else: - self.result[title] = round(value, FLOAT_ROUND_TO) - - def is_integer_num(self, n): - if isinstance(n, int): - return True - if isinstance(n, float): - return n.is_integer() - return False + return \ No newline at end of file diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 5c72134..a2fbf80 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -1,39 +1,35 @@ from __future__ import annotations import re -import string import logging import asyncio -import aiofiles import voluptuous as vol from homeassistant.core import HomeAssistant, callback -from homeassistant.const import CONF_NAME, EntityCategory from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_NAME, EntityCategory +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo, format_mac from homeassistant.helpers.entity import Entity from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo, format_mac from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import * from .common import * +from .api import Inverter from .discovery import InverterDiscovery from .coordinator import InverterCoordinator -from .api import Inverter from .services import * _LOGGER = logging.getLogger(__name__) -_FMT = string.Formatter() - -def _create_sensor(coordinator, inverter_name, inverter, sensor, config, disable_templating): +def _create_sensor(coordinator, sensor, battery_life_cycle_rating): try: if "artificial" in sensor: - entity = SolarmanStatus(coordinator, inverter_name, inverter, sensor["name"]) + entity = SolarmanStatus(coordinator, sensor) elif "isstr" in sensor: - entity = SolarmanSensorText(coordinator, inverter_name, inverter, sensor, config, disable_templating) + entity = SolarmanSensorBase(coordinator, sensor) else: - entity = SolarmanSensor(coordinator, inverter_name, inverter, sensor, config, disable_templating) + entity = SolarmanSensor(coordinator, sensor, battery_life_cycle_rating) entity.update() @@ -45,18 +41,15 @@ def _create_sensor(coordinator, inverter_name, inverter, sensor, config, disable async def async_setup(hass: HomeAssistant, config, async_add_entities: AddEntitiesCallback, id = None): _LOGGER.debug(f"async_setup: {config}") - lookup_path = hass.config.path(LOOKUP_DIRECTORY_PATH) - inverter_name = config.get(CONF_NAME) inverter_discovery = config.get(CONF_INVERTER_DISCOVERY) inverter_host = config.get(CONF_INVERTER_HOST) inverter_serial = config.get(CONF_INVERTER_SERIAL) inverter_port = config.get(CONF_INVERTER_PORT) inverter_mb_slave_id = config.get(CONF_INVERTER_MB_SLAVE_ID) + lookup_path = hass.config.path(LOOKUP_DIRECTORY_PATH) lookup_file = config.get(CONF_LOOKUP_FILE) - battery_nominal_voltage = config.get(CONF_BATTERY_NOMINAL_VOLTAGE) battery_life_cycle_rating = config.get(CONF_BATTERY_LIFE_CYCLE_RATING) - disable_templating = config.get(CONF_DISABLE_TEMPLATING) inverter_discovery = InverterDiscovery(hass, inverter_host) @@ -73,25 +66,15 @@ async def async_setup(hass: HomeAssistant, config, async_add_entities: AddEntiti if not inverter_mb_slave_id: inverter_mb_slave_id = DEFAULT_INVERTER_MB_SLAVE_ID - if not battery_nominal_voltage: - battery_nominal_voltage = DEFAULT_BATTERY_NOMINAL_VOLTAGE - - if not battery_life_cycle_rating: - battery_life_cycle_rating = DEFAULT_BATTERY_LIFE_CYCLE_RATING - - if not disable_templating: - disable_templating = DEFAULT_DISABLE_TEMPLATING - if inverter_host is None: raise vol.Invalid("configuration parameter [inverter_host] does not have a value") if inverter_serial is None: raise vol.Invalid("configuration parameter [inverter_serial] does not have a value") - inverter = Inverter(inverter_host, inverter_mac, inverter_serial, inverter_port, inverter_mb_slave_id, lookup_path, lookup_file) + inverter = Inverter(inverter_host, inverter_serial, inverter_port, inverter_mb_slave_id, inverter_name, inverter_mac, lookup_path, lookup_file) sensors = await inverter.get_sensors() - coordinator = InverterCoordinator(hass, inverter) - hass.data.setdefault(DOMAIN, {})[id] = coordinator + coordinator = InverterCoordinator(hass, inverter) # Fetch initial data so we have data when entities subscribe. # @@ -102,59 +85,60 @@ async def async_setup(hass: HomeAssistant, config, async_add_entities: AddEntiti # coordinator.async_refresh() instead. # _LOGGER.debug(f"async_setup: coordinator.async_config_entry_first_refresh") + await coordinator.async_config_entry_first_refresh() + # Add entities. + # _LOGGER.debug(f"async_setup: async_add_entities") - async_add_entities(_create_sensor(coordinator, inverter_name, inverter, sensor, { "Battery Nominal Voltage": battery_nominal_voltage, "Battery Life Cycle Rating": battery_life_cycle_rating }, disable_templating) for sensor in sensors) + async_add_entities(_create_sensor(coordinator, sensor, battery_life_cycle_rating) for sensor in sensors) + + # Register the services with home assistant. + # _LOGGER.debug(f"async_setup: register_services") - register_services(hass, inverter) + + hass.data.setdefault(DOMAIN, {})[id] = coordinator -# Set-up from configuration.yaml -#async def async_setup_platform(hass: HomeAssistant, config, async_add_entities: AddEntitiesCallback, discovery_info = None): -# _LOGGER.debug(f"async_setup_platform: {config}") -# await async_setup(hass, config, async_add_entities) + register_services(hass, inverter) -async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry, async_add_entities: AddEntitiesCallback) -> bool: - _LOGGER.debug(f"async_setup_entry: {entry.options}") - await async_setup(hass, entry.options, async_add_entities, entry.entry_id) +async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry, async_add_entities: AddEntitiesCallback) -> bool: + _LOGGER.debug(f"async_setup_entry: {config.options}") + await async_setup(hass, config.options, async_add_entities, config.entry_id) return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: - _LOGGER.debug(f"async_unload_entry: remove_services {entry.options}") +async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: + _LOGGER.debug(f"async_unload_entry: {config.options}") remove_services(hass) return True -class InverterCoordinatorEntity(CoordinatorEntity[InverterCoordinator]): - def __init__(self, coordinator: InverterCoordinator, id: str = None, device_name: str = None, device_lookup_file: str = None, manufacturer: str = None): +class SolarmanCoordinatorEntity(CoordinatorEntity[InverterCoordinator]): + def __init__(self, coordinator: InverterCoordinator, name: str = None): super().__init__(coordinator) - self.id = coordinator.inverter.serial - self.device_name = device_name - self.model = device_lookup_file.replace(".yaml", "") - + self.model = self.coordinator.inverter.lookup_file.replace(".yaml", "") + if '_' in self.model: dev_man = self.model.split('_') - self.model = dev_man[1].upper() self.manufacturer = dev_man[0].capitalize() + self.model = dev_man[1].upper() self._attr_device_info = { "connections": {(CONNECTION_NETWORK_MAC, format_mac(self.coordinator.inverter.mac))} - } if self.coordinator.inverter.mac else {} - - self._attr_device_info = self._attr_device_info | { - "identifiers": {(DOMAIN, self.id)}, - "name": self.device_name, + } if self.coordinator.inverter.mac else {} | { + "identifiers": {(DOMAIN, self.coordinator.inverter.serial)}, + "name": self.coordinator.inverter.name, + "manufacturer": self.manufacturer, "model": self.model, - "manufacturer": self.manufacturer + "serial_number": self.coordinator.inverter.serial } - self._attr_extra_state_attributes = { "id": self.id, "integration": DOMAIN } + #self._attr_extra_state_attributes = { "id": self.coordinator.inverter.serial, "integration": DOMAIN } + self._attr_extra_state_attributes = {} -class SolarmanStatus(InverterCoordinatorEntity): - def __init__(self, coordinator, inverter_name, inverter, field_name): - super().__init__(coordinator, inverter.serial, inverter_name, inverter.lookup_file) - self._inverter_name = inverter_name - self._field_name = field_name +class SolarmanStatus(SolarmanCoordinatorEntity): + def __init__(self, coordinator, sensor): + super().__init__(coordinator) + self.sensor_name = sensor["name"] # Return the category of the sensor. self._attr_entity_category = (EntityCategory.DIAGNOSTIC) @@ -163,10 +147,10 @@ def __init__(self, coordinator, inverter_name, inverter, field_name): self._attr_icon = "mdi:information" # Return the name of the sensor. - self._attr_name = "{} {}".format(self._inverter_name, self._field_name) + self._attr_name = "{} {}".format(self.coordinator.inverter.name, self.sensor_name) # Return a unique_id based on the serial number - self._attr_unique_id = "{}_{}_{}".format(self._inverter_name, self.coordinator.inverter.serial, self._field_name) + self._attr_unique_id = "{}_{}_{}".format(self.coordinator.inverter.name, self.coordinator.inverter.serial, self.sensor_name) @property def available(self) -> bool: @@ -185,16 +169,13 @@ def update(self): self._attr_state = self.coordinator.inverter.get_connection_status() self._attr_extra_state_attributes["updated"] = self.coordinator.inverter.status_lastUpdate -class SolarmanSensorText(SolarmanStatus): - def __init__(self, coordinator, inverter_name, inverter, sensor, config, disable_templating): - SolarmanStatus.__init__(self, coordinator, inverter_name, inverter, sensor["name"]) +class SolarmanSensorBase(SolarmanStatus): + def __init__(self, coordinator, sensor): + SolarmanStatus.__init__(self, coordinator, sensor) self._attr_entity_registry_enabled_default = not "disabled" in sensor - if "display_precision" in sensor: - self._attr_suggested_display_precision = sensor["display_precision"] - - if "display_precision" in sensor: - self._suggested_display_precision = sensor["display_precision"] + if "suggested_display_precision" in sensor: + self._attr_suggested_display_precision = sensor["suggested_display_precision"] if "state_class" in sensor and sensor["state_class"]: self._attr_extra_state_attributes = { "state_class": sensor["state_class"] } @@ -205,63 +186,34 @@ def __init__(self, coordinator, inverter_name, inverter, sensor, config, disable self.attributes = sensor["attributes"] if "attributes" in sensor else None - self.config = config - - self.is_ok = True - - self.params = sensor["params"] if "params" in sensor else None - - self.formula = sensor["formula"] if "formula" in sensor else None - - if not disable_templating: - if self.params and self.formula: - self.formula_pcount = len([p for p in _FMT.parse(self.formula) if p[2] is not None]) - if self.formula_pcount != len(self.params): - self.is_ok = False - _LOGGER.error(f"{self._field_name} template is not valid.") - elif "formula" in sensor: - self.is_ok = False - - def _lookup_param(self, p): - if p in self.coordinator.data: - return self.coordinator.data[p] - - if p in self.config: - return self.config[p] - - return 0 - def update(self): - if not self.is_ok: - return - c = len(self.coordinator.data) - if c > 1 or (c == 1 and self._field_name in self.coordinator.data): - if self._field_name in self.coordinator.data: - self._attr_state = self.coordinator.data[self._field_name] + if c > 1 or (c == 1 and self.sensor_name in self.coordinator.data): + if self.sensor_name in self.coordinator.data: + self._attr_state = self.coordinator.data[self.sensor_name]["state"] + if "value" in self.coordinator.data[self.sensor_name]: + self._attr_extra_state_attributes["value"] = self.coordinator.data[self.sensor_name]["value"] if self.attributes: for attr in self.attributes: if attr in self.coordinator.data: - attr_name = attr.replace(f"{self._field_name} ", "") - self._attr_extra_state_attributes[attr_name] = self.coordinator.data[attr] - if self._field_name + " enum" in self.coordinator.data: - self._attr_extra_state_attributes["Value"] = self.coordinator.data[self._field_name + " enum"] - elif self.formula: - if set(self.params) <= self.coordinator.data.keys() | self.config: - params = [self._lookup_param(p) for p in self.params] - if self.formula_pcount == len(params): - formula = self.formula.format(*params) - self._attr_state = eval(formula) - -class SolarmanSensor(SolarmanSensorText): - def __init__(self, coordinator, inverter_name, inverter, sensor, config, disable_templating): - SolarmanSensorText.__init__(self, coordinator, inverter_name, inverter, sensor, config, disable_templating) - - if device_class := sensor["class"]: + attr_name = attr.replace(f"{self.sensor_name} ", "") + self._attr_extra_state_attributes[attr_name] = self.coordinator.data[attr]["state"] + +class SolarmanSensor(SolarmanSensorBase): + def __init__(self, coordinator, sensor, battery_life_cycle_rating): + SolarmanSensorBase.__init__(self, coordinator, sensor) + + if "class" in sensor and (device_class := sensor["class"]): + self._attr_device_class = device_class + + if "device_class" in sensor and (device_class := sensor["device_class"]): self._attr_device_class = device_class - if unit_of_measurement := sensor["uom"]: + if "uom" in sensor and (unit_of_measurement := sensor["uom"]): + self._attr_unit_of_measurement = unit_of_measurement + + if "unit_of_measurement" in sensor and (unit_of_measurement := sensor["unit_of_measurement"]): self._attr_unit_of_measurement = unit_of_measurement - if sensor["name"] == "Battery": - self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Nominal Voltage": config["Battery Nominal Voltage"], "Life Cycle Rating": config["Battery Life Cycle Rating"] } \ No newline at end of file + if "name" in sensor and sensor["name"] == "Battery": + self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Life Cycle Rating": battery_life_cycle_rating } \ No newline at end of file diff --git a/custom_components/solarman/services.py b/custom_components/solarman/services.py index 0484c55..aed79e9 100644 --- a/custom_components/solarman/services.py +++ b/custom_components/solarman/services.py @@ -1,10 +1,6 @@ -from __future__ import annotations - -import voluptuous as vol - from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv - +import voluptuous as vol from .const import * from .api import Inverter From cbbe473a864b2240cbe00d4bb07345d9442cbb0d Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 16:29:28 +0200 Subject: [PATCH 04/39] fix: readme.md Diagnostics - added max() --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 9076af2..fc92763 100644 --- a/readme.md +++ b/readme.md @@ -76,7 +76,7 @@ template: - name: "Inverter Device Since Last update" unique_id: "inverter_device_since_last_update" availability: "{{ has_value('sensor.inverter_connection_status') }}" - state: "{{ (states('sensor.update_ticker') | float - as_timestamp(states.sensor.inverter_connection_status.last_updated)) | round(0, 'ceil') }}" + state: "{{ max((states('sensor.update_ticker') | float - as_timestamp(states.sensor.inverter_connection_status.last_updated)) | round(0, 'ceil'), 0) }}" state_class: "Measurement" device_class: "Duration" unit_of_measurement: "s" From cd23997dd4f4476477b432949b3997ad444334ad Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 16:38:01 +0200 Subject: [PATCH 05/39] chore: version bump --- custom_components/solarman/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/solarman/manifest.json b/custom_components/solarman/manifest.json index 21f0126..3a04488 100644 --- a/custom_components/solarman/manifest.json +++ b/custom_components/solarman/manifest.json @@ -9,5 +9,5 @@ "iot_class": "local_polling", "issue_tracker": "https://github.com/davidrapan/ha-solarman/issues", "requirements": ["ipaddress","pyyaml","pysolarmanv5>=3.0.2"], - "version": "24.07.04" + "version": "24.07.14" } From 639b47fc3b1bb12c6b279a5fcf72a4f856eee72e Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 17:34:12 +0200 Subject: [PATCH 06/39] refactor: services.py constants moved to const.py --- custom_components/solarman/const.py | 9 ++++++++- custom_components/solarman/services.py | 28 ++++++++++++-------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index 9186070..18c8159 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -41,4 +41,11 @@ TIMINGS_QUERY_INTERVAL_DEFAULT = 60 TIMINGS_QUERY_EXCEPT_SLEEP = 4 -DIGITS_DEFAULT = 6 \ No newline at end of file +DIGITS_DEFAULT = 6 + +SERVICES_PARAM_REGISTER = "register" +SERVICES_PARAM_VALUE = "value" +SERVICES_PARAM_VALUES = "values" + +SERVICE_WRITE_REGISTER = "write_holding_register" +SERVICE_WRITE_MULTIPLE_REGISTERS = "write_multiple_holding_registers" \ No newline at end of file diff --git a/custom_components/solarman/services.py b/custom_components/solarman/services.py index aed79e9..87a311a 100644 --- a/custom_components/solarman/services.py +++ b/custom_components/solarman/services.py @@ -1,44 +1,42 @@ +from __future__ import annotations + +import voluptuous as vol + from homeassistant.core import HomeAssistant from homeassistant.helpers import config_validation as cv -import voluptuous as vol + from .const import * from .api import Inverter -SERVICE_WRITE_REGISTER = "write_holding_register" -SERVICE_WRITE_MULTIPLE_REGISTERS = "write_multiple_holding_registers" -PARAM_REGISTER = "register" -PARAM_VALUE = "value" -PARAM_VALUES = "values" - # Register the services one can invoke on the inverter. # Apart from this, it also need to be defined in the file # services.yaml for the Home Assistant UI in "Developer Tools" SERVICE_WRITE_REGISTER_SCHEMA = vol.Schema( { - vol.Required(PARAM_REGISTER): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)), - vol.Required(PARAM_VALUE): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)), + vol.Required(SERVICES_PARAM_REGISTER): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)), + vol.Required(SERVICES_PARAM_VALUE): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)), } ) SERVICE_WRITE_MULTIPLE_REGISTERS_SCHEMA = vol.Schema( { - vol.Required(PARAM_REGISTER): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)), - vol.Required(PARAM_VALUES): vol.All(cv.ensure_list, [vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535))]), + vol.Required(SERVICES_PARAM_REGISTER): vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535)), + vol.Required(SERVICES_PARAM_VALUES): vol.All(cv.ensure_list, [vol.All(vol.Coerce(int), vol.Range(min = 0, max = 65535))]), } ) def register_services(hass: HomeAssistant, inverter: Inverter): async def write_holding_register(call) -> None: await inverter.service_write_holding_register( - register = call.data.get(PARAM_REGISTER), - value = call.data.get(PARAM_VALUE)) + register = call.data.get(SERVICES_PARAM_REGISTER), + value = call.data.get(SERVICES_PARAM_VALUE)) return async def write_multiple_holding_registers(call) -> None: await inverter.service_write_multiple_holding_registers( - register = call.data.get(PARAM_REGISTER), - values = call.data.get(PARAM_VALUES)) + register = call.data.get(SERVICES_PARAM_REGISTER), + values = call.data.get(SERVICES_PARAM_VALUES)) return hass.services.async_register( From e6838d41d23e6d00fc275ec42692230c95847489 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 17:45:10 +0200 Subject: [PATCH 07/39] refactor: discovery.py constants moved to const.py --- custom_components/solarman/const.py | 8 +++++++- custom_components/solarman/discovery.py | 12 +++++++----- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index 18c8159..c362a4c 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -4,7 +4,13 @@ PLATFORMS: list[str] = ["sensor"] SENSOR_PREFIX = "Solarman" +IP_BROADCAST = "" +IP_ANY = "0.0.0.0" + +PORT_ANY = 0 + DISCOVERY_PORT = 48899 +DISCOVERY_TIMEOUT = 1.0 DISCOVERY_MESSAGE = "WIFIKIT-214028-READ" DISCOVERY_RECV_MESSAGE_SIZE = 1024 @@ -48,4 +54,4 @@ SERVICES_PARAM_VALUES = "values" SERVICE_WRITE_REGISTER = "write_holding_register" -SERVICE_WRITE_MULTIPLE_REGISTERS = "write_multiple_holding_registers" \ No newline at end of file +SERVICE_WRITE_MULTIPLE_REGISTERS = "write_multiple_holding_registers" diff --git a/custom_components/solarman/discovery.py b/custom_components/solarman/discovery.py index 3c92d41..0a235a8 100644 --- a/custom_components/solarman/discovery.py +++ b/custom_components/solarman/discovery.py @@ -25,7 +25,7 @@ def __init__(self, hass: HomeAssistant, address = None): self._mac = None self._serial = None - async def _discover(self, address = "", source = "0.0.0.0"): + async def _discover(self, address = IP_BROADCAST, source = IP_ANY): loop = asyncio.get_running_loop() try: @@ -33,8 +33,10 @@ async def _discover(self, address = "", source = "0.0.0.0"): sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) sock.setsockopt(socket.SOL_SOCKET, socket.SO_BROADCAST, 1) sock.setblocking(False) - sock.settimeout(1.0) - #sock.bind((source, 0)) + sock.settimeout(DISCOVERY_TIMEOUT) + + if source != IP_ANY: + sock.bind((source, PORT_ANY)) await loop.sock_sendto(sock, self._message, (address, self._port)) @@ -64,7 +66,7 @@ async def _discover_all(self): _LOGGER.debug(f"_discover_all: Broadcasting on {net.with_prefixlen}") await self._discover(str(IPv4Network(net, False).broadcast_address)) - #await self._discover("", ipv4["address"]) + #await self._discover(IP_BROADCAST, ipv4["address"]) if self._ip is not None: return None @@ -95,4 +97,4 @@ async def get_mac(self): async def get_serial(self): if not self._serial: await self.discover() - return self._serial \ No newline at end of file + return self._serial From 349dd69d32d1652ba47540137dcfceca9074c8e6 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 18:16:00 +0200 Subject: [PATCH 08/39] refactor: parser.py get_requests set default state --- custom_components/solarman/parser.py | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/custom_components/solarman/parser.py b/custom_components/solarman/parser.py index 8921358..279ae1f 100644 --- a/custom_components/solarman/parser.py +++ b/custom_components/solarman/parser.py @@ -1,5 +1,6 @@ from __future__ import annotations +import re import struct import logging @@ -42,6 +43,19 @@ def is_requestable(self, parameters): def is_scheduled(self, parameters, runtime): return "realtime" in parameters or (runtime % (parameters["update_interval"] if "update_interval" in parameters else self._update_interval) == 0) + def default_from_unit_of_measurement(self, parameters): + return None if (uom := parameters["uom"] if "uom" in parameters else (parameters["unit_of_measurement"] if "unit_of_measurement" in parameters else "")) and re.match(r"\S+", uom) else "" + + def set_state(self, key, value): + self._result[key] = {} + self._result[key]["state"] = value + + def set_state_number(self, key, value, digits): + if isinstance(value, int) or (isinstance(value, float) and value.is_integer()): + self.set_state(key, int(value)) + else: + self.set_state(key, round(value, digits)) + def get_sensors(self): result = [{"name": "Connection Status", "artificial": ""}] for i in self.lookup(): @@ -60,8 +74,7 @@ def get_requests(self, runtime = 0): for i in self.lookup(): for j in i["items"]: if self.is_requestable(j) and self.is_scheduled(j, runtime): - self._result[j["name"]] = {} - self._result[j["name"]]["state"] = "" + self.set_state(j["name"], self.default_from_unit_of_measurement(j)) for r in j["registers"]: registers.append(r) @@ -79,16 +92,6 @@ def parse(self, rawData, start, length): return - def set_state(self, key, value): - self._result[key] = {} - self._result[key]["state"] = value - - def set_state_number(self, key, value, digits): - if isinstance(value, int) or (isinstance(value, float) and value.is_integer()): - self.set_state(key, int(value)) - else: - self.set_state(key, round(value, digits)) - def get_result(self): return self._result From c5d330ddc016e999d2cb9ae2d476846a6e7275d2 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 19:59:27 +0200 Subject: [PATCH 09/39] refactor: Standardized request format using consts --- custom_components/solarman/api.py | 6 +++--- custom_components/solarman/common.py | 11 +++++++++++ 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index e7d8fc3..5846e8d 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -167,9 +167,9 @@ async def async_get(self, runtime = 0): try: for request in requests: - code = request["mb_functioncode"] - start = request["start"] - end = request["end"] + code = get_request_code(request) + start = get_request_start(request) + end = get_request_end(request) _LOGGER.debug(f"Querying ({start} - {end}) ...") diff --git a/custom_components/solarman/common.py b/custom_components/solarman/common.py index 8c71d1b..955ce40 100644 --- a/custom_components/solarman/common.py +++ b/custom_components/solarman/common.py @@ -1,5 +1,7 @@ import asyncio +from .const import * + async def async_execute(x): loop = asyncio.get_running_loop() return await loop.run_in_executor(None, x) @@ -18,3 +20,12 @@ def format_exception(e): def Raise(exception) -> None: raise exception + +def get_request_code(request): + return request[REQUEST_CODE] if REQUEST_CODE in request else request[REQUEST_CODE_ALT] + +def get_request_start(request): + return request[REQUEST_START] + +def get_request_end(request): + return request[REQUEST_END] \ No newline at end of file From 2fafedfde24bb833bd3781c6f34e85100a9ff696 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 20:01:39 +0200 Subject: [PATCH 10/39] refactor: parser.py constants moved to const.py --- custom_components/solarman/const.py | 8 +++++++- custom_components/solarman/coordinator.py | 2 +- custom_components/solarman/parser.py | 13 ++++++++----- 3 files changed, 16 insertions(+), 7 deletions(-) diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index c362a4c..1614896 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -47,7 +47,13 @@ TIMINGS_QUERY_INTERVAL_DEFAULT = 60 TIMINGS_QUERY_EXCEPT_SLEEP = 4 -DIGITS_DEFAULT = 6 +REGISTERS_MIN_SPAN_DEFAULT = 25 +REGISTERS_DIGITS_DEFAULT = 6 + +REQUEST_CODE = "code" +REQUEST_CODE_ALT = "mb_functioncode" +REQUEST_START = "start" +REQUEST_END = "end" SERVICES_PARAM_REGISTER = "register" SERVICES_PARAM_VALUE = "value" diff --git a/custom_components/solarman/coordinator.py b/custom_components/solarman/coordinator.py index 68f8fbd..6904caf 100644 --- a/custom_components/solarman/coordinator.py +++ b/custom_components/solarman/coordinator.py @@ -22,7 +22,7 @@ def _accounting(self): if self.last_update_success: self.counter += 1 - # Temporary fix to retrieve all data after disconnect + # Temporary fix to retrieve all data after reconnect if self.inverter.status != 1: self.counter = 0 diff --git a/custom_components/solarman/parser.py b/custom_components/solarman/parser.py index 279ae1f..ed3b547 100644 --- a/custom_components/solarman/parser.py +++ b/custom_components/solarman/parser.py @@ -13,23 +13,26 @@ class ParameterParser: def __init__(self, parameter_definition): self._lookups = parameter_definition self._update_interval = TIMINGS_QUERY_INTERVAL_DEFAULT - self._digits = DIGITS_DEFAULT + self._min_span = REGISTERS_MIN_SPAN_DEFAULT + self._digits = REGISTERS_DIGITS_DEFAULT self._result = {} if "default" in parameter_definition: default = parameter_definition["default"] if "update_interval" in default: self._update_interval = default["update_interval"] + if "min_span" in default: + self._min_span = default["min_span"] if "digits" in default: self._digits = default["digits"] - _LOGGER.debug(f"Default update_interval: {self._update_interval}, digits: {self._digits}") + _LOGGER.debug(f"Default update_interval: {self._update_interval}, min_span: {self._min_span}, digits: {self._digits}") def lookup(self): return self._lookups["parameters"] def is_valid(self, parameters): - return "name" in parameters and "rule" in parameters + return "name" in parameters and "rule" in parameters # and "registers" in parameters def is_enabled(self, parameters): return not "disabled" in parameters @@ -80,9 +83,9 @@ def get_requests(self, runtime = 0): registers.sort() - groups = group_when(registers, lambda x, y: y - x > 25) + groups = group_when(registers, lambda x, y: y - x > self._min_span) - return [{ "start": r[0], "end": r[-1], "mb_functioncode": 0x03 } for r in groups] + return [{ REQUEST_START: r[0], REQUEST_END: r[-1], REQUEST_CODE: 0x03 } for r in groups] def parse(self, rawData, start, length): for i in self.lookup(): From 2dc54b3f09eb76359ccb76cbf9a13f56ce824a6f Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 20:27:27 +0200 Subject: [PATCH 11/39] feat: Added SmartLoad State entity --- .../inverter_definitions/deye_sg01hp3.yaml | 26 ++++++++++++++++++- .../inverter_definitions/deye_sg04lp3.yaml | 26 ++++++++++++++++++- .../deye_sun-12k-sg04lp3.yaml | 26 ++++++++++++++++++- 3 files changed, 75 insertions(+), 3 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 1ec94cf..eb9b696 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -330,6 +330,31 @@ parameters: min: 0 max: 100 + - name: "SmartLoad State" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0228] + icon: "mdi:lightning-bolt-circle" + isstr: true + lookup: + - key: 0x0001 + value: "Off" + - key: 0x0004 + value: "Off" + - key: 0x0005 + value: "Off" + - key: 0x0008 + value: "On" + - key: 0x0009 + value: "On" + - key: 0x000C + value: "Off" + - key: 0x000D + value: "On" + - group: BMS items: - name: "BMS Charging Voltage" @@ -794,7 +819,6 @@ parameters: registers: [0x0228] icon: "mdi:information" isstr: true - lookup_default: "X-grid" lookup: - key: 0x0001 value: "Off-grid" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index f27ada6..acaac60 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -335,6 +335,31 @@ parameters: min: 0 max: 100 + - name: "SmartLoad State" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0228] + icon: "mdi:lightning-bolt-circle" + isstr: true + lookup: + - key: 0x0001 + value: "Off" + - key: 0x0004 + value: "Off" + - key: 0x0005 + value: "Off" + - key: 0x0008 + value: "On" + - key: 0x0009 + value: "On" + - key: 0x000C + value: "Off" + - key: 0x000D + value: "On" + - group: BMS items: - name: "BMS Charged Voltage" @@ -793,7 +818,6 @@ parameters: registers: [0x0228] icon: "mdi:information" isstr: true - lookup_default: "X-grid" lookup: - key: 0x0001 value: "Off-grid" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 78012bb..d77ae1a 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -338,6 +338,31 @@ parameters: min: 0 max: 100 + - name: "SmartLoad State" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0228] + icon: "mdi:lightning-bolt-circle" + isstr: true + lookup: + - key: 0x0001 + value: "Off" + - key: 0x0004 + value: "Off" + - key: 0x0005 + value: "Off" + - key: 0x0008 + value: "On" + - key: 0x0009 + value: "On" + - key: 0x000C + value: "Off" + - key: 0x000D + value: "On" + - group: BMS items: - name: "BMS Charged Voltage" @@ -826,7 +851,6 @@ parameters: registers: [0x0228] icon: "mdi:information" isstr: true - lookup_default: "X-grid" lookup: - key: 0x0001 value: "Off-grid" From bdb87050993fb64483cccad71676654a2b9b9307 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 22:17:18 +0200 Subject: [PATCH 12/39] refactor: Config/Options flow - Removed Disable Templating item - Removed Name item from Options flow --- custom_components/solarman/config_flow.py | 16 +++++++--------- custom_components/solarman/const.py | 2 -- custom_components/solarman/translations/de.json | 6 ++---- custom_components/solarman/translations/en.json | 6 ++---- custom_components/solarman/translations/it.json | 6 ++---- custom_components/solarman/translations/pl.json | 6 ++---- .../solarman/translations/pt-BR.json | 6 ++---- 7 files changed, 17 insertions(+), 31 deletions(-) diff --git a/custom_components/solarman/config_flow.py b/custom_components/solarman/config_flow.py index c2f8585..e041703 100644 --- a/custom_components/solarman/config_flow.py +++ b/custom_components/solarman/config_flow.py @@ -30,14 +30,14 @@ async def async_update_listener(hass: HomeAssistant, entry: ConfigEntry) -> None async def step_user_data_process(discovery): _LOGGER.debug(f"step_user_data_process: discovery: {discovery}") - return { CONF_NAME: DEFAULT_NAME, CONF_INVERTER_DISCOVERY: DEFAULT_DISCOVERY, CONF_INVERTER_HOST: await discovery.get_ip(), CONF_INVERTER_SERIAL: await discovery.get_serial(), CONF_INVERTER_PORT: DEFAULT_PORT_INVERTER, CONF_INVERTER_MB_SLAVE_ID: DEFAULT_INVERTER_MB_SLAVE_ID, CONF_LOOKUP_FILE: DEFAULT_LOOKUP_FILE, CONF_BATTERY_NOMINAL_VOLTAGE: DEFAULT_BATTERY_NOMINAL_VOLTAGE, CONF_BATTERY_LIFE_CYCLE_RATING: DEFAULT_BATTERY_LIFE_CYCLE_RATING, CONF_DISABLE_TEMPLATING: DEFAULT_DISABLE_TEMPLATING } + return { CONF_NAME: DEFAULT_NAME, CONF_INVERTER_DISCOVERY: DEFAULT_DISCOVERY, CONF_INVERTER_HOST: await discovery.get_ip(), CONF_INVERTER_SERIAL: await discovery.get_serial(), CONF_INVERTER_PORT: DEFAULT_PORT_INVERTER, CONF_INVERTER_MB_SLAVE_ID: DEFAULT_INVERTER_MB_SLAVE_ID, CONF_LOOKUP_FILE: DEFAULT_LOOKUP_FILE, CONF_BATTERY_NOMINAL_VOLTAGE: DEFAULT_BATTERY_NOMINAL_VOLTAGE, CONF_BATTERY_LIFE_CYCLE_RATING: DEFAULT_BATTERY_LIFE_CYCLE_RATING } -async def step_user_data_schema(hass: HomeAssistant, data: dict[str, Any] = { CONF_NAME: DEFAULT_NAME, CONF_INVERTER_DISCOVERY: DEFAULT_DISCOVERY, CONF_INVERTER_PORT: DEFAULT_PORT_INVERTER, CONF_INVERTER_MB_SLAVE_ID: DEFAULT_INVERTER_MB_SLAVE_ID, CONF_LOOKUP_FILE: DEFAULT_LOOKUP_FILE, CONF_BATTERY_NOMINAL_VOLTAGE: DEFAULT_BATTERY_NOMINAL_VOLTAGE, CONF_BATTERY_LIFE_CYCLE_RATING: DEFAULT_BATTERY_LIFE_CYCLE_RATING, CONF_DISABLE_TEMPLATING: DEFAULT_DISABLE_TEMPLATING }) -> Schema: +async def step_user_data_schema(hass: HomeAssistant, data: dict[str, Any] = { CONF_NAME: DEFAULT_NAME, CONF_INVERTER_DISCOVERY: DEFAULT_DISCOVERY, CONF_INVERTER_PORT: DEFAULT_PORT_INVERTER, CONF_INVERTER_MB_SLAVE_ID: DEFAULT_INVERTER_MB_SLAVE_ID, CONF_LOOKUP_FILE: DEFAULT_LOOKUP_FILE, CONF_BATTERY_NOMINAL_VOLTAGE: DEFAULT_BATTERY_NOMINAL_VOLTAGE, CONF_BATTERY_LIFE_CYCLE_RATING: DEFAULT_BATTERY_LIFE_CYCLE_RATING }, wname: bool = True) -> vol.Schema: lookup_files = sorted([f for f in await async_execute(lambda: os.listdir(hass.config.path(LOOKUP_DIRECTORY_PATH))) if os.path.isfile(LOOKUP_DIRECTORY_PATH + f)]) _LOGGER.debug(f"step_user_data_schema: data: {data}, {LOOKUP_DIRECTORY_PATH}: {lookup_files}") - STEP_USER_DATA_SCHEMA = vol.Schema( + STEP_USER_DATA_SCHEMA = vol.Schema({ vol.Required(CONF_NAME, default = data.get(CONF_NAME)): str }, extra = vol.PREVENT_EXTRA) if wname else vol.Schema({}, extra = vol.PREVENT_EXTRA) + STEP_USER_DATA_SCHEMA = STEP_USER_DATA_SCHEMA.extend( { - vol.Required(CONF_NAME, default = data.get(CONF_NAME)): str, vol.Required(CONF_INVERTER_DISCOVERY, default = data.get(CONF_INVERTER_DISCOVERY)): bool, vol.Required(CONF_INVERTER_HOST, default = data.get(CONF_INVERTER_HOST)): str, vol.Required(CONF_INVERTER_SERIAL, default = data.get(CONF_INVERTER_SERIAL)): int, @@ -46,9 +46,7 @@ async def step_user_data_schema(hass: HomeAssistant, data: dict[str, Any] = { CO vol.Optional(CONF_LOOKUP_FILE, default = data.get(CONF_LOOKUP_FILE)): vol.In(lookup_files), vol.Optional(CONF_BATTERY_NOMINAL_VOLTAGE, default = data.get(CONF_BATTERY_NOMINAL_VOLTAGE)): int, vol.Optional(CONF_BATTERY_LIFE_CYCLE_RATING, default = data.get(CONF_BATTERY_LIFE_CYCLE_RATING)): int, - vol.Optional(CONF_DISABLE_TEMPLATING, default = data.get(CONF_DISABLE_TEMPLATING)): bool, - }, - extra = vol.PREVENT_EXTRA + } ) _LOGGER.debug(f"step_user_data_schema: STEP_USER_DATA_SCHEMA: {STEP_USER_DATA_SCHEMA}") return STEP_USER_DATA_SCHEMA @@ -134,7 +132,7 @@ async def async_step_init(self, user_input: dict[str, Any] | None = None) -> Con """Handle options flow.""" _LOGGER.debug(f"OptionsFlowHandler.async_step_init: {user_input}") if user_input is None: - return self.async_show_form(step_id = "init", data_schema = await step_user_data_schema(self.hass, self.entry.options)) + return self.async_show_form(step_id = "init", data_schema = await step_user_data_schema(self.hass, self.entry.options, False)) errors = {} @@ -150,7 +148,7 @@ async def async_step_init(self, user_input: dict[str, Any] | None = None) -> Con else: return self.async_create_entry(title = info["title"], data = user_input) - return self.async_show_form(step_id = "init", data_schema = await step_user_data_schema(self.hass, user_input), errors = errors) + return self.async_show_form(step_id = "init", data_schema = await step_user_data_schema(self.hass, user_input, False), errors = errors) class InvalidHost(HomeAssistantError): """Error to indicate there is invalid hostname or IP address.""" diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index 1614896..927c3f4 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -27,7 +27,6 @@ CONF_LOOKUP_FILE = "lookup_file" CONF_BATTERY_NOMINAL_VOLTAGE = "battery_nominal_voltage" CONF_BATTERY_LIFE_CYCLE_RATING = "battery_life_cycle_rating" -CONF_DISABLE_TEMPLATING = "disable_templating" DEFAULT_NAME = "Inverter" DEFAULT_DISCOVERY = True @@ -36,7 +35,6 @@ DEFAULT_LOOKUP_FILE = "deye_hybrid.yaml" DEFAULT_BATTERY_NOMINAL_VOLTAGE = 48 DEFAULT_BATTERY_LIFE_CYCLE_RATING = 6000 -DEFAULT_DISABLE_TEMPLATING = False ACTION_RETRY_ATTEMPTS = 5 diff --git a/custom_components/solarman/translations/de.json b/custom_components/solarman/translations/de.json index 4aaf830..d5f4d4a 100644 --- a/custom_components/solarman/translations/de.json +++ b/custom_components/solarman/translations/de.json @@ -20,8 +20,7 @@ "mb_slave_id": "Modbus-Slave-ID (normalerweise 1)", "lookup_file": "YAML-Datei mit der Parameter-Definition", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", @@ -47,8 +46,7 @@ "mb_slave_id": "Modbus-Slave-ID (normalerweise 1)", "lookup_file": "YAML-Datei mit der Parameter-Definition", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", diff --git a/custom_components/solarman/translations/en.json b/custom_components/solarman/translations/en.json index 9c100b7..5152ce2 100644 --- a/custom_components/solarman/translations/en.json +++ b/custom_components/solarman/translations/en.json @@ -20,8 +20,7 @@ "mb_slave_id": "Modbus Slave ID (usually 1)", "lookup_file": "The yaml file containing inverter parameter definitions", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", @@ -48,8 +47,7 @@ "mb_slave_id": "Modbus Slave ID (usually 1)", "lookup_file": "The yaml file containing inverter parameter definitions", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", diff --git a/custom_components/solarman/translations/it.json b/custom_components/solarman/translations/it.json index b7d9ddf..1a038cd 100644 --- a/custom_components/solarman/translations/it.json +++ b/custom_components/solarman/translations/it.json @@ -20,8 +20,7 @@ "mb_slave_id": "Slave ID di Modbus (solitamente 1)", "lookup_file": "File YAML contenente la definizione Inverter", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", @@ -48,8 +47,7 @@ "mb_slave_id": "Slave ID di Modbus (solitamente 1)", "lookup_file": "File YAML contenente la definizione Inverter", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", diff --git a/custom_components/solarman/translations/pl.json b/custom_components/solarman/translations/pl.json index 6bc756c..f954c17 100644 --- a/custom_components/solarman/translations/pl.json +++ b/custom_components/solarman/translations/pl.json @@ -20,8 +20,7 @@ "mb_slave_id": "Modbus Slave ID (zwykle 1)", "lookup_file": "Plik yaml u\u017cywany do definiowania parametr\u00f3w", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", @@ -48,8 +47,7 @@ "mb_slave_id": "Modbus Slave ID (zwykle 1)", "lookup_file": "Plik yaml u\u017cywany do definiowania parametr\u00f3w", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", diff --git a/custom_components/solarman/translations/pt-BR.json b/custom_components/solarman/translations/pt-BR.json index dc1fc48..cc10113 100644 --- a/custom_components/solarman/translations/pt-BR.json +++ b/custom_components/solarman/translations/pt-BR.json @@ -20,8 +20,7 @@ "mb_slave_id": "Modbus Slave ID (geralmente 1)", "lookup_file": "O arquivo yaml a ser usado para definição de parâmetro", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", @@ -48,8 +47,7 @@ "mb_slave_id": "Modbus Slave ID (geralmente 1)", "lookup_file": "O arquivo yaml a ser usado para definição de parâmetro", "battery_nominal_voltage": "Lithium-ion battery nominal voltage", - "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating", - "disable_templating": "Disable template sensors" + "battery_life_cycle_rating": "Lithium-ion battery expected life cycle rating" }, "data_description": { "inverter_host": "The hostname or IP address of the device to connect to.", From f1b80fae5b805258a4516fbffe0521719fe8b46c Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 22:44:35 +0200 Subject: [PATCH 13/39] feat: Add SmartLoad/Gen voltage and power entities --- .../inverter_definitions/deye_sg01hp3.yaml | 81 ++++++++++++++++-- .../inverter_definitions/deye_sg04lp3.yaml | 83 +++++++++++++++++-- .../deye_sun-12k-sg04lp3.yaml | 81 ++++++++++++++++-- 3 files changed, 226 insertions(+), 19 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index eb9b696..44f0c1b 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -1052,7 +1052,7 @@ parameters: registers: [0x025E, 0x02BE] icon: "mdi:transmission-tower" - # Grid internal - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid internal - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Internal Power" realtime: class: "power" @@ -1156,7 +1156,7 @@ parameters: registers: [0x026A, 0x02C3] icon: "mdi:transmission-tower" - # Grid external - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid external - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "External Power" realtime: class: "power" @@ -1201,7 +1201,7 @@ parameters: registers: [0x0270, 0x02B1] icon: "mdi:transmission-tower" - # Grid - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" realtime: class: "measurement" @@ -1302,7 +1302,7 @@ parameters: rule: 4 registers: [0x027B, 0x02B5] - # Inverter output - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Inverter output - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Inverter Power" realtime: class: "power" @@ -1377,7 +1377,7 @@ parameters: registers: [0x0282, 0x02BA] icon: "mdi:home-lightning-bolt" - # UPS output - Total active power is U16bit (low 16 bits) + U16bit (high 16 bits) + # UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) - name: "UPS Power" realtime: class: "power" @@ -1445,7 +1445,7 @@ parameters: rule: 2 registers: [0x028C, 0x0292] - # Load - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" realtime: class: "power" @@ -1455,6 +1455,75 @@ parameters: rule: 2 registers: [0x028D, 0x0293] + - group: SmartLoad/Generator + items: + # SmartLoad/Generator - The voltage of phase A + - name: "SmartLoad L1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0295] + + # SmartLoad/Generator - The voltage of phase B + - name: "SmartLoad L2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0296] + + # SmartLoad/Generator - The voltage of phase C + - name: "SmartLoad L3 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0297] + + # Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L1 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x0298, 0x029C] + + # SmartLoad/Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L2 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x0299, 0x029D] + + # SmartLoad/Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L3 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x029A, 0x029E] + + # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x029B, 0x029F] + - group: Photovoltaic items: # Photovoltaic - The combined power of Input 1 & 2 diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index acaac60..42ed541 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -1028,7 +1028,7 @@ parameters: registers: [0x025E, 0x02BE] icon: "mdi:transmission-tower" - # Grid internal - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid internal - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Internal Power" realtime: class: "power" @@ -1132,7 +1132,7 @@ parameters: registers: [0x026A, 0x02C3] icon: "mdi:transmission-tower" - # Grid external - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid external - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "External Power" realtime: class: "power" @@ -1177,7 +1177,7 @@ parameters: registers: [0x0270, 0x02B1] icon: "mdi:transmission-tower" - # Grid - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" realtime: class: "measurement" @@ -1274,7 +1274,7 @@ parameters: rule: 4 registers: [0x027B, 0x02B5] - # Inverter output - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Inverter output - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Inverter Power" realtime: class: "power" @@ -1301,7 +1301,7 @@ parameters: signed: registers: [0x027C, 0x02B6] - # Inverter output - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Inverter - Frequency - name: "Inverter Frequency" realtime: class: "frequency" @@ -1346,7 +1346,7 @@ parameters: registers: [0x0282, 0x02BA] icon: "mdi:home-lightning-bolt" - # UPS output - Total active power is U16bit (low 16 bits) + U16bit (high 16 bits) + # UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) - name: "UPS Power" realtime: class: "power" @@ -1414,7 +1414,7 @@ parameters: rule: 2 registers: [0x028C, 0x0292] - # Load - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" realtime: class: "power" @@ -1424,6 +1424,75 @@ parameters: rule: 2 registers: [0x028D, 0x0293] + - group: SmartLoad/Generator + items: + # SmartLoad/Generator - The voltage of phase A + - name: "SmartLoad L1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0295] + + # SmartLoad/Generator - The voltage of phase B + - name: "SmartLoad L2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0296] + + # SmartLoad/Generator - The voltage of phase C + - name: "SmartLoad L3 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0297] + + # Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L1 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x0298, 0x029C] + + # SmartLoad/Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L2 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x0299, 0x029D] + + # SmartLoad/Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L3 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x029A, 0x029E] + + # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x029B, 0x029F] + - group: Photovoltaic items: # Photovoltaic - The combined power of Input 1 & 2 diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index d77ae1a..62fc095 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -1090,7 +1090,7 @@ parameters: registers: [0x025E, 0x02BE] icon: "mdi:transmission-tower" - # Grid internal - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid internal - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Internal Power" realtime: class: "power" @@ -1194,7 +1194,7 @@ parameters: registers: [0x026A, 0x02C3] icon: "mdi:transmission-tower" - # Grid external - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid external - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "External Power" realtime: class: "power" @@ -1239,7 +1239,7 @@ parameters: registers: [0x0270, 0x02B1] icon: "mdi:transmission-tower" - # Grid - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" realtime: class: "measurement" @@ -1337,7 +1337,7 @@ parameters: rule: 4 registers: [0x027B, 0x02B5] - # Inverter output - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Inverter output - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Inverter Power" realtime: class: "power" @@ -1409,7 +1409,7 @@ parameters: registers: [0x0282, 0x02BA] icon: "mdi:home-lightning-bolt" - # UPS output - Total active power is U16bit (low 16 bits) + U16bit (high 16 bits) + # UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) - name: "UPS Power" realtime: class: "power" @@ -1477,7 +1477,7 @@ parameters: rule: 2 registers: [0x028C, 0x0292] - # Load - Total active power is S16bit (low 16 bits) + S16bit (high 16 bits) + # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" realtime: class: "power" @@ -1487,6 +1487,75 @@ parameters: rule: 2 registers: [0x028D, 0x0293] + - group: SmartLoad/Generator + items: + # SmartLoad/Generator - The voltage of phase A + - name: "SmartLoad L1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0295] + + # SmartLoad/Generator - The voltage of phase B + - name: "SmartLoad L2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0296] + + # SmartLoad/Generator - The voltage of phase C + - name: "SmartLoad L3 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0297] + + # Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L1 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x0298, 0x029C] + + # SmartLoad/Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L2 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x0299, 0x029D] + + # SmartLoad/Generator - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad L3 Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x029A, 0x029E] + + # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "SmartLoad Power" + realtime: + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + registers: [0x029B, 0x029F] + - group: Photovoltaic items: # Photovoltaic - The combined power of Input 1 & 2 From e1bda5c13d9c1f1d17f0e558d54c57da3181e593 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Sun, 14 Jul 2024 23:35:04 +0200 Subject: [PATCH 14/39] fix: Extended PV Power to include all inputs --- .../solarman/inverter_definitions/deye_sg01hp3.yaml | 8 ++++++-- .../solarman/inverter_definitions/deye_sg04lp3.yaml | 6 ++++-- .../inverter_definitions/deye_sun-12k-sg04lp3.yaml | 6 ++++-- 3 files changed, 14 insertions(+), 6 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 44f0c1b..c25d069 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -1526,7 +1526,7 @@ parameters: - group: Photovoltaic items: - # Photovoltaic - The combined power of Input 1 & 2 + # Photovoltaic - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" realtime: class: "power" @@ -1534,12 +1534,16 @@ parameters: uom: "W" rule: 1 digits: 0 - registers: [0x02A0, 0x02A1] + registers: [0x02A0, 0x02A1, 0x02A2, 0x02A3] sensors: - scale: 10 registers: [0x02A0] - scale: 10 registers: [0x02A1] + - scale: 10 + registers: [0x02A2] + - scale: 10 + registers: [0x02A3] icon: "mdi:solar-power-variant" # Photovoltaic - The power of Input 1 (L:1W, H:10W) diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 42ed541..9a65866 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -1495,7 +1495,7 @@ parameters: - group: Photovoltaic items: - # Photovoltaic - The combined power of Input 1 & 2 + # Photovoltaic - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" realtime: class: "power" @@ -1503,10 +1503,12 @@ parameters: uom: "W" rule: 1 digits: 0 - registers: [0x02A0, 0x02A1] + registers: [0x02A0, 0x02A1, 0x02A2, 0x02A3] sensors: - registers: [0x02A0] - registers: [0x02A1] + - registers: [0x02A2] + - registers: [0x02A3] icon: "mdi:solar-power-variant" # Photovoltaic - The power of Input 1 (L:1W, H:10W) diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 62fc095..467b31d 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -1558,7 +1558,7 @@ parameters: - group: Photovoltaic items: - # Photovoltaic - The combined power of Input 1 & 2 + # Photovoltaic - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" realtime: class: "power" @@ -1566,10 +1566,12 @@ parameters: uom: "W" rule: 1 digits: 0 - registers: [0x02A0, 0x02A1] + registers: [0x02A0, 0x02A1, 0x02A2, 0x02A3] sensors: - registers: [0x02A0] - registers: [0x02A1] + - registers: [0x02A2] + - registers: [0x02A3] icon: "mdi:solar-power-variant" # Photovoltaic - The power of Input 1 (L:1W, H:10W) From 40e7199898621444de6c9763e0412af583de274c Mon Sep 17 00:00:00 2001 From: David Rapan Date: Mon, 15 Jul 2024 02:59:44 +0200 Subject: [PATCH 15/39] refactor: readme.md --- readme.md | 57 +++++++++++++++++++++++-------------------------------- 1 file changed, 24 insertions(+), 33 deletions(-) diff --git a/readme.md b/readme.md index fc92763..a41bc86 100644 --- a/readme.md +++ b/readme.md @@ -1,46 +1,37 @@ -# Solarman integration +# ⚡ Solarman Stick Logger integration -Integration for Solarman Stick Logger +> [!NOTE] +> Use 💬 Discussions for 🙏 Q&A and 💡 Development Planning, etc. and leave 🚩 Issues for 🐞 bug reporting, 🎁 feature requests and such... + +> [!NOTE] +> It's still 🚧 work in progress but currently very 🐎 stable 😉 +> *I mean at least for my device as I'm not able to* 🧪 *test it for any other so any* 🧍 *volunteers?* 😊 > [!IMPORTANT] > This integration builds on and is heavily inspired by [@StephanJoubert](https://github.com/StephanJoubert/home_assistant_solarman) (but W/ decent amount of changes): > - Using asynchronous part of [@jmccrohan](https://github.com/jmccrohan/pysolarmanv5) + small adjustments to the inner workings of the library itself > - Fetching is implemented through DataUpdateCoordinator + incorporates many more up to date features of HA > - Improved stability (no more disconnects and missing values) -> > - Discovery and not just for configuration but also as part of initialization (i.e. adapts to changed IP) -> > - Registers which are requested are decided dynamically (when missing from the inverter definition file) > - Different registers can be requested in different intervals according to their 'update_interval' set in inverter definition file -> -> - Added attribute type of a sensor which can be attached to any other sensor -> - Added template sensors defined by simple formulas and parameters which are then evaluated during runtime -> - Added configuration for Battery Nominal Voltage and Battery Life Cycle Rating for calculating SOH of the battery -> - *All this new features can be seen utilized in the 'deye_sg04lp3.yaml'* -> +> - New Inverter profiles features **See 'deye_sg04lp3.yaml' for examples*: +> - Added attribute type of a sensor which can be attached to any other sensor +> - Added template sensors defined by simple formulas and parameters which are then evaluated during runtime +> - Added configuration for Battery Nominal Voltage and Battery Life Cycle Rating for calculating SOH of the battery > - And many more fixes and improvements (while trying to fully preserve backward compatibility) > [!WARNING] > Is note worthy that some names of the SG04LP3 sensors did change for different reasons (some were due to aestetics, etc.) -> So look through the file and change them as you see fit manually before I'll make it available from the HA configuration. -> -> One more thing.. It's not possible to use this integration side by side (with the same device) with the implementation from Stephan! It will override it. - -> [!NOTE] -> It's still work in progress but I'm now over 3 weeks of uptime so it's really stable ;) -> -> *I mean at least for my device as I'm not able to test it for any other so any volunteers?* -> -> ... - -> [!WARNING] -> TODO: Rest of the info :-D +> So look through the file and change them as you see fit manually before I'll make it available from the HA configuration. +> One more thing.. It's not possible to use this integration side by side (with the same device) with the implementation from Stephan! It will override it. +> TODO: Rest of the info... 😃 -## Miscellaneous +## 🚀 Miscellaneous -Some might wonder why Energy Dashboard shows different(higher) Load Consumption than sensor like for example "Today(Daily) Load Consumption. And it's because the Energy Dashboard does it's own calculations by summing up Imported(Bought) and Produced energy which also includes consumption of the inverter itself + some AC/DC losses along the way." +Some might wonder why Energy Dashboard shows different(higher) Load Consumption than sensor like for example "Today(Daily) Load Consumption. And it's because the Energy Dashboard does it's own calculations by summing up Imported(Bought) and Produced energy which also includes consumption of the inverter itself + some AC/DC losses along the way." -_So for those curious enough here is some insight..._ +_So for those curious enough here is some insight..._ #### Inverter power losses calculation [W]: ``` @@ -57,9 +48,9 @@ Total losses = Total Energy Imported(Bought) + Total Production + Total Battery Today(Daily) losses = Today(Daily) Energy Imported(Bought) + Today(Daily) Production + Today(Daily) Battery Discharge - Today(Daily) Energy Exported(Sold) - Today(Daily) Battery Charge - Today(Daily) Load Consumption ``` -_To get value which is in Energy Dashboard as "Home Consumption" remove subtraction of Load Consumption from the above._ +_To get value which is in Energy Dashboard as "Home Consumption" remove subtraction of Load Consumption from the above._ -## Diagnostics +## 🏭 Diagnostics I was using during the development also this sensor bundle: ``` @@ -87,17 +78,17 @@ template: icon: "mdi:calendar-clock" ``` Which provides informantion about how long it is since last update (with resolution of seconds). -Maybe it will be useful for some, but since the stability of the polling improved a lot it's not really needed. +Maybe it will be useful for some, but since the stability of the polling improved a lot it's not really needed. -## Installation +## 🔨 Installation -[![Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=davidrapan&repository=ha-solarman&category=integration) +[![🔌 Open your Home Assistant instance and open a repository inside the Home Assistant Community Store.](https://my.home-assistant.io/badges/hacs_repository.svg)](https://my.home-assistant.io/redirect/hacs_repository/?owner=davidrapan&repository=ha-solarman&category=integration) -### HACS (Manually) +### 🪛 HACS (Manually) - Follow the link [here](https://hacs.xyz/docs/faq/custom_repositories/) - Add custom repository: https://github.com/davidrapan/ha-solarman - Select type of the category: integration - Find newly added Solarman, open it and then click on the DOWNLOAD button -### Manually +### 🔧 Manually - Copy the contents of 'custom_components/solarman' directory into the Home Assistant with exactly the same hirearchy withing the '/config' directory \ No newline at end of file From 32a5f2e008853d318508e6a9f1ada36db3e6cbfb Mon Sep 17 00:00:00 2001 From: David Rapan Date: Mon, 15 Jul 2024 19:27:56 +0200 Subject: [PATCH 16/39] refactor: Pseudo enums reworked as true enums - In the context of the HA refactor: Naming: Load UPS entities prefix from UPS fix: Extended Power losses to include all inputs fix: 'deye_string' inverter profile file formatting --- custom_components/solarman/api.py | 2 +- custom_components/solarman/const.py | 2 +- .../inverter_definitions/deye_hybrid.yaml | 101 +++-- .../inverter_definitions/deye_sg01hp3.yaml | 170 +++++--- .../inverter_definitions/deye_sg04lp3.yaml | 168 +++++--- .../inverter_definitions/deye_string.yaml | 392 +++++++++--------- .../deye_sun-12k-sg04lp3.yaml | 168 +++++--- custom_components/solarman/parser.py | 10 +- custom_components/solarman/sensor.py | 4 + 9 files changed, 578 insertions(+), 439 deletions(-) diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index 5846e8d..43cba78 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -163,7 +163,7 @@ async def async_get(self, runtime = 0): requests_count = len(requests) result = 0 - _LOGGER.debug(f"Scheduling {requests_count} query requests. #{runtime}") + _LOGGER.debug(f"Scheduling {requests_count} query requests. #{runtime}") try: for request in requests: diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index 927c3f4..e8e44ba 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -43,7 +43,7 @@ TIMINGS_COORDINATOR_TIMEOUT = TIMINGS_INTERVAL * 6 TIMINGS_SOCKET_TIMEOUT = TIMINGS_INTERVAL * 3 - 1 TIMINGS_QUERY_INTERVAL_DEFAULT = 60 -TIMINGS_QUERY_EXCEPT_SLEEP = 4 +TIMINGS_QUERY_EXCEPT_SLEEP = 2 REGISTERS_MIN_SPAN_DEFAULT = 25 REGISTERS_DIGITS_DEFAULT = 6 diff --git a/custom_components/solarman/inverter_definitions/deye_hybrid.yaml b/custom_components/solarman/inverter_definitions/deye_hybrid.yaml index 684251b..c949743 100644 --- a/custom_components/solarman/inverter_definitions/deye_hybrid.yaml +++ b/custom_components/solarman/inverter_definitions/deye_hybrid.yaml @@ -14,7 +14,7 @@ requests: mb_functioncode: 0x03 parameters: - - group: solar + - group: PV items: - name: "PV1 Power" class: "power" @@ -23,7 +23,7 @@ parameters: scale: 1 rule: 1 registers: [0x00BA] - icon: "mdi:solar-power" + icon: "mdi:solar-power-variant" - name: "PV2 Power" class: "power" @@ -32,7 +32,7 @@ parameters: scale: 1 rule: 1 registers: [0x00BB] - icon: "mdi:solar-power" + icon: "mdi:solar-power-variant" - name: "PV1 Voltage" class: "voltage" @@ -41,7 +41,7 @@ parameters: scale: 0.1 rule: 1 registers: [0x006D] - icon: "mdi:solar-power" + icon: "mdi:solar-power-variant" - name: "PV2 Voltage" class: "voltage" @@ -50,7 +50,7 @@ parameters: scale: 0.1 rule: 1 registers: [0x006F] - icon: "mdi:solar-power" + icon: "mdi:solar-power-variant" - name: "PV1 Current" class: "current" @@ -58,7 +58,7 @@ parameters: scale: 0.1 rule: 1 registers: [0x006E] - icon: "mdi:solar-power" + icon: "mdi:solar-power-variant" - name: "PV2 Current" class: "current" @@ -67,7 +67,7 @@ parameters: scale: 0.1 rule: 1 registers: [0x0070] - icon: "mdi:solar-power" + icon: "mdi:solar-power-variant" - name: "Daily Production" class: "energy" @@ -135,13 +135,13 @@ parameters: icon: "mdi:battery-minus" - name: "Battery Status" - class: "" - state_class: "measurement" + class: "enum" + state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00BD] - isstr: true + options: ["Charge", "Stand-by", "Discharge"] lookup: - key: 0 value: "Charge" @@ -158,7 +158,6 @@ parameters: scale: 1 rule: 2 registers: [0x00BE] - icon: "mdi:battery" - name: "Battery Voltage" class: "voltage" @@ -167,7 +166,6 @@ parameters: scale: 0.01 rule: 1 registers: [0x00B7] - icon: "mdi:battery" - name: "Battery SOC" class: "battery" @@ -176,7 +174,6 @@ parameters: scale: 1 rule: 1 registers: [0x00B8] - icon: "mdi:battery" - name: "Battery Current" class: "current" @@ -185,7 +182,6 @@ parameters: scale: 0.01 rule: 2 registers: [0x00BF] - icon: "mdi:battery" - name: "Battery Temperature" class: "temperature" @@ -195,7 +191,6 @@ parameters: rule: 1 offset: 1000 registers: [0x00B6] - icon: "mdi:battery" - group: Grid items: @@ -224,7 +219,8 @@ parameters: scale: 0.01 rule: 1 registers: [0x00A0] - icon: "mdi:current-ac" + icon: "mdi:transmission-tower" + - name: "Grid Voltage L2" class: "voltage" state_class: "measurement" @@ -241,7 +237,7 @@ parameters: scale: 0.01 rule: 1 registers: [0x00A1] - icon: "mdi:current-ac" + icon: "mdi:transmission-tower" - name: "Internal CT L1 Power" class: "power" @@ -333,7 +329,6 @@ parameters: scale: 1 rule: 1 registers: [0x00B2] - icon: "mdi:lightning-bolt-outline" - name: "Load L1 Power" class: "power" @@ -342,7 +337,6 @@ parameters: scale: 1 rule: 1 registers: [0x00B0] - icon: "mdi:lightning-bolt-outline" - name: "Load L2 Power" class: "power" @@ -351,7 +345,6 @@ parameters: scale: 1 rule: 1 registers: [0x00B1] - icon: "mdi:lightning-bolt-outline" - name: "Load Voltage" class: "voltage" @@ -360,7 +353,6 @@ parameters: scale: 0.1 rule: 1 registers: [0x009D] - icon: "mdi:lightning-bolt-outline" - name: "Daily Load Consumption" class: "energy" @@ -369,7 +361,6 @@ parameters: scale: 0.1 rule: 1 registers: [0x0054] - icon: "mdi:lightning-bolt-outline" - name: "Total Load Consumption" class: "energy" @@ -378,43 +369,47 @@ parameters: scale: 0.1 rule: 3 registers: [0x0055, 0x0056] - icon: "mdi:lightning-bolt-outline" - name: "SmartLoad Enable Status" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00C3] - isstr: true + options: ["OFF", "ON"] lookup: - key: 0 value: "OFF" - key: 1 value: "ON" - icon: "mdi:lightning-bolt-outline" + icon: "mdi:lightning-bolt-circle" - group: Inverter items: - name: "Running Status" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x003B] - isstr: true + range: + min: 0 + max: 5 + options: ["Standby", "Self-test", "Normal", "Alarm", "Fault"] lookup: - - key: 0 - value: "Stand-by" - - key: 1 - value: "Self-checking" - - key: 2 + - key: 0x0000 + value: "Standby" + - key: 0x0001 + value: "Self-test" + - key: 0x0002 value: "Normal" - - key: 3 - value: "FAULT" - icon: "mdi:home-lightning-bolt" + - key: 0x0003 + value: "Alarm" + - key: 0x0004 + value: "Fault" + icon: "mdi:information" - name: "Total Power" class: "power" @@ -423,7 +418,6 @@ parameters: scale: 1 rule: 2 registers: [0x00AF] - icon: "mdi:home-lightning-bolt" - name: "Grid Frequency" class: "frequency" @@ -432,7 +426,6 @@ parameters: scale: 0.01 rule: 1 registers: [0x004F] - icon: "mdi:sine-wave" - name: "Current L1" class: "current" @@ -441,7 +434,6 @@ parameters: scale: 0.01 rule: 2 registers: [0x00A4] - icon: "mdi:home-lightning-bolt" - name: "Current L2" class: "current" @@ -449,7 +441,6 @@ parameters: scale: 0.01 rule: 2 registers: [0x00A5] - icon: "mdi:home-lightning-bolt" - name: "Inverter L1 Power" class: "power" @@ -458,7 +449,6 @@ parameters: scale: 1 rule: 2 registers: [0x00AD] - icon: "mdi:home-lightning-bolt" - name: "Inverter L2 Power" class: "power" @@ -467,7 +457,6 @@ parameters: scale: 1 rule: 2 registers: [0x00AE] - icon: "mdi:home-lightning-bolt" - name: "Load Frequency" class: "" @@ -476,7 +465,6 @@ parameters: scale: 0.01 rule: 1 registers: [0x00C0] - icon: "mdi:sine-wave" - name: "DC Temperature" class: "temperature" @@ -486,7 +474,6 @@ parameters: rule: 2 offset: 1000 registers: [0x005A] - icon: "mdi:thermometer" - name: "AC Temperature" class: "temperature" @@ -496,7 +483,6 @@ parameters: rule: 2 offset: 1000 registers: [0x005B] - icon: "mdi:thermometer" - name: "Inverter ID" class: "" @@ -526,13 +512,13 @@ parameters: isstr: true - name: "Grid-connected Status" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00C2] - isstr: true + options: ["Off-Grid", "On-Grid"] lookup: - key: 0 value: "Off-Grid" @@ -540,13 +526,13 @@ parameters: value: "On-Grid" - name: "Gen-connected Status" - class: "" - uom: "" + class: "enum" state_class: "" + uom: "" scale: 1 rule: 1 registers: [0x00A6] - isstr: true + options: ["none", "On"] lookup: - key: 0 value: "none" @@ -562,13 +548,20 @@ parameters: registers: [0x00A6] - name: "Work Mode" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 3 registers: [0x00F4, 0x00F7] - isstr: true + options: + [ + "Selling First", + "Zero-Export to Load&Solar Sell", + "Zero-Export to Home&Solar Sell", + "Zero-Export to Load", + "Zero-Export to Home", + ] lookup: - key: 0 value: "Selling First" @@ -817,7 +810,7 @@ parameters: icon: "mdi:checkbox-marked-outline" - name: "Time of use" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 @@ -825,7 +818,7 @@ parameters: mask: 1 registers: [0x00F8] icon: "mdi:checkbox-marked-outline" - isstr: true + options: ["Disable", "Enable"] lookup: - key: 0 value: "Disable" diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index c25d069..2739fdf 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -12,14 +12,23 @@ parameters: # Device - Type of the Device - name: "Device" update_interval: 300 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0000] icon: "mdi:information" - isstr: true + options: + [ + "String Inverter", + "Single-Phase Hybrid Inverter", + "Microinverter", + "LV 3-Phase Hybrid Inverter", + "HV 3-Phase Hybrid Inverter", + "HV 3-Phase Inverter 6-15kw", + "HV 3-Phase Inverter 20-50kw" + ] lookup: - key: 0x0200 value: "String Inverter" @@ -58,14 +67,14 @@ parameters: - name: "Device Protocol Version" attribute: update_interval: 300 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0002] icon: "mdi:information" - isstr: true + options: ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5"] lookup: - key: 0x0100 value: "1.0" @@ -108,14 +117,14 @@ parameters: items: - name: "Battery Control Mode" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0062] icon: "mdi:battery" - isstr: true + options: ["Lead-Battery, four-stage charging method", "Lithium"] lookup: - key: 0x0000 value: "Lead-Battery, four-stage charging method" @@ -275,14 +284,14 @@ parameters: - name: "Battery Grid Charging" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0082] icon: "mdi:battery" - isstr: true + options: ["Disabled", "Enabled"] lookup: - key: 0x0000 value: "Disabled" @@ -290,14 +299,14 @@ parameters: value: "Enabled" - name: "SmartLoad Mode" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0085] icon: "mdi:lightning-bolt-circle" - isstr: true + options: ["Generator", "Output", "Microinverter"] lookup: - key: 0x0000 value: "Generator" @@ -331,14 +340,14 @@ parameters: max: 100 - name: "SmartLoad State" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:lightning-bolt-circle" - isstr: true + options: ["Off", "On"] lookup: - key: 0x0001 value: "Off" @@ -354,6 +363,8 @@ parameters: value: "Off" - key: 0x000D value: "On" + - key: "default" + value: "On" - group: BMS items: @@ -456,20 +467,21 @@ parameters: icon: "mdi:battery" - name: "BMS Alarm" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00DC] icon: "mdi:battery-alert" - isstr: true - lookup_default: "Active" + options: ["Inactive", "Active"] lookup: - key: 0 value: "Inactive" - key: 1 value: "Active" + - key: "default" + value: "Active" - name: "BMS Fault Location" class: "" @@ -499,14 +511,27 @@ parameters: - name: "BMS Type" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00DF] icon: "mdi:battery" - isstr: true + options: + [ + "PYLON", + "Tianbangda", + "KOK", + "Keith", + "Toppai", + "Peneng 485", + "Jeris 485", + "Sunwoda 485", + "Xinrui 485", + "Tianbangda 485", + "Shenggao Electric CAN", + ] lookup: - key: 0x0000 value: "PYLON" @@ -515,7 +540,7 @@ parameters: - key: 0x0002 value: "KOK" - key: 0x0003 - value: "keith" + value: "Keith" - key: 0x0004 value: "Toppai" - key: 0x0005 @@ -536,7 +561,7 @@ parameters: # Device - Operating (Running) status - name: "Device Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 @@ -546,7 +571,7 @@ parameters: range: min: 0 max: 5 - isstr: true + options: ["Standby", "Self-test", "Normal", "Alarm", "Fault"] lookup: - key: 0x0000 value: "Standby" @@ -767,14 +792,14 @@ parameters: # Device - Power on/off status - name: "Device Power Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0227] icon: "mdi:information" - isstr: true + options: ["Off", "On"] lookup: - key: 0x0000 value: "Off" @@ -784,15 +809,24 @@ parameters: # Device - AC Relay status - name: "Device Relay Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:information" - isstr: true - lookup_default: "Power Supply" + options: + [ + "Inverter", + "Grid", + "Inverter-Grid", + "Generator", + "Inverter-Gen", + "Grid-Generator", + "Inv-Grid-Gen", + "Power Supply" + ] lookup: - key: 0x0001 value: "Inverter" @@ -808,17 +842,20 @@ parameters: value: "Grid-Generator" - key: 0x000D value: "Inv-Grid-Gen" + - key: "default" + value: "Power Supply" # Device - AC Grid state - name: "Device State" - class: "" + update_interval: 30 + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:information" - isstr: true + options: ["Off-grid", "On-grid"] lookup: - key: 0x0001 value: "Off-grid" @@ -838,15 +875,22 @@ parameters: # Device - Alarm message (word 1 & 2) [0, 65535] - name: "Device Alert" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 3 registers: [0x0229, 0x022A] icon: "mdi:alert-circle" - isstr: true - lookup_default: "Error" + options: + [ + "Ok", + "Fan failure", + "Grid error", + "Battery loss", + "Parallel communication quality", + "Error" + ] lookup: - key: 0x0000 value: "Ok" @@ -858,6 +902,8 @@ parameters: value: "Battery loss" - key: 0x8000 value: "Parallel communication quality" + - key: "default" + value: "Error" # Device - Fault message (word 1, 2, 3 & 4) [0, 65535] - name: "Device Fault" @@ -1312,14 +1358,14 @@ parameters: rule: 4 registers: [0x027C, 0x02B6] - # Inverter - Includes consumption of the device itself aswell power losses of AC/DC conversions + # Inverter - Includes consumption of the inverter device itself as well AC/DC conversion losses - name: "Power losses" class: "power" state_class: "measurement" uom: "W" rule: 1 digits: 0 - registers: [0x024E, 0x02A0, 0x02A1, 0x027C, 0x02B6] + registers: [0x024E, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x027C, 0x02B6] sensors: - signed: scale: 10 @@ -1328,6 +1374,10 @@ parameters: registers: [0x02A0] - scale: 10 registers: [0x02A1] + - scale: 10 + registers: [0x02A2] + - scale: 10 + registers: [0x02A3] - subtract: signed: registers: [0x027C, 0x02B6] @@ -1342,10 +1392,10 @@ parameters: rule: 1 registers: [0x027E] - - group: Upload + - group: UPS items: - # UPS output - The power of phase A is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L1 Power" + # Load UPS output - The power of phase A is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L1 Power" realtime: class: "power" state_class: "measurement" @@ -1355,8 +1405,8 @@ parameters: registers: [0x0280, 0x02B8] icon: "mdi:home-lightning-bolt" - # UPS output - The power of phase B is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L2 Power" + # Load UPS output - The power of phase B is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L2 Power" realtime: class: "power" state_class: "measurement" @@ -1366,8 +1416,8 @@ parameters: registers: [0x0281, 0x02B9] icon: "mdi:home-lightning-bolt" - # UPS output - The power of phase C is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L3 Power" + # Load UPS output - The power of phase C is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L3 Power" realtime: class: "power" state_class: "measurement" @@ -1377,8 +1427,8 @@ parameters: registers: [0x0282, 0x02BA] icon: "mdi:home-lightning-bolt" - # UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS Power" + # Load UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS Power" realtime: class: "power" state_class: "measurement" @@ -1388,6 +1438,8 @@ parameters: registers: [0x0283, 0x02BB] icon: "mdi:home-lightning-bolt" + - group: Load + items: # Load output - The voltage of phase A - name: "Load L1 Voltage" class: "voltage" @@ -1422,7 +1474,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028A, 0x0290] # Load - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1432,7 +1484,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028B, 0x0291] # Load - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1442,7 +1494,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028C, 0x0292] # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1452,7 +1504,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028D, 0x0293] - group: SmartLoad/Generator @@ -1524,9 +1576,9 @@ parameters: rule: 2 registers: [0x029B, 0x029F] - - group: Photovoltaic + - group: PV items: - # Photovoltaic - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) + # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" realtime: class: "power" @@ -1546,7 +1598,7 @@ parameters: registers: [0x02A3] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 1 (L:1W, H:10W) + # PV - The power of Input 1 (L:1W, H:10W) - name: "PV1 Power" realtime: class: "power" @@ -1557,7 +1609,7 @@ parameters: registers: [0x02A0] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 2 (L:1W, H:10W) + # PV - The power of Input 2 (L:1W, H:10W) - name: "PV2 Power" realtime: class: "power" @@ -1568,7 +1620,7 @@ parameters: registers: [0x02A1] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 3 (L:1W, H:10W) + # PV - The power of Input 3 (L:1W, H:10W) - name: "PV3 Power" disabled: realtime: @@ -1580,7 +1632,7 @@ parameters: registers: [0x02A2] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 4 (L:1W, H:10W) + # PV - The power of Input 4 (L:1W, H:10W) - name: "PV4 Power" disabled: realtime: @@ -1592,7 +1644,7 @@ parameters: registers: [0x02A3] icon: "mdi:solar-power-variant" - # Photovoltaic - The voltage of Input 1 + # PV - The voltage of Input 1 - name: "PV1 Voltage" realtime: class: "voltage" @@ -1606,7 +1658,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 1 + # PV - The current of Input 1 - name: "PV1 Current" realtime: class: "current" @@ -1620,7 +1672,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 2 + # PV - The voltage of Input 2 - name: "PV2 Voltage" realtime: class: "voltage" @@ -1634,7 +1686,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 2 + # PV - The current of Input 2 - name: "PV2 Current" realtime: class: "current" @@ -1648,7 +1700,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 3 + # PV - The voltage of Input 3 - name: "PV3 Voltage" disabled: realtime: @@ -1663,7 +1715,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 3 + # PV - The current of Input 3 - name: "PV3 Current" disabled: realtime: @@ -1678,7 +1730,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 4 + # PV - The voltage of Input 4 - name: "PV4 Voltage" disabled: realtime: @@ -1693,7 +1745,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 4 + # PV - The current of Input 4 - name: "PV4 Current" disabled: realtime: diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 9a65866..97c8ce2 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -18,14 +18,23 @@ parameters: # Device - Type of the Device - name: "Device" update_interval: 300 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0000] icon: "mdi:information" - isstr: true + options: + [ + "String Inverter", + "Single-Phase Hybrid Inverter", + "Microinverter", + "LV 3-Phase Hybrid Inverter", + "HV 3-Phase Hybrid Inverter", + "HV 3-Phase Inverter 6-15kw", + "HV 3-Phase Inverter 20-50kw" + ] lookup: - key: 0x0200 value: "String Inverter" @@ -64,14 +73,14 @@ parameters: - name: "Device Protocol Version" attribute: update_interval: 300 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0002] icon: "mdi:information" - isstr: true + options: ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5"] lookup: - key: 0x0100 value: "1.0" @@ -114,14 +123,14 @@ parameters: items: - name: "Battery Control Mode" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0062] icon: "mdi:battery" - isstr: true + options: ["Lead-Battery, four-stage charging method", "Lithium"] lookup: - key: 0x0000 value: "Lead-Battery, four-stage charging method" @@ -280,14 +289,14 @@ parameters: - name: "Battery Grid Charging" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0082] icon: "mdi:battery" - isstr: true + options: ["Disabled", "Enabled"] lookup: - key: 0x0000 value: "Disabled" @@ -295,14 +304,14 @@ parameters: value: "Enabled" - name: "SmartLoad Mode" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0085] icon: "mdi:lightning-bolt-circle" - isstr: true + options: ["Generator", "Output", "Microinverter"] lookup: - key: 0x0000 value: "Generator" @@ -336,14 +345,14 @@ parameters: max: 100 - name: "SmartLoad State" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:lightning-bolt-circle" - isstr: true + options: ["Off", "On"] lookup: - key: 0x0001 value: "Off" @@ -359,6 +368,8 @@ parameters: value: "Off" - key: 0x000D value: "On" + - key: "default" + value: "On" - group: BMS items: @@ -461,20 +472,21 @@ parameters: icon: "mdi:battery" - name: "BMS Alarm" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00DC] icon: "mdi:battery-alert" - isstr: true - lookup_default: "Active" + options: ["Inactive", "Active"] lookup: - key: 0 value: "Inactive" - key: 1 value: "Active" + - key: "default" + value: "Active" - name: "BMS Fault Location" class: "" @@ -504,14 +516,27 @@ parameters: - name: "BMS Type" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00DF] icon: "mdi:battery" - isstr: true + options: + [ + "PYLON", + "Tianbangda", + "KOK", + "Keith", + "Toppai", + "Peneng 485", + "Jeris 485", + "Sunwoda 485", + "Xinrui 485", + "Tianbangda 485", + "Shenggao Electric CAN", + ] lookup: - key: 0x0000 value: "PYLON" @@ -520,7 +545,7 @@ parameters: - key: 0x0002 value: "KOK" - key: 0x0003 - value: "keith" + value: "Keith" - key: 0x0004 value: "Toppai" - key: 0x0005 @@ -541,7 +566,7 @@ parameters: # Device - Operating (Running) status - name: "Device Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 @@ -551,7 +576,7 @@ parameters: range: min: 0 max: 5 - isstr: true + options: ["Standby", "Self-test", "Normal", "Alarm", "Fault"] lookup: - key: 0x0000 value: "Standby" @@ -766,14 +791,14 @@ parameters: # Device - Power on/off status - name: "Device Power Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0227] icon: "mdi:information" - isstr: true + options: ["Off", "On"] lookup: - key: 0x0000 value: "Off" @@ -783,15 +808,24 @@ parameters: # Device - AC Relay status - name: "Device Relay Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:information" - isstr: true - lookup_default: "Power Supply" + options: + [ + "Inverter", + "Grid", + "Inverter-Grid", + "Generator", + "Inverter-Gen", + "Grid-Generator", + "Inv-Grid-Gen", + "Power Supply" + ] lookup: - key: 0x0001 value: "Inverter" @@ -807,17 +841,20 @@ parameters: value: "Grid-Generator" - key: 0x000D value: "Inv-Grid-Gen" + - key: "default" + value: "Power Supply" # Device - AC Grid state - name: "Device State" - class: "" + update_interval: 30 + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:information" - isstr: true + options: ["Off-grid", "On-grid"] lookup: - key: 0x0001 value: "Off-grid" @@ -837,15 +874,22 @@ parameters: # Device - Alarm message (word 1 & 2) [0, 65535] - name: "Device Alert" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 3 registers: [0x0229, 0x022A] icon: "mdi:alert-circle" - isstr: true - lookup_default: "Error" + options: + [ + "Ok", + "Fan failure", + "Grid error", + "Battery loss", + "Parallel communication quality", + "Error" + ] lookup: - key: 0x0000 value: "Ok" @@ -857,6 +901,8 @@ parameters: value: "Battery loss" - key: 0x8000 value: "Parallel communication quality" + - key: "default" + value: "Error" # Device - Fault message (word 1, 2, 3 & 4) [0, 65535] - name: "Device Fault" @@ -1284,19 +1330,21 @@ parameters: rule: 4 registers: [0x027C, 0x02B6] - # Inverter - Includes consumption of the device itself aswell power losses of AC/DC conversions + # Inverter - Includes consumption of the inverter device itself as well AC/DC conversion losses - name: "Power losses" class: "power" state_class: "measurement" uom: "W" rule: 1 digits: 0 - registers: [0x024E, 0x02A0, 0x02A1, 0x027C, 0x02B6] + registers: [0x024E, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x027C, 0x02B6] sensors: - signed: registers: [0x024E] - registers: [0x02A0] - registers: [0x02A1] + - registers: [0x02A2] + - registers: [0x02A3] - subtract: signed: registers: [0x027C, 0x02B6] @@ -1311,10 +1359,10 @@ parameters: rule: 1 registers: [0x027E] - - group: Upload + - group: UPS items: - # UPS output - The power of phase A is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L1 Power" + # Load UPS output - The power of phase A is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L1 Power" realtime: class: "power" state_class: "measurement" @@ -1324,8 +1372,8 @@ parameters: registers: [0x0280, 0x02B8] icon: "mdi:home-lightning-bolt" - # UPS output - The power of phase B is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L2 Power" + # Load UPS output - The power of phase B is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L2 Power" realtime: class: "power" state_class: "measurement" @@ -1335,8 +1383,8 @@ parameters: registers: [0x0281, 0x02B9] icon: "mdi:home-lightning-bolt" - # UPS output - The power of phase C is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L3 Power" + # Load UPS output - The power of phase C is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L3 Power" realtime: class: "power" state_class: "measurement" @@ -1346,8 +1394,8 @@ parameters: registers: [0x0282, 0x02BA] icon: "mdi:home-lightning-bolt" - # UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS Power" + # Load UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS Power" realtime: class: "power" state_class: "measurement" @@ -1357,6 +1405,8 @@ parameters: registers: [0x0283, 0x02BB] icon: "mdi:home-lightning-bolt" + - group: Load + items: # Load output - The voltage of phase A - name: "Load L1 Voltage" class: "voltage" @@ -1391,7 +1441,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028A, 0x0290] # Load - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1401,7 +1451,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028B, 0x0291] # Load - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1411,7 +1461,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028C, 0x0292] # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1421,7 +1471,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028D, 0x0293] - group: SmartLoad/Generator @@ -1493,9 +1543,9 @@ parameters: rule: 2 registers: [0x029B, 0x029F] - - group: Photovoltaic + - group: PV items: - # Photovoltaic - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) + # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" realtime: class: "power" @@ -1511,7 +1561,7 @@ parameters: - registers: [0x02A3] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 1 (L:1W, H:10W) + # PV - The power of Input 1 (L:1W, H:10W) - name: "PV1 Power" realtime: class: "power" @@ -1522,7 +1572,7 @@ parameters: registers: [0x02A0] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 2 (L:1W, H:10W) + # PV - The power of Input 2 (L:1W, H:10W) - name: "PV2 Power" realtime: class: "power" @@ -1533,7 +1583,7 @@ parameters: registers: [0x02A1] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 3 (L:1W, H:10W) + # PV - The power of Input 3 (L:1W, H:10W) - name: "PV3 Power" disabled: realtime: @@ -1545,7 +1595,7 @@ parameters: registers: [0x02A2] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 4 (L:1W, H:10W) + # PV - The power of Input 4 (L:1W, H:10W) - name: "PV4 Power" disabled: realtime: @@ -1557,7 +1607,7 @@ parameters: registers: [0x02A3] icon: "mdi:solar-power-variant" - # Photovoltaic - The voltage of Input 1 + # PV - The voltage of Input 1 - name: "PV1 Voltage" realtime: class: "voltage" @@ -1571,7 +1621,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 1 + # PV - The current of Input 1 - name: "PV1 Current" realtime: class: "current" @@ -1585,7 +1635,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 2 + # PV - The voltage of Input 2 - name: "PV2 Voltage" realtime: class: "voltage" @@ -1599,7 +1649,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 2 + # PV - The current of Input 2 - name: "PV2 Current" realtime: class: "current" @@ -1613,7 +1663,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 3 + # PV - The voltage of Input 3 - name: "PV3 Voltage" disabled: realtime: @@ -1628,7 +1678,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 3 + # PV - The current of Input 3 - name: "PV3 Current" disabled: realtime: @@ -1643,7 +1693,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 4 + # PV - The voltage of Input 4 - name: "PV4 Voltage" disabled: realtime: @@ -1658,7 +1708,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 4 + # PV - The current of Input 4 - name: "PV4 Current" disabled: realtime: diff --git a/custom_components/solarman/inverter_definitions/deye_string.yaml b/custom_components/solarman/inverter_definitions/deye_string.yaml index 566d94f..64b78cc 100644 --- a/custom_components/solarman/inverter_definitions/deye_string.yaml +++ b/custom_components/solarman/inverter_definitions/deye_string.yaml @@ -1,206 +1,196 @@ - requests: - start: 0x0003 - end: 0x0070 + end: 0x0070 mb_functioncode: 0x03 parameters: - - group: solar - items: - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x006D] - icon: 'mdi:solar-power' - - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x006F] - icon: 'mdi:solar-power' - - - name: "PV1 Current" - class: "current" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x006E] - icon: 'mdi:solar-power' - - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x0070] - icon: 'mdi:solar-power' - - - name: "Daily Production" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [0x003C] - icon: 'mdi:solar-power' - - - name: "Total Production" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 3 - registers: [0x003F,0x0040] - icon: 'mdi:solar-power' - validation: - min: 0.1 - invalidate_all: - - - - - group: Grid - items: - - name: "Grid Voltage L-L(A)" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0049] - icon: 'mdi:transmission-tower' - - - name: "Grid Voltage L-L(B))" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x004A] - icon: 'mdi:transmission-tower' - - - name: "Grid Voltage L-L(C)" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x004B] - icon: 'mdi:transmission-tower' - - - name: "Grid Current A" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 2 - registers: [0x004C] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid Current B" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 2 - registers: [0x004D] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid Current C" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 2 - registers: [0x004E] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x004F] - icon: 'mdi:home-lightning-bolt' - - - group: Inverter - items: - - name: "Running Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x003B] - isstr: true - lookup: - - key: 0 - value: "Stand-by" - - key: 1 - value: "Self-checking" - - key: 2 - value: "Normal" - - key: 3 - value: "FAULT" - icon: 'mdi:home-lightning-bolt' - - - name: "Total Output AC Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 0.1 - rule: 3 - registers: [0x0050,0x0051] - icon: 'mdi:home-lightning-bolt' - - - name: "Input Active Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 0.1 - rule: 3 - registers: [0x0052, 0x0053] - icon: 'mdi:home-lightning-bolt' - - - name: "Output Apparent Power" - class: "apparent_power" - state_class: "measurement" - uom: "VA" - scale: 0.1 - rule: 3 - registers: [0x0054, 0x0055] - icon: 'mdi:home-lightning-bolt' - - - name: "Output Active Power" - class: "energy" - state_class: "measurement" - uom: "W" - scale: 0.1 - rule: 3 - registers: [0x0056, 0x0057] - icon: 'mdi:home-lightning-bolt' - - - name: "Output Reactive Power" - class: "reactive_power" - state_class: "measurement" - uom: "VAR" - rule: 3 - scale: 0.1 - registers: [0x0058, 0x0059] - icon: 'mdi:home-lightning-bolt' - - - name: "Inverter ID" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 5 - registers: [0x0003,0x0004,0x0005,0x0006,0x0007] - isstr: true + - group: PV + items: + - name: "PV1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x006D] + icon: "mdi:solar-power-variant" + + - name: "PV2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x006F] + icon: "mdi:solar-power-variant" + + - name: "PV1 Current" + class: "current" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x006E] + icon: "mdi:solar-power-variant" + + - name: "PV2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x0070] + icon: "mdi:solar-power-variant" + + - name: "Daily Production" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [0x003C] + icon: "mdi:solar-power" + + - name: "Total Production" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 3 + registers: [0x003F, 0x0040] + icon: "mdi:solar-power" + validation: + min: 0.1 + invalidate_all: + + - group: Grid + items: + - name: "Grid Voltage L-L(A)" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0049] + + - name: "Grid Voltage L-L(B))" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x004A] + + - name: "Grid Voltage L-L(C)" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x004B] + + - name: "Grid Current A" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 2 + registers: [0x004C] + + - name: "Grid Current B" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 2 + registers: [0x004D] + + - name: "Grid Current C" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 2 + registers: [0x004E] + + - name: "Grid Frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x004F] + + - group: Inverter + items: + - name: "Running Status" + class: "enum" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x003B] + icon: "mdi:information" + range: + min: 0 + max: 5 + options: ["Standby", "Self-test", "Normal", "Alarm", "Fault"] + lookup: + - key: 0x0000 + value: "Standby" + - key: 0x0001 + value: "Self-test" + - key: 0x0002 + value: "Normal" + - key: 0x0003 + value: "Alarm" + - key: 0x0004 + value: "Fault" + + - name: "Total Output AC Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 0.1 + rule: 3 + registers: [0x0050, 0x0051] + + - name: "Input Active Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 0.1 + rule: 3 + registers: [0x0052, 0x0053] + + - name: "Output Apparent Power" + class: "apparent_power" + state_class: "measurement" + uom: "VA" + scale: 0.1 + rule: 3 + registers: [0x0054, 0x0055] + + - name: "Output Active Power" + class: "energy" + state_class: "measurement" + uom: "W" + scale: 0.1 + rule: 3 + registers: [0x0056, 0x0057] + + - name: "Output Reactive Power" + class: "reactive_power" + state_class: "measurement" + uom: "VAR" + rule: 3 + scale: 0.1 + registers: [0x0058, 0x0059] + + - name: "Inverter ID" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 5 + registers: [0x0003, 0x0004, 0x0005, 0x0006, 0x0007] + isstr: true diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 467b31d..52839ec 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -20,14 +20,23 @@ parameters: # Device - Type of the Device - name: "Device" update_interval: 300 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0000] icon: "mdi:information" - isstr: true + options: + [ + "String Inverter", + "Single-Phase Hybrid Inverter", + "Microinverter", + "LV 3-Phase Hybrid Inverter", + "HV 3-Phase Hybrid Inverter", + "HV 3-Phase Inverter 6-15kw", + "HV 3-Phase Inverter 20-50kw" + ] lookup: - key: 0x0200 value: "String Inverter" @@ -66,14 +75,14 @@ parameters: - name: "Device Protocol Version" attribute: update_interval: 300 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0002] icon: "mdi:information" - isstr: true + options: ["1.0", "1.1", "1.2", "1.3", "1.4", "1.5"] lookup: - key: 0x0100 value: "1.0" @@ -116,14 +125,14 @@ parameters: items: - name: "Battery Control Mode" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0062] icon: "mdi:battery" - isstr: true + options: ["Lead-Battery, four-stage charging method", "Lithium"] lookup: - key: 0x0000 value: "Lead-Battery, four-stage charging method" @@ -283,14 +292,14 @@ parameters: - name: "Battery Grid Charging" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0082] icon: "mdi:battery" - isstr: true + options: ["Disabled", "Enabled"] lookup: - key: 0x0000 value: "Disabled" @@ -298,14 +307,14 @@ parameters: value: "Enabled" - name: "SmartLoad Mode" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0085] icon: "mdi:lightning-bolt-circle" - isstr: true + options: ["Generator", "Output", "Microinverter"] lookup: - key: 0x0000 value: "Generator" @@ -339,14 +348,14 @@ parameters: max: 100 - name: "SmartLoad State" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:lightning-bolt-circle" - isstr: true + options: ["Off", "On"] lookup: - key: 0x0001 value: "Off" @@ -362,6 +371,8 @@ parameters: value: "Off" - key: 0x000D value: "On" + - key: "default" + value: "On" - group: BMS items: @@ -464,20 +475,21 @@ parameters: icon: "mdi:battery" - name: "BMS Alarm" - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00DC] icon: "mdi:battery-alert" - isstr: true - lookup_default: "Active" + options: ["Inactive", "Active"] lookup: - key: 0 value: "Inactive" - key: 1 value: "Active" + - key: "default" + value: "Active" - name: "BMS Fault Location" class: "" @@ -507,14 +519,27 @@ parameters: - name: "BMS Type" attribute: - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x00DF] icon: "mdi:battery" - isstr: true + options: + [ + "PYLON", + "Tianbangda", + "KOK", + "Keith", + "Toppai", + "Peneng 485", + "Jeris 485", + "Sunwoda 485", + "Xinrui 485", + "Tianbangda 485", + "Shenggao Electric CAN", + ] lookup: - key: 0x0000 value: "PYLON" @@ -523,7 +548,7 @@ parameters: - key: 0x0002 value: "KOK" - key: 0x0003 - value: "keith" + value: "Keith" - key: 0x0004 value: "Toppai" - key: 0x0005 @@ -544,7 +569,7 @@ parameters: # Device - Operating (Running) status - name: "Device Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 @@ -554,7 +579,7 @@ parameters: range: min: 0 max: 5 - isstr: true + options: ["Standby", "Self-test", "Normal", "Alarm", "Fault"] lookup: - key: 0x0000 value: "Standby" @@ -799,14 +824,14 @@ parameters: # Device - Power on/off status - name: "Device Power Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0227] icon: "mdi:information" - isstr: true + options: ["Off", "On"] lookup: - key: 0x0000 value: "Off" @@ -816,15 +841,24 @@ parameters: # Device - AC Relay status - name: "Device Relay Status" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:information" - isstr: true - lookup_default: "Power Supply" + options: + [ + "Inverter", + "Grid", + "Inverter-Grid", + "Generator", + "Inverter-Gen", + "Grid-Generator", + "Inv-Grid-Gen", + "Power Supply" + ] lookup: - key: 0x0001 value: "Inverter" @@ -840,17 +874,20 @@ parameters: value: "Grid-Generator" - key: 0x000D value: "Inv-Grid-Gen" + - key: "default" + value: "Power Supply" # Device - AC Grid state - name: "Device State" - class: "" + update_interval: 30 + class: "enum" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0228] icon: "mdi:information" - isstr: true + options: ["Off-grid", "On-grid"] lookup: - key: 0x0001 value: "Off-grid" @@ -870,15 +907,22 @@ parameters: # Device - Alarm message (word 1 & 2) [0, 65535] - name: "Device Alert" update_interval: 30 - class: "" + class: "enum" state_class: "" uom: "" scale: 1 rule: 3 registers: [0x0229, 0x022A] icon: "mdi:alert-circle" - isstr: true - lookup_default: "Error" + options: + [ + "Ok", + "Fan failure", + "Grid error", + "Battery loss", + "Parallel communication quality", + "Error" + ] lookup: - key: 0x0000 value: "Ok" @@ -890,6 +934,8 @@ parameters: value: "Battery loss" - key: 0x8000 value: "Parallel communication quality" + - key: "default" + value: "Error" # Device - Fault message (word 1, 2, 3 & 4) [0, 65535] - name: "Device Fault" @@ -1347,19 +1393,21 @@ parameters: rule: 4 registers: [0x027C, 0x02B6] - # Inverter - Includes consumption of the device itself aswell power losses of AC/DC conversions + # Inverter - Includes consumption of the inverter device itself as well AC/DC conversion losses - name: "Power losses" class: "power" state_class: "measurement" uom: "W" rule: 1 digits: 0 - registers: [0x024E, 0x02A0, 0x02A1, 0x027C, 0x02B6] + registers: [0x024E, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x027C, 0x02B6] sensors: - signed: registers: [0x024E] - registers: [0x02A0] - registers: [0x02A1] + - registers: [0x02A2] + - registers: [0x02A3] - subtract: signed: registers: [0x027C, 0x02B6] @@ -1374,10 +1422,10 @@ parameters: rule: 1 registers: [0x027E] - - group: Upload + - group: UPS items: - # UPS output - The power of phase A is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L1 Power" + # Load UPS output - The power of phase A is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L1 Power" realtime: class: "power" state_class: "measurement" @@ -1387,8 +1435,8 @@ parameters: registers: [0x0280, 0x02B8] icon: "mdi:home-lightning-bolt" - # UPS output - The power of phase B is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L2 Power" + # Load UPS output - The power of phase B is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L2 Power" realtime: class: "power" state_class: "measurement" @@ -1398,8 +1446,8 @@ parameters: registers: [0x0281, 0x02B9] icon: "mdi:home-lightning-bolt" - # UPS output - The power of phase C is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS L3 Power" + # Load UPS output - The power of phase C is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS L3 Power" realtime: class: "power" state_class: "measurement" @@ -1409,8 +1457,8 @@ parameters: registers: [0x0282, 0x02BA] icon: "mdi:home-lightning-bolt" - # UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) - - name: "UPS Power" + # Load UPS output - The power is U16bit (low 16 bits) + U16bit (high 16 bits) + - name: "Load UPS Power" realtime: class: "power" state_class: "measurement" @@ -1420,6 +1468,8 @@ parameters: registers: [0x0283, 0x02BB] icon: "mdi:home-lightning-bolt" + - group: Load + items: # Load output - The voltage of phase A - name: "Load L1 Voltage" class: "voltage" @@ -1454,7 +1504,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028A, 0x0290] # Load - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1464,7 +1514,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028B, 0x0291] # Load - The power of phase A is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1474,7 +1524,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028C, 0x0292] # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) @@ -1484,7 +1534,7 @@ parameters: state_class: "measurement" uom: "W" scale: 1 - rule: 2 + rule: 4 registers: [0x028D, 0x0293] - group: SmartLoad/Generator @@ -1556,9 +1606,9 @@ parameters: rule: 2 registers: [0x029B, 0x029F] - - group: Photovoltaic + - group: PV items: - # Photovoltaic - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) + # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" realtime: class: "power" @@ -1574,7 +1624,7 @@ parameters: - registers: [0x02A3] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 1 (L:1W, H:10W) + # PV - The power of Input 1 (L:1W, H:10W) - name: "PV1 Power" realtime: class: "power" @@ -1585,7 +1635,7 @@ parameters: registers: [0x02A0] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 2 (L:1W, H:10W) + # PV - The power of Input 2 (L:1W, H:10W) - name: "PV2 Power" realtime: class: "power" @@ -1596,7 +1646,7 @@ parameters: registers: [0x02A1] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 3 (L:1W, H:10W) + # PV - The power of Input 3 (L:1W, H:10W) - name: "PV3 Power" disabled: realtime: @@ -1608,7 +1658,7 @@ parameters: registers: [0x02A2] icon: "mdi:solar-power-variant" - # Photovoltaic - The power of Input 4 (L:1W, H:10W) + # PV - The power of Input 4 (L:1W, H:10W) - name: "PV4 Power" disabled: realtime: @@ -1620,7 +1670,7 @@ parameters: registers: [0x02A3] icon: "mdi:solar-power-variant" - # Photovoltaic - The voltage of Input 1 + # PV - The voltage of Input 1 - name: "PV1 Voltage" realtime: class: "voltage" @@ -1634,7 +1684,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 1 + # PV - The current of Input 1 - name: "PV1 Current" realtime: class: "current" @@ -1648,7 +1698,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 2 + # PV - The voltage of Input 2 - name: "PV2 Voltage" realtime: class: "voltage" @@ -1662,7 +1712,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 2 + # PV - The current of Input 2 - name: "PV2 Current" realtime: class: "current" @@ -1676,7 +1726,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 3 + # PV - The voltage of Input 3 - name: "PV3 Voltage" disabled: realtime: @@ -1691,7 +1741,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 3 + # PV - The current of Input 3 - name: "PV3 Current" disabled: realtime: @@ -1706,7 +1756,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The voltage of Input 4 + # PV - The voltage of Input 4 - name: "PV4 Voltage" disabled: realtime: @@ -1721,7 +1771,7 @@ parameters: min: 0 max: 65535 - # Photovoltaic - The current of Input 4 + # PV - The current of Input 4 - name: "PV4 Current" disabled: realtime: diff --git a/custom_components/solarman/parser.py b/custom_components/solarman/parser.py index ed3b547..58d26dc 100644 --- a/custom_components/solarman/parser.py +++ b/custom_components/solarman/parser.py @@ -107,12 +107,12 @@ def in_range(self, value, definition): return True - def lookup_value(self, value, definition): - for o in definition["lookup"]: - if (o["key"] == value): + def lookup_value(self, value, keyvaluepairs): + for o in keyvaluepairs: + if o["key"] == value or o["key"] == "default": return o["value"] - return value if not "lookup_default" in definition else f"{definition["lookup_default"]} [{value}]" + return keyvaluepairs[0]["value"] def do_validate(self, key, value, rule): if "min" in rule: @@ -243,7 +243,7 @@ def try_parse_unsigned(self, rawData, definition, start, length): if found: if "lookup" in definition: - self.set_state(key, self.lookup_value(value, definition)) + self.set_state(key, self.lookup_value(value, definition["lookup"])) self._result[key]["value"] = int(value) else: if "validation" in definition: diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index a2fbf80..6032032 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -215,5 +215,9 @@ def __init__(self, coordinator, sensor, battery_life_cycle_rating): if "unit_of_measurement" in sensor and (unit_of_measurement := sensor["unit_of_measurement"]): self._attr_unit_of_measurement = unit_of_measurement + if "options" in sensor and (options := sensor["options"]): + self._attr_options = options + self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "options": options } + if "name" in sensor and sensor["name"] == "Battery": self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Life Cycle Rating": battery_life_cycle_rating } \ No newline at end of file From 47b6d34dc69c8517f7864add46a1a3fc4dcc5648 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Mon, 15 Jul 2024 23:32:55 +0200 Subject: [PATCH 17/39] fix: Try for extended handling for EHOSTUNREACH --- custom_components/solarman/api.py | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index 43cba78..567e234 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -1,5 +1,6 @@ import time import yaml +import errno import struct import socket import logging @@ -71,6 +72,11 @@ async def _send_receive_v5_frame(self, data_logging_stick_frame): raise except TimeoutError: raise + except OSError as e: + if e.errno == errno.EHOSTUNREACH: + self.log.debug("[%s] EHOSTUNREACH error: %s", self.serial, e) + self.log.debug("[%s] Send/Receive error: %s", self.serial, e) + raise TimeoutError() except Exception as e: self.log.exception("[%s] Send/Receive error: %s", self.serial, e) raise @@ -104,7 +110,10 @@ async def async_disconnect(self, loud = True) -> None: _LOGGER.debug(f"{e} can be during closing ignored.") finally: self.writer.close() - await self.writer.wait_closed() + try: + await self.writer.wait_closed() + except OSError as e: # Happens when host is unreachable. + _LOGGER.debug(f"{e} can be during closing ignored.") async def async_read(self, params, code, start, end) -> None: length = end - start + 1 From 1c390170e4ed0d3cebb3b57f67801c612d9c8de2 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Tue, 16 Jul 2024 15:06:58 +0200 Subject: [PATCH 18/39] fix: Battery SOH, State and cycles sensors - Reworked and thus removed formulas from definition files fix: SG04LP3 Today sensor back to Daily sensors - Added Battery SOH, State and cycles sensors --- custom_components/solarman/common.py | 8 ++- custom_components/solarman/const.py | 6 +- custom_components/solarman/coordinator.py | 20 +++--- .../inverter_definitions/deye_sg01hp3.yaml | 13 ++-- .../inverter_definitions/deye_sg04lp3.yaml | 52 ++++++++++++--- .../deye_sun-12k-sg04lp3.yaml | 28 +-------- custom_components/solarman/sensor.py | 63 +++++++++++++++++-- 7 files changed, 129 insertions(+), 61 deletions(-) diff --git a/custom_components/solarman/common.py b/custom_components/solarman/common.py index 955ce40..b6b81c9 100644 --- a/custom_components/solarman/common.py +++ b/custom_components/solarman/common.py @@ -28,4 +28,10 @@ def get_request_start(request): return request[REQUEST_START] def get_request_end(request): - return request[REQUEST_END] \ No newline at end of file + return request[REQUEST_END] + +def get_battery_power_capacity(capacity, voltage): + return capacity * voltage / 1000 + +def get_battery_cycles(charge, capacity, voltage): + return charge / get_battery_power_capacity(capacity, voltage) diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index e8e44ba..e439595 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -39,11 +39,11 @@ ACTION_RETRY_ATTEMPTS = 5 TIMINGS_INTERVAL = 5 -TIMINGS_COORDINATOR = td(seconds = TIMINGS_INTERVAL) -TIMINGS_COORDINATOR_TIMEOUT = TIMINGS_INTERVAL * 6 +TIMINGS_UPDATE_INTERVAL = td(seconds = TIMINGS_INTERVAL) +TIMINGS_UPDATE_TIMEOUT = TIMINGS_INTERVAL * 6 TIMINGS_SOCKET_TIMEOUT = TIMINGS_INTERVAL * 3 - 1 TIMINGS_QUERY_INTERVAL_DEFAULT = 60 -TIMINGS_QUERY_EXCEPT_SLEEP = 2 +TIMINGS_QUERY_EXCEPT_SLEEP = 3 REGISTERS_MIN_SPAN_DEFAULT = 25 REGISTERS_DIGITS_DEFAULT = 6 diff --git a/custom_components/solarman/coordinator.py b/custom_components/solarman/coordinator.py index 6904caf..7262229 100644 --- a/custom_components/solarman/coordinator.py +++ b/custom_components/solarman/coordinator.py @@ -14,23 +14,23 @@ class InverterCoordinator(DataUpdateCoordinator[dict[str, Any]]): def __init__(self, hass: HomeAssistant, inverter): - super().__init__(hass, _LOGGER, name = SENSOR_PREFIX, update_interval = TIMINGS_COORDINATOR, always_update = False) + super().__init__(hass, _LOGGER, name = SENSOR_PREFIX, update_interval = TIMINGS_UPDATE_INTERVAL, always_update = False) self.inverter = inverter - self.counter = -1 + self._counter = -1 def _accounting(self): if self.last_update_success: - self.counter += 1 + self._counter += 1 - # Temporary fix to retrieve all data after reconnect - if self.inverter.status != 1: - self.counter = 0 - - return int(self.counter * self._update_interval_seconds) + return int(self._counter * self._update_interval_seconds) async def _async_update_data(self) -> dict[str, Any]: - async with asyncio.timeout(TIMINGS_COORDINATOR_TIMEOUT): - return await self.inverter.async_get(self._accounting()) + try: + async with asyncio.timeout(TIMINGS_UPDATE_TIMEOUT): + return await self.inverter.async_get(self._accounting()) + except Exception: + self._counter = -1 # Temporary fix to retrieve all data after reconnect + raise #async def _reload(self): # _LOGGER.debug('_reload') diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 2739fdf..9883d1c 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -628,8 +628,7 @@ parameters: uom: "" scale: 1 rule: 0 - params: ["Today Battery Charge", "Battery Capacity", "Battery Nominal Voltage"] - formula: "round({0} / ({1} * {2} / 1000), 2)" + digits: 2 icon: "mdi:battery-sync" - name: "Total Battery Life Cycles" @@ -638,8 +637,7 @@ parameters: uom: "" scale: 1 rule: 0 - params: ["Total Battery Charge", "Battery Capacity", "Battery Nominal Voltage"] - formula: "round({0} / ({1} * {2} / 1000), 2)" + digits: 2 icon: "mdi:battery-sync" - name: "Today Energy Export" @@ -993,8 +991,7 @@ parameters: uom: "%" scale: 1 rule: 0 - params: ["Total Battery Charge", "Battery Capacity", "Battery Nominal Voltage", "Battery Life Cycle Rating"] - formula: "round(100 - {0} / ({1} * {2} / 1000) / ({3} * 0.05), 2)" + digits: 2 icon: "mdi:battery-heart" # Battery - The state of battery @@ -1004,9 +1001,7 @@ parameters: uom: "" scale: 1 rule: 0 - params: ["Battery Power", "Battery Power"] - formula: "'discharging' if {0} > 50 else 'charging' if {1} < -50 else 'static'" - isstr: true + digits: 2 icon: "mdi:battery" # Battery - The current of battery 1 is S16bit (low 16 bits) diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 97c8ce2..414f146 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -591,7 +591,7 @@ parameters: - group: Meter items: - - name: "Today Battery Charge" + - name: "Daily Battery Charge" class: "energy" state_class: "total_increasing" uom: "kWh" @@ -600,7 +600,7 @@ parameters: registers: [0x0202] icon: "mdi:battery-plus" - - name: "Today Battery Discharge" + - name: "Daily Battery Discharge" class: "energy" state_class: "total_increasing" uom: "kWh" @@ -627,7 +627,25 @@ parameters: registers: [0x0206, 0x0207] icon: "mdi:battery-minus" - - name: "Today Energy Bought" + - name: "Daily Battery Life Cycles" + class: "" + state_class: "total_increasing" + uom: "" + scale: 1 + rule: 0 + digits: 2 + icon: "mdi:battery-sync" + + - name: "Total Battery Life Cycles" + class: "" + state_class: "total_increasing" + uom: "" + scale: 1 + rule: 0 + digits: 2 + icon: "mdi:battery-sync" + + - name: "Daily Energy Bought" class: "energy" state_class: "total_increasing" uom: "kWh" @@ -636,7 +654,7 @@ parameters: registers: [0x0208] icon: "mdi:transmission-tower-export" - - name: "Today Energy Sold" + - name: "Daily Energy Sold" class: "energy" state_class: "total_increasing" uom: "kWh" @@ -663,7 +681,7 @@ parameters: registers: [0x020C, 0x020D] icon: "mdi:transmission-tower-import" - - name: "Today Load Consumption" + - name: "Daily Load Consumption" class: "energy" state_class: "total_increasing" uom: "kWh" @@ -679,7 +697,7 @@ parameters: rule: 3 registers: [0x020F, 0x0210] - - name: "Today Losses" + - name: "Daily Losses" class: "energy" state_class: "total_increasing" uom: "kWh" @@ -741,7 +759,7 @@ parameters: scale: 0.1 registers: [0x0204, 0x0205] - - name: "Today Production" + - name: "Daily Production" class: "energy" state_class: "total_increasing" uom: "kWh" @@ -985,6 +1003,26 @@ parameters: rule: 2 registers: [0x024E] + # Battery - The state of health + - name: "Battery SOH" + class: "" + state_class: "measurement" + uom: "%" + scale: 1 + rule: 0 + digits: 2 + icon: "mdi:battery-heart" + + # Battery - The state of battery + - name: "Battery State" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 0 + digits: 2 + icon: "mdi:battery" + # Battery - The current of battery 1 is S16bit (low 16 bits) - name: "Battery Current" class: "current" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 52839ec..3620d72 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -636,13 +636,7 @@ parameters: uom: "" scale: 1 rule: 0 - params: - [ - "Today Battery Charge", - "Battery Capacity", - "Battery Nominal Voltage", - ] - formula: "round({0} / ({1} * {2} / 1000), 2)" + digits: 2 icon: "mdi:battery-sync" - name: "Total Battery Life Cycles" @@ -651,13 +645,7 @@ parameters: uom: "" scale: 1 rule: 0 - params: - [ - "Total Battery Charge", - "Battery Capacity", - "Battery Nominal Voltage", - ] - formula: "round({0} / ({1} * {2} / 1000), 2)" + digits: 2 icon: "mdi:battery-sync" - name: "Today Energy Bought" @@ -1025,14 +1013,7 @@ parameters: uom: "%" scale: 1 rule: 0 - params: - [ - "Total Battery Charge", - "Battery Capacity", - "Battery Nominal Voltage", - "Battery Life Cycle Rating", - ] - formula: "round(100 - {0} / ({1} * {2} / 1000) / ({3} * 0.05), 2)" + digits: 2 icon: "mdi:battery-heart" # Battery - The state of battery @@ -1042,9 +1023,6 @@ parameters: uom: "" scale: 1 rule: 0 - params: ["Battery Power", "Battery Power"] - formula: "'discharging' if {0} > 50 else 'charging' if {1} < -50 else 'static'" - isstr: true icon: "mdi:battery" # Battery - The current of battery 1 is S16bit (low 16 bits) diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 6032032..f36e6b5 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -22,12 +22,14 @@ _LOGGER = logging.getLogger(__name__) -def _create_sensor(coordinator, sensor, battery_life_cycle_rating): +def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating): try: if "artificial" in sensor: entity = SolarmanStatus(coordinator, sensor) elif "isstr" in sensor: entity = SolarmanSensorBase(coordinator, sensor) + elif sensor["name"] in ("Battery SOH", "Battery State", "Today Battery Life Cycles", "Total Battery Life Cycles"): + entity = SolarmanBatterySensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) else: entity = SolarmanSensor(coordinator, sensor, battery_life_cycle_rating) @@ -49,6 +51,7 @@ async def async_setup(hass: HomeAssistant, config, async_add_entities: AddEntiti inverter_mb_slave_id = config.get(CONF_INVERTER_MB_SLAVE_ID) lookup_path = hass.config.path(LOOKUP_DIRECTORY_PATH) lookup_file = config.get(CONF_LOOKUP_FILE) + battery_nominal_voltage = config.get(CONF_BATTERY_NOMINAL_VOLTAGE) battery_life_cycle_rating = config.get(CONF_BATTERY_LIFE_CYCLE_RATING) inverter_discovery = InverterDiscovery(hass, inverter_host) @@ -92,7 +95,7 @@ async def async_setup(hass: HomeAssistant, config, async_add_entities: AddEntiti # _LOGGER.debug(f"async_setup: async_add_entities") - async_add_entities(_create_sensor(coordinator, sensor, battery_life_cycle_rating) for sensor in sensors) + async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors) # Register the services with home assistant. # @@ -180,24 +183,38 @@ def __init__(self, coordinator, sensor): if "state_class" in sensor and sensor["state_class"]: self._attr_extra_state_attributes = { "state_class": sensor["state_class"] } + self._digits = sensor["digits"] if "digits" in sensor else REGISTERS_DIGITS_DEFAULT + self._attr_entity_category = (None) self._attr_icon = sensor["icon"] if "icon" in sensor else None self.attributes = sensor["attributes"] if "attributes" in sensor else None + def get_data_state(self, name): + return self.coordinator.data[name]["state"] + + def get_data_value(self, name): + return self.coordinator.data[name]["value"] + + def get_data(self, name, default): + if name in self.coordinator.data: + return self.get_data_state(name) + + return default + def update(self): c = len(self.coordinator.data) if c > 1 or (c == 1 and self.sensor_name in self.coordinator.data): if self.sensor_name in self.coordinator.data: - self._attr_state = self.coordinator.data[self.sensor_name]["state"] + self._attr_state = self.get_data_state(self.sensor_name) if "value" in self.coordinator.data[self.sensor_name]: - self._attr_extra_state_attributes["value"] = self.coordinator.data[self.sensor_name]["value"] + self._attr_extra_state_attributes["value"] = self.get_data_value(self.sensor_name) if self.attributes: for attr in self.attributes: if attr in self.coordinator.data: attr_name = attr.replace(f"{self.sensor_name} ", "") - self._attr_extra_state_attributes[attr_name] = self.coordinator.data[attr]["state"] + self._attr_extra_state_attributes[attr_name] = self.get_data_state(attr) class SolarmanSensor(SolarmanSensorBase): def __init__(self, coordinator, sensor, battery_life_cycle_rating): @@ -220,4 +237,38 @@ def __init__(self, coordinator, sensor, battery_life_cycle_rating): self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "options": options } if "name" in sensor and sensor["name"] == "Battery": - self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Life Cycle Rating": battery_life_cycle_rating } \ No newline at end of file + self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Life Cycle Rating": battery_life_cycle_rating } + +class SolarmanBatterySensor(SolarmanSensor): + def __init__(self, coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating): + SolarmanSensor.__init__(self, coordinator, sensor, battery_life_cycle_rating) + self._battery_nominal_voltage = battery_nominal_voltage + self._battery_life_cycle_rating = battery_life_cycle_rating + + def update(self): + #super().update() + c = len(self.coordinator.data) + if c > 1 or (c == 1 and self.sensor_name in self.coordinator.data): + match self.sensor_name: + case "Battery SOH": + battery_capacity = self.get_data("Battery Capacity", None) + total_battery_charge = self.get_data("Total Battery Charge", None) + today_battery_charge = self.get_data("Today Battery Charge", None) + if total_battery_charge and battery_capacity and self._battery_nominal_voltage and self._battery_life_cycle_rating: + self._attr_state = round(100 - total_battery_charge / get_battery_power_capacity(battery_capacity, self._battery_nominal_voltage) / (self._battery_life_cycle_rating * 0.05), self._digits) + case "Battery State": + battery_power = self.get_data("Battery Power", None) + if battery_power: + self._attr_state = "discharging" if battery_power > 50 else "charging" if battery_power < -50 else "standby" + case "Today Battery Life Cycles": + battery_capacity = self.get_data("Battery Capacity", None) + total_battery_charge = self.get_data("Total Battery Charge", None) + today_battery_charge = self.get_data("Today Battery Charge", None) + if today_battery_charge and battery_capacity and self._battery_nominal_voltage: + self._attr_state = round(get_battery_cycles(today_battery_charge, battery_capacity, self._battery_nominal_voltage), self._digits) + case "Total Battery Life Cycles": + battery_capacity = self.get_data("Battery Capacity", None) + total_battery_charge = self.get_data("Total Battery Charge", None) + today_battery_charge = self.get_data("Today Battery Charge", None) + if total_battery_charge and battery_capacity and self._battery_nominal_voltage: + self._attr_state = round(get_battery_cycles(total_battery_charge, battery_capacity, self._battery_nominal_voltage), self._digits) From 09426ff125c9955fb2efb330a770bf5ba43ac716 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Tue, 16 Jul 2024 15:27:38 +0200 Subject: [PATCH 19/39] refactor: readme.md added links --- readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/readme.md b/readme.md index a41bc86..77f578f 100644 --- a/readme.md +++ b/readme.md @@ -1,7 +1,7 @@ # ⚡ Solarman Stick Logger integration > [!NOTE] -> Use 💬 Discussions for 🙏 Q&A and 💡 Development Planning, etc. and leave 🚩 Issues for 🐞 bug reporting, 🎁 feature requests and such... +> Use [💬 Discussions](https://github.com/davidrapan/ha-solarman/discussions) for 🙏 Q&A and 💡 Development Planning, etc. and leave [🚩 Issues](https://github.com/davidrapan/ha-solarman/issues) for 🐞 bug reporting, 🎁 feature requests and such... > [!NOTE] > It's still 🚧 work in progress but currently very 🐎 stable 😉 From bd2a1a1942b30980249da8eb90a67202fed6405e Mon Sep 17 00:00:00 2001 From: David Rapan Date: Tue, 16 Jul 2024 16:51:34 +0200 Subject: [PATCH 20/39] fix: rounding of whole numbers (integers) fix: Properly handle uint of custom sensors fix: readme.md feature set updated according to the recent changes --- custom_components/solarman/common.py | 3 +++ .../solarman/inverter_definitions/deye_sg01hp3.yaml | 1 + .../solarman/inverter_definitions/deye_sg04lp3.yaml | 1 + .../inverter_definitions/deye_sun-12k-sg04lp3.yaml | 1 + custom_components/solarman/parser.py | 13 +++++-------- custom_components/solarman/sensor.py | 7 +++---- readme.md | 7 +++---- 7 files changed, 17 insertions(+), 16 deletions(-) diff --git a/custom_components/solarman/common.py b/custom_components/solarman/common.py index b6b81c9..8f0e93d 100644 --- a/custom_components/solarman/common.py +++ b/custom_components/solarman/common.py @@ -21,6 +21,9 @@ def format_exception(e): def Raise(exception) -> None: raise exception +def get_number(value, digits): + return int(value) if isinstance(value, int) or (isinstance(value, float) and value.is_integer()) else (n if (n := round(value, digits)) and not n.is_integer() else int(n)) + def get_request_code(request): return request[REQUEST_CODE] if REQUEST_CODE in request else request[REQUEST_CODE_ALT] diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 9883d1c..6e765f0 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -1361,6 +1361,7 @@ parameters: rule: 1 digits: 0 registers: [0x024E, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x027C, 0x02B6] + uint: enforce sensors: - signed: scale: 10 diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 414f146..121d2ee 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -1376,6 +1376,7 @@ parameters: rule: 1 digits: 0 registers: [0x024E, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x027C, 0x02B6] + uint: enforce sensors: - signed: registers: [0x024E] diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 3620d72..3590906 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -1379,6 +1379,7 @@ parameters: rule: 1 digits: 0 registers: [0x024E, 0x02A0, 0x02A1, 0x02A2, 0x02A3, 0x027C, 0x02B6] + uint: enforce sensors: - signed: registers: [0x024E] diff --git a/custom_components/solarman/parser.py b/custom_components/solarman/parser.py index 58d26dc..463d874 100644 --- a/custom_components/solarman/parser.py +++ b/custom_components/solarman/parser.py @@ -53,12 +53,6 @@ def set_state(self, key, value): self._result[key] = {} self._result[key]["state"] = value - def set_state_number(self, key, value, digits): - if isinstance(value, int) or (isinstance(value, float) and value.is_integer()): - self.set_state(key, int(value)) - else: - self.set_state(key, round(value, digits)) - def get_sensors(self): result = [{"name": "Connection Status", "artificial": ""}] for i in self.lookup(): @@ -242,6 +236,9 @@ def try_parse_unsigned(self, rawData, definition, start, length): found = value is not None if found: + if "uint" in definition and value < 0: + value = 0 + if "lookup" in definition: self.set_state(key, self.lookup_value(value, definition["lookup"])) self._result[key]["value"] = int(value) @@ -250,7 +247,7 @@ def try_parse_unsigned(self, rawData, definition, start, length): if not self.do_validate(key, value, definition["validation"]): return - self.set_state_number(key, value, definition["digits"] if "digits" in definition else self._digits) + self.set_state(key, get_number(value, definition["digits"] if "digits" in definition else self._digits)) return @@ -263,7 +260,7 @@ def try_parse_signed(self, rawData, definition, start, length): if not self.do_validate(key, value, definition["validation"]): return - self.set_state_number(key, value, definition["digits"] if "digits" in definition else self._digits) + self.set_state(key, get_number(value, definition["digits"] if "digits" in definition else self._digits)) return diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index f36e6b5..1e38bd6 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -1,6 +1,5 @@ from __future__ import annotations -import re import logging import asyncio import voluptuous as vol @@ -255,7 +254,7 @@ def update(self): total_battery_charge = self.get_data("Total Battery Charge", None) today_battery_charge = self.get_data("Today Battery Charge", None) if total_battery_charge and battery_capacity and self._battery_nominal_voltage and self._battery_life_cycle_rating: - self._attr_state = round(100 - total_battery_charge / get_battery_power_capacity(battery_capacity, self._battery_nominal_voltage) / (self._battery_life_cycle_rating * 0.05), self._digits) + self._attr_state = get_number(100 - total_battery_charge / get_battery_power_capacity(battery_capacity, self._battery_nominal_voltage) / (self._battery_life_cycle_rating * 0.05), self._digits) case "Battery State": battery_power = self.get_data("Battery Power", None) if battery_power: @@ -265,10 +264,10 @@ def update(self): total_battery_charge = self.get_data("Total Battery Charge", None) today_battery_charge = self.get_data("Today Battery Charge", None) if today_battery_charge and battery_capacity and self._battery_nominal_voltage: - self._attr_state = round(get_battery_cycles(today_battery_charge, battery_capacity, self._battery_nominal_voltage), self._digits) + self._attr_state = get_number(get_battery_cycles(today_battery_charge, battery_capacity, self._battery_nominal_voltage), self._digits) case "Total Battery Life Cycles": battery_capacity = self.get_data("Battery Capacity", None) total_battery_charge = self.get_data("Total Battery Charge", None) today_battery_charge = self.get_data("Today Battery Charge", None) if total_battery_charge and battery_capacity and self._battery_nominal_voltage: - self._attr_state = round(get_battery_cycles(total_battery_charge, battery_capacity, self._battery_nominal_voltage), self._digits) + self._attr_state = get_number(get_battery_cycles(total_battery_charge, battery_capacity, self._battery_nominal_voltage), self._digits) diff --git a/readme.md b/readme.md index 77f578f..5b338c4 100644 --- a/readme.md +++ b/readme.md @@ -13,12 +13,11 @@ > - Fetching is implemented through DataUpdateCoordinator + incorporates many more up to date features of HA > - Improved stability (no more disconnects and missing values) > - Discovery and not just for configuration but also as part of initialization (i.e. adapts to changed IP) -> - Registers which are requested are decided dynamically (when missing from the inverter definition file) -> - Different registers can be requested in different intervals according to their 'update_interval' set in inverter definition file > - New Inverter profiles features **See 'deye_sg04lp3.yaml' for examples*: +> - Different registers can be requested in different intervals according to their 'update_interval' set in inverter definition file +> - Registers which will be part of a request are decided dynamically (when missing from the inverter definition file) > - Added attribute type of a sensor which can be attached to any other sensor -> - Added template sensors defined by simple formulas and parameters which are then evaluated during runtime -> - Added configuration for Battery Nominal Voltage and Battery Life Cycle Rating for calculating SOH of the battery +> - Added configuration for Battery Nominal Voltage and Battery Life Cycle Rating for calculating SOH and life cycles of the battery > - And many more fixes and improvements (while trying to fully preserve backward compatibility) > [!WARNING] From 4cae460465437b60134684842ec44ad789367d00 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Tue, 16 Jul 2024 17:31:29 +0200 Subject: [PATCH 21/39] feat: readme.md Added link pointing to Milestones --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 5b338c4..ff122ab 100644 --- a/readme.md +++ b/readme.md @@ -1,6 +1,7 @@ # ⚡ Solarman Stick Logger integration > [!NOTE] +> If you are curious about what's planned next look into [🪧 Milestones](https://github.com/davidrapan/ha-solarman/milestones) > Use [💬 Discussions](https://github.com/davidrapan/ha-solarman/discussions) for 🙏 Q&A and 💡 Development Planning, etc. and leave [🚩 Issues](https://github.com/davidrapan/ha-solarman/issues) for 🐞 bug reporting, 🎁 feature requests and such... > [!NOTE] @@ -21,7 +22,7 @@ > - And many more fixes and improvements (while trying to fully preserve backward compatibility) > [!WARNING] -> Is note worthy that some names of the SG04LP3 sensors did change for different reasons (some were due to aestetics, etc.) +> It's note worthy that some names of the SG04LP3 sensors did change for different reasons (some were due to aestetics, etc.) > So look through the file and change them as you see fit manually before I'll make it available from the HA configuration. > One more thing.. It's not possible to use this integration side by side (with the same device) with the implementation from Stephan! It will override it. > TODO: Rest of the info... 😃 From a9572cb4fc813abf59bdb6b1b7ef587609286fa4 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Tue, 16 Jul 2024 18:56:12 +0200 Subject: [PATCH 22/39] feat: Signed sensor can be defined as inverted feat: Entity ID can be set manually --- .../inverter_definitions/deye_sg01hp3.yaml | 2 +- .../inverter_definitions/deye_sg04lp3.yaml | 2 +- .../deye_sun-12k-sg04lp3.yaml | 27 ++++++++++++++++++- custom_components/solarman/parser.py | 3 +++ custom_components/solarman/sensor.py | 16 +++++++---- 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 6e765f0..829f43c 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -975,7 +975,7 @@ parameters: "Battery Grid Charging Current", ] - # Battery - The power of battery is S16bit (low 16 bits | L:1W, H:10W) + # Battery - The power of battery is S16bit - name: "Battery Power" class: "power" state_class: "measurement" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 121d2ee..4e90bf9 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -994,7 +994,7 @@ parameters: "Battery Grid Charging Current", ] - # Battery - The power of battery is S16bit (low 16 bits | L:1W, H:10W) + # Battery - The power of battery is S16bit - name: "Battery Power" class: "power" state_class: "measurement" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 3590906..8a69a3c 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -997,7 +997,7 @@ parameters: "Battery Grid Charging Current", ] - # Battery - The power of battery is S16bit (low 16 bits | L:1W, H:10W) + # Battery - The power of battery is S16bit - name: "Battery Power" class: "power" state_class: "measurement" @@ -1006,6 +1006,17 @@ parameters: rule: 2 registers: [0x024E] + # Battery - The inverted power of battery is S16bit + - name: "Battery Power ∇" + entity_id: "battery_power_inverted" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 2 + inverted: True + registers: [0x024E] + # Battery - The state of health - name: "Battery SOH" class: "" @@ -1275,6 +1286,20 @@ parameters: icon: "mdi:transmission-tower" attributes: ["Zero Export"] + # Grid - The inverted power is S16bit (low 16 bits) + S16bit (high 16 bits) + - name: "Grid Power ∇" + entity_id: "grid_power_inverted" + realtime: + class: "measurement" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 4 + inverted: True + registers: [0x0271, 0x02B2] + icon: "mdi:transmission-tower" + attributes: ["Zero Export"] + - group: Inverter items: # Inverter output - The voltage of phase A diff --git a/custom_components/solarman/parser.py b/custom_components/solarman/parser.py index 463d874..fadab8f 100644 --- a/custom_components/solarman/parser.py +++ b/custom_components/solarman/parser.py @@ -256,6 +256,9 @@ def try_parse_signed(self, rawData, definition, start, length): value = self._read_registers_signed(rawData, definition, start, length) if value is not None: + if "inverted" in definition and definition["inverted"]: + value = -value + if "validation" in definition: if not self.do_validate(key, value, definition["validation"]): return diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 1e38bd6..594cc46 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -141,18 +141,24 @@ class SolarmanStatus(SolarmanCoordinatorEntity): def __init__(self, coordinator, sensor): super().__init__(coordinator) self.sensor_name = sensor["name"] + self.sensor_entity_id = sensor["entity_id"] if "entity_id" in sensor else None + self.sensor_unique_id = self.sensor_entity_id if self.sensor_entity_id else self.sensor_name - # Return the category of the sensor. + # Set the category of the sensor. self._attr_entity_category = (EntityCategory.DIAGNOSTIC) - # Return the icon of the sensor. + # Set the icon of the sensor. self._attr_icon = "mdi:information" - # Return the name of the sensor. + # Set the name of the sensor. self._attr_name = "{} {}".format(self.coordinator.inverter.name, self.sensor_name) - # Return a unique_id based on the serial number - self._attr_unique_id = "{}_{}_{}".format(self.coordinator.inverter.name, self.coordinator.inverter.serial, self.sensor_name) + # Set the entity_id of the sensor. + if self.sensor_entity_id: + self.entity_id = "sensor.{}_{}".format(self.coordinator.inverter.name, self.sensor_entity_id) + + # Set a unique_id based on the serial number + self._attr_unique_id = "{}_{}_{}".format(self.coordinator.inverter.name, self.coordinator.inverter.serial, self.sensor_unique_id) @property def available(self) -> bool: From 80f1c77323a58e89bcb28abacace0d16b1b0c73e Mon Sep 17 00:00:00 2001 From: David Rapan Date: Wed, 17 Jul 2024 00:25:00 +0200 Subject: [PATCH 23/39] feat: readme.md Added shields.io --- readme.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/readme.md b/readme.md index ff122ab..5146764 100644 --- a/readme.md +++ b/readme.md @@ -1,5 +1,11 @@ # ⚡ Solarman Stick Logger integration +[![Stable](https://img.shields.io/github/release/davidrapan/ha-solarman.svg)](https://github.com/davidrapan/ha-solarman/releases/latest) +[![GitHub Activity](https://img.shields.io/github/commit-activity/y/davidrapan/ha-solarman.svg?label=commits)](https://github.com/davidrapan/ha-solarman/commits/main) +[![License](https://img.shields.io/github/license/davidrapan/ha-solarman.svg)](LICENSE) +[![HACS Supported](https://img.shields.io/badge/HACS-Supported-green.svg)](https://github.com/custom-components/hacs) +[![Discussions](https://img.shields.io/badge/community-discussions-brightgreen.svg)](https://github.com/davidrapan/ha-solarman/discussions) + > [!NOTE] > If you are curious about what's planned next look into [🪧 Milestones](https://github.com/davidrapan/ha-solarman/milestones) > Use [💬 Discussions](https://github.com/davidrapan/ha-solarman/discussions) for 🙏 Q&A and 💡 Development Planning, etc. and leave [🚩 Issues](https://github.com/davidrapan/ha-solarman/issues) for 🐞 bug reporting, 🎁 feature requests and such... From 3d2cda2e2f1949757ee6c102105860f51a2a3e0e Mon Sep 17 00:00:00 2001 From: David Rapan Date: Wed, 17 Jul 2024 11:07:33 +0200 Subject: [PATCH 24/39] refactor: Separated Coordinator initialization refactor: Separated entities from sensor platform feat: Added Switch platform feat: added SwitchEntity for Solar Sell --- custom_components/solarman/__init__.py | 83 +++++++- custom_components/solarman/api.py | 31 +-- custom_components/solarman/common.py | 10 + custom_components/solarman/const.py | 3 +- custom_components/solarman/coordinator.py | 2 +- custom_components/solarman/entity.py | 116 ++++++++++++ .../inverter_definitions/deye_sg01hp3.yaml | 39 +++- .../inverter_definitions/deye_sg04lp3.yaml | 12 ++ .../deye_sun-12k-sg04lp3.yaml | 12 ++ custom_components/solarman/sensor.py | 177 +++--------------- custom_components/solarman/services.py | 6 +- custom_components/solarman/switch.py | 98 ++++++++++ 12 files changed, 403 insertions(+), 186 deletions(-) create mode 100644 custom_components/solarman/entity.py create mode 100644 custom_components/solarman/switch.py diff --git a/custom_components/solarman/__init__.py b/custom_components/solarman/__init__.py index b27d6c2..0363892 100644 --- a/custom_components/solarman/__init__.py +++ b/custom_components/solarman/__init__.py @@ -2,22 +2,89 @@ import logging +from homeassistant.const import CONF_NAME from homeassistant.core import HomeAssistant from homeassistant.config_entries import ConfigEntry from .const import * +from .common import * +from .api import Inverter +from .discovery import InverterDiscovery +from .coordinator import InverterCoordinator from .config_flow import async_update_listener +from .services import * _LOGGER = logging.getLogger(__name__) -async def async_setup_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: - _LOGGER.debug(f"async_setup_entry({entry.as_dict()})") - await hass.config_entries.async_forward_entry_setups(entry, PLATFORMS) - entry.async_on_unload(entry.add_update_listener(async_update_listener)) +async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: + _LOGGER.debug(f"async_setup_entry({config.as_dict()})") + + options = config.options + + inverter_name = options.get(CONF_NAME) + inverter_host = options.get(CONF_INVERTER_HOST) + inverter_serial = options.get(CONF_INVERTER_SERIAL) + inverter_port = options.get(CONF_INVERTER_PORT) + inverter_mb_slave_id = options.get(CONF_INVERTER_MB_SLAVE_ID) + lookup_path = hass.config.path(LOOKUP_DIRECTORY_PATH) + lookup_file = options.get(CONF_LOOKUP_FILE) + + inverter_discovery = InverterDiscovery(hass, inverter_host) + + if inverter_discovery: + if inverter_host_scanned := await inverter_discovery.get_ip(): + inverter_host = inverter_host_scanned + + if inverter_serial == 0: + if inverter_serial_scanned := await inverter_discovery.get_serial(): + inverter_serial = inverter_serial_scanned + + inverter_mac = await inverter_discovery.get_mac() + + if inverter_host is None: + raise vol.Invalid("Configuration parameter [inverter_host] does not have a value") + if inverter_serial is None: + raise vol.Invalid("Configuration parameter [inverter_serial] does not have a value") + if inverter_port is None: + raise vol.Invalid("Configuration parameter [inverter_port] does not have a value") + if not inverter_mb_slave_id: + inverter_mb_slave_id = DEFAULT_INVERTER_MB_SLAVE_ID + + inverter = Inverter(inverter_host, inverter_serial, inverter_port, inverter_mb_slave_id, inverter_name, inverter_mac, lookup_path, lookup_file) + + await inverter.load() + + coordinator = InverterCoordinator(hass, inverter) + + hass.data.setdefault(DOMAIN, {})[config.entry_id] = coordinator + + # Fetch initial data so we have data when entities subscribe. + # + # If the refresh fails, async_config_entry_first_refresh will + # raise ConfigEntryNotReady and setup will try again later. + # + # If you do not want to retry setup on failure, use + # coordinator.async_refresh() instead. + # + _LOGGER.debug(f"async_setup: coordinator.async_config_entry_first_refresh") + + await coordinator.async_config_entry_first_refresh() + + # Register the services with home assistant. + # + _LOGGER.debug(f"async_setup: register_services") + + register_services(hass, inverter) + + # Forward setup + # + await hass.config_entries.async_forward_entry_setups(config, PLATFORMS) + config.async_on_unload(config.add_update_listener(async_update_listener)) return True -async def async_unload_entry(hass: HomeAssistant, entry: ConfigEntry) -> bool: - _LOGGER.debug(f"async_unload_entry({entry.as_dict()})") - if unload_ok := await hass.config_entries.async_unload_platforms(entry, PLATFORMS): - _ = hass.data[DOMAIN].pop(entry.entry_id) +async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: + _LOGGER.debug(f"async_unload_entry({config.as_dict()})") + if unload_ok := await hass.config_entries.async_unload_platforms(config, PLATFORMS): + _ = hass.data[DOMAIN].pop(config.entry_id) + remove_services(hass) return unload_ok diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index 567e234..a98c132 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -1,11 +1,9 @@ import time -import yaml import errno import struct import socket import logging import asyncio -import aiofiles import threading import concurrent.futures @@ -136,9 +134,12 @@ def __init__(self, address, serial, port, mb_slave_id, name, mac, lookup_path, l self.lookup_path = lookup_path self.lookup_file = lookup_file if lookup_file and not lookup_file == "parameters.yaml" else "deye_hybrid.yaml" - async def get_sensors(self): - async with aiofiles.open(self.lookup_path + self.lookup_file) as f: - self.parameter_definition = yaml.safe_load(await f.read()) + #execute_async(self.load()) + + async def load(self): + self.parameter_definition = await yaml_open(self.lookup_path + self.lookup_file) + + def get_sensors(self): if self.parameter_definition: params = ParameterParser(self.parameter_definition) return params.get_sensors() @@ -221,20 +222,22 @@ async def service_write_holding_register(self, register, value) -> bool: _LOGGER.debug(f"service_write_holding_register: {register}, value: {value}") try: await self.async_connect() - await self.write_holding_register(register, value) + response = await self.write_holding_register(register, value) + _LOGGER.debug(f"service_write_holding_register: {register}, response: {response}") except Exception as e: _LOGGER.warning(f"service_write_holding_register: {register}, value: {value} failed. [{format_exception(e)}]") - await self.async_disconnect() - return False + #await self.async_disconnect() + raise return True - async def service_write_multiple_holding_registers(self, registers, values) -> bool: - _LOGGER.debug(f"service_write_multiple_holding_registers: {registers}, values: {values}") + async def service_write_multiple_holding_registers(self, register, values) -> bool: + _LOGGER.debug(f"service_write_multiple_holding_registers: {register}, values: {values}") try: await self.async_connect() - await self.write_multiple_holding_registers(registers, values) + response = await self.write_multiple_holding_registers(register, values) + _LOGGER.debug(f"service_write_multiple_holding_register: {register}, response: {response}") except Exception as e: - _LOGGER.warning(f"service_write_multiple_holding_registers: {registers}, values: {values} failed. [{format_exception(e)}]") - await self.async_disconnect() - return False + _LOGGER.warning(f"service_write_multiple_holding_registers: {register}, values: {values} failed. [{format_exception(e)}]") + #await self.async_disconnect() + raise return True diff --git a/custom_components/solarman/common.py b/custom_components/solarman/common.py index 8f0e93d..0f3551f 100644 --- a/custom_components/solarman/common.py +++ b/custom_components/solarman/common.py @@ -1,4 +1,6 @@ +import yaml import asyncio +import aiofiles from .const import * @@ -6,6 +8,14 @@ async def async_execute(x): loop = asyncio.get_running_loop() return await loop.run_in_executor(None, x) +def execute_async(x): + loop = asyncio.get_event_loop() + return loop.run_until_complete(x) + +async def yaml_open(file): + async with aiofiles.open(file) as f: + return yaml.safe_load(await f.read()) + def group_when(iterable, predicate): i, x, size = 0, 0, len(iterable) while i < size - 1: diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index e439595..a996a7a 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -1,8 +1,7 @@ from datetime import timedelta as td DOMAIN = "solarman" -PLATFORMS: list[str] = ["sensor"] -SENSOR_PREFIX = "Solarman" +PLATFORMS: list[str] = ["sensor", "switch"] IP_BROADCAST = "" IP_ANY = "0.0.0.0" diff --git a/custom_components/solarman/coordinator.py b/custom_components/solarman/coordinator.py index 7262229..a3cdd5c 100644 --- a/custom_components/solarman/coordinator.py +++ b/custom_components/solarman/coordinator.py @@ -14,7 +14,7 @@ class InverterCoordinator(DataUpdateCoordinator[dict[str, Any]]): def __init__(self, hass: HomeAssistant, inverter): - super().__init__(hass, _LOGGER, name = SENSOR_PREFIX, update_interval = TIMINGS_UPDATE_INTERVAL, always_update = False) + super().__init__(hass, _LOGGER, name = inverter.name, update_interval = TIMINGS_UPDATE_INTERVAL, always_update = False) self.inverter = inverter self._counter = -1 diff --git a/custom_components/solarman/entity.py b/custom_components/solarman/entity.py new file mode 100644 index 0000000..5f7d341 --- /dev/null +++ b/custom_components/solarman/entity.py @@ -0,0 +1,116 @@ +from __future__ import annotations + +import logging +import asyncio +import voluptuous as vol + +from functools import cached_property, partial + +from homeassistant.components.template.sensor import SensorTemplate +from homeassistant.components.template.sensor import TriggerSensorEntity +from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription +from homeassistant.helpers.template import Template + +from homeassistant.core import HomeAssistant, callback +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_NAME, EntityCategory, STATE_OFF, STATE_ON +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo, format_mac +from homeassistant.helpers.entity import Entity, ToggleEntity +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import * +from .common import * +from .services import * +from .api import Inverter +from .discovery import InverterDiscovery +from .coordinator import InverterCoordinator + +_LOGGER = logging.getLogger(__name__) + +class SolarmanCoordinatorEntity(CoordinatorEntity[InverterCoordinator]): + def __init__(self, coordinator: InverterCoordinator, name: str = None): + super().__init__(coordinator) + self.model = self.coordinator.inverter.lookup_file.replace(".yaml", "") + + if '_' in self.model: + dev_man = self.model.split('_') + self.manufacturer = dev_man[0].capitalize() + self.model = dev_man[1].upper() + + self._attr_device_info = { + "connections": {(CONNECTION_NETWORK_MAC, format_mac(self.coordinator.inverter.mac))} + } if self.coordinator.inverter.mac else {} | { + "identifiers": {(DOMAIN, self.coordinator.inverter.serial)}, + "name": self.coordinator.inverter.name, + "manufacturer": self.manufacturer, + "model": self.model, + "serial_number": self.coordinator.inverter.serial + } + + #self._attr_extra_state_attributes = { "id": self.coordinator.inverter.serial, "integration": DOMAIN } + self._attr_extra_state_attributes = {} + +class SolarmanEntity(SolarmanCoordinatorEntity): + def __init__(self, coordinator, sensor): + super().__init__(coordinator) + self.sensor_name = sensor["name"] + self.sensor_entity_id = sensor["entity_id"] if "entity_id" in sensor else None + self.sensor_unique_id = self.sensor_entity_id if self.sensor_entity_id else self.sensor_name + + # Set the category of the sensor. + self._attr_entity_category = (None) + + # Set the icon of the sensor. + self._attr_icon = "mdi:information" + + # Set the name of the sensor. + self._attr_name = "{} {}".format(self.coordinator.inverter.name, self.sensor_name) + + # Set the entity_id of the sensor. + if self.sensor_entity_id: + self.entity_id = "sensor.{}_{}".format(self.coordinator.inverter.name, self.sensor_entity_id) + + # Set a unique_id based on the serial number + self._attr_unique_id = "{}_{}_{}".format(self.coordinator.inverter.name, self.coordinator.inverter.serial, self.sensor_unique_id) + + @property + def available(self) -> bool: + """Return if entity is available.""" + return self._attr_available and self.coordinator.inverter.is_connected() + + @callback + def _handle_coordinator_update(self) -> None: + """Handle updated data from the coordinator.""" + self.update() + self.async_write_ha_state() + +class SolarmanBaseEntity(SolarmanEntity): + def __init__(self, coordinator, sensor): + super().__init__(coordinator, sensor) + self._attr_entity_registry_enabled_default = not "disabled" in sensor + + def get_data_state(self, name): + return self.coordinator.data[name]["state"] + + def get_data_value(self, name): + return self.coordinator.data[name]["value"] + + def get_data(self, name, default): + if name in self.coordinator.data: + return self.get_data_state(name) + + return default + + def update(self): + c = len(self.coordinator.data) + if c > 1 or (c == 1 and self.sensor_name in self.coordinator.data): + if self.sensor_name in self.coordinator.data: + self._attr_state = self.get_data_state(self.sensor_name) + if "value" in self.coordinator.data[self.sensor_name]: + self._attr_extra_state_attributes["value"] = self.get_data_value(self.sensor_name) + if self.attributes: + for attr in self.attributes: + if attr in self.coordinator.data: + attr_name = attr.replace(f"{self.sensor_name} ", "") + self._attr_extra_state_attributes[attr_name] = self.get_data_state(attr) \ No newline at end of file diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 829f43c..0e87d9c 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -27,7 +27,7 @@ parameters: "LV 3-Phase Hybrid Inverter", "HV 3-Phase Hybrid Inverter", "HV 3-Phase Inverter 6-15kw", - "HV 3-Phase Inverter 20-50kw" + "HV 3-Phase Inverter 20-50kw", ] lookup: - key: 0x0200 @@ -366,6 +366,18 @@ parameters: - key: "default" value: "On" + - group: Solar Sell + items: + - name: "Solar Sell" + update_interval: 30 + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + switch: True + registers: [0x0091] + - group: BMS items: - name: "BMS Charging Voltage" @@ -722,7 +734,21 @@ parameters: uom: "kWh" rule: 3 digits: 1 - registers: [0x020A, 0x020B, 0x0216, 0x0217, 0x0206, 0x0207, 0x020C, 0x020D, 0x020F, 0x0210, 0x0204, 0x0205] + registers: + [ + 0x020A, + 0x020B, + 0x0216, + 0x0217, + 0x0206, + 0x0207, + 0x020C, + 0x020D, + 0x020F, + 0x0210, + 0x0204, + 0x0205, + ] sensors: - scale: 0.1 registers: [0x020A, 0x020B] @@ -823,7 +849,7 @@ parameters: "Inverter-Gen", "Grid-Generator", "Inv-Grid-Gen", - "Power Supply" + "Power Supply", ] lookup: - key: 0x0001 @@ -887,7 +913,7 @@ parameters: "Grid error", "Battery loss", "Parallel communication quality", - "Error" + "Error", ] lookup: - key: 0x0000 @@ -1252,10 +1278,7 @@ parameters: rule: 4 registers: [0x0271, 0x02B2] icon: "mdi:transmission-tower" - attributes: - [ - "Zero Export", - ] + attributes: ["Zero Export"] - group: Inverter items: diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 4e90bf9..d399e67 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -371,6 +371,18 @@ parameters: - key: "default" value: "On" + - group: Solar Sell + items: + - name: "Solar Sell" + update_interval: 30 + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + switch: True + registers: [0x0091] + - group: BMS items: - name: "BMS Charged Voltage" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 8a69a3c..1573061 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -374,6 +374,18 @@ parameters: - key: "default" value: "On" + - group: Solar Sell + items: + - name: "Solar Sell" + update_interval: 30 + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + switch: True + registers: [0x0091] + - group: BMS items: - name: "BMS Charged Voltage" diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 594cc46..1d5921d 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -4,20 +4,27 @@ import asyncio import voluptuous as vol +from functools import cached_property, partial + +from homeassistant.components.template.sensor import SensorTemplate +from homeassistant.components.template.sensor import TriggerSensorEntity +from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription +from homeassistant.helpers.template import Template + from homeassistant.core import HomeAssistant, callback from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_NAME, EntityCategory +from homeassistant.const import EntityCategory, STATE_OFF, STATE_ON from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo, format_mac -from homeassistant.helpers.entity import Entity +from homeassistant.helpers.entity import Entity, ToggleEntity from homeassistant.helpers.entity_platform import AddEntitiesCallback from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import * from .common import * +from .services import * from .api import Inverter -from .discovery import InverterDiscovery from .coordinator import InverterCoordinator -from .services import * +from .entity import SolarmanCoordinatorEntity, SolarmanBaseEntity, SolarmanEntity _LOGGER = logging.getLogger(__name__) @@ -25,10 +32,10 @@ def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cy try: if "artificial" in sensor: entity = SolarmanStatus(coordinator, sensor) - elif "isstr" in sensor: - entity = SolarmanSensorBase(coordinator, sensor) elif sensor["name"] in ("Battery SOH", "Battery State", "Today Battery Life Cycles", "Total Battery Life Cycles"): entity = SolarmanBatterySensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) + #elif "switch" in sensor and sensor["switch"]: + # entity = SolarmanSwitchSensor(coordinator, sensor, battery_life_cycle_rating) else: entity = SolarmanSensor(coordinator, sensor, battery_life_cycle_rating) @@ -39,147 +46,46 @@ def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cy _LOGGER.error(f"Configuring {sensor} failed. [{format_exception(e)}]") raise -async def async_setup(hass: HomeAssistant, config, async_add_entities: AddEntitiesCallback, id = None): - _LOGGER.debug(f"async_setup: {config}") - - inverter_name = config.get(CONF_NAME) - inverter_discovery = config.get(CONF_INVERTER_DISCOVERY) - inverter_host = config.get(CONF_INVERTER_HOST) - inverter_serial = config.get(CONF_INVERTER_SERIAL) - inverter_port = config.get(CONF_INVERTER_PORT) - inverter_mb_slave_id = config.get(CONF_INVERTER_MB_SLAVE_ID) - lookup_path = hass.config.path(LOOKUP_DIRECTORY_PATH) - lookup_file = config.get(CONF_LOOKUP_FILE) - battery_nominal_voltage = config.get(CONF_BATTERY_NOMINAL_VOLTAGE) - battery_life_cycle_rating = config.get(CONF_BATTERY_LIFE_CYCLE_RATING) - - inverter_discovery = InverterDiscovery(hass, inverter_host) - - if inverter_discovery: - if inverter_host_scanned := await inverter_discovery.get_ip(): - inverter_host = inverter_host_scanned - - if inverter_serial == 0: - if inverter_serial_scanned := await inverter_discovery.get_serial(): - inverter_serial = inverter_serial_scanned - - inverter_mac = await inverter_discovery.get_mac() - - if not inverter_mb_slave_id: - inverter_mb_slave_id = DEFAULT_INVERTER_MB_SLAVE_ID - - if inverter_host is None: - raise vol.Invalid("configuration parameter [inverter_host] does not have a value") - if inverter_serial is None: - raise vol.Invalid("configuration parameter [inverter_serial] does not have a value") - - inverter = Inverter(inverter_host, inverter_serial, inverter_port, inverter_mb_slave_id, inverter_name, inverter_mac, lookup_path, lookup_file) - sensors = await inverter.get_sensors() +async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry, async_add_entities: AddEntitiesCallback) -> bool: + _LOGGER.debug(f"async_setup_entry: {config.options}") + coordinator = hass.data[DOMAIN][config.entry_id] - coordinator = InverterCoordinator(hass, inverter) + options = config.options - # Fetch initial data so we have data when entities subscribe. - # - # If the refresh fails, async_config_entry_first_refresh will - # raise ConfigEntryNotReady and setup will try again later. - # - # If you do not want to retry setup on failure, use - # coordinator.async_refresh() instead. - # - _LOGGER.debug(f"async_setup: coordinator.async_config_entry_first_refresh") + battery_nominal_voltage = options.get(CONF_BATTERY_NOMINAL_VOLTAGE) + battery_life_cycle_rating = options.get(CONF_BATTERY_LIFE_CYCLE_RATING) - await coordinator.async_config_entry_first_refresh() + sensors = coordinator.inverter.get_sensors() # Add entities. # _LOGGER.debug(f"async_setup: async_add_entities") - async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors) - - # Register the services with home assistant. - # - _LOGGER.debug(f"async_setup: register_services") - - hass.data.setdefault(DOMAIN, {})[id] = coordinator - - register_services(hass, inverter) - -async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry, async_add_entities: AddEntitiesCallback) -> bool: - _LOGGER.debug(f"async_setup_entry: {config.options}") - await async_setup(hass, config.options, async_add_entities, config.entry_id) + async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors if not "switch" in sensor) return True async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: _LOGGER.debug(f"async_unload_entry: {config.options}") - remove_services(hass) return True -class SolarmanCoordinatorEntity(CoordinatorEntity[InverterCoordinator]): - def __init__(self, coordinator: InverterCoordinator, name: str = None): - super().__init__(coordinator) - self.model = self.coordinator.inverter.lookup_file.replace(".yaml", "") - - if '_' in self.model: - dev_man = self.model.split('_') - self.manufacturer = dev_man[0].capitalize() - self.model = dev_man[1].upper() - - self._attr_device_info = { - "connections": {(CONNECTION_NETWORK_MAC, format_mac(self.coordinator.inverter.mac))} - } if self.coordinator.inverter.mac else {} | { - "identifiers": {(DOMAIN, self.coordinator.inverter.serial)}, - "name": self.coordinator.inverter.name, - "manufacturer": self.manufacturer, - "model": self.model, - "serial_number": self.coordinator.inverter.serial - } - - #self._attr_extra_state_attributes = { "id": self.coordinator.inverter.serial, "integration": DOMAIN } - self._attr_extra_state_attributes = {} - -class SolarmanStatus(SolarmanCoordinatorEntity): +class SolarmanStatus(SolarmanEntity): def __init__(self, coordinator, sensor): - super().__init__(coordinator) - self.sensor_name = sensor["name"] - self.sensor_entity_id = sensor["entity_id"] if "entity_id" in sensor else None - self.sensor_unique_id = self.sensor_entity_id if self.sensor_entity_id else self.sensor_name + super().__init__(coordinator, sensor) - # Set the category of the sensor. self._attr_entity_category = (EntityCategory.DIAGNOSTIC) - # Set the icon of the sensor. - self._attr_icon = "mdi:information" - - # Set the name of the sensor. - self._attr_name = "{} {}".format(self.coordinator.inverter.name, self.sensor_name) - - # Set the entity_id of the sensor. - if self.sensor_entity_id: - self.entity_id = "sensor.{}_{}".format(self.coordinator.inverter.name, self.sensor_entity_id) - - # Set a unique_id based on the serial number - self._attr_unique_id = "{}_{}_{}".format(self.coordinator.inverter.name, self.coordinator.inverter.serial, self.sensor_unique_id) - @property def available(self) -> bool: """Return if entity is available.""" - if type(self) is SolarmanStatus: - return True - return self._attr_available and self.coordinator.inverter.is_connected() - - @callback - def _handle_coordinator_update(self) -> None: - """Handle updated data from the coordinator.""" - self.update() - self.async_write_ha_state() + return True def update(self): self._attr_state = self.coordinator.inverter.get_connection_status() self._attr_extra_state_attributes["updated"] = self.coordinator.inverter.status_lastUpdate -class SolarmanSensorBase(SolarmanStatus): - def __init__(self, coordinator, sensor): - SolarmanStatus.__init__(self, coordinator, sensor) +class SolarmanSensor(SolarmanBaseEntity): + def __init__(self, coordinator, sensor, battery_life_cycle_rating): + super().__init__(coordinator, sensor) self._attr_entity_registry_enabled_default = not "disabled" in sensor if "suggested_display_precision" in sensor: @@ -196,35 +102,6 @@ def __init__(self, coordinator, sensor): self.attributes = sensor["attributes"] if "attributes" in sensor else None - def get_data_state(self, name): - return self.coordinator.data[name]["state"] - - def get_data_value(self, name): - return self.coordinator.data[name]["value"] - - def get_data(self, name, default): - if name in self.coordinator.data: - return self.get_data_state(name) - - return default - - def update(self): - c = len(self.coordinator.data) - if c > 1 or (c == 1 and self.sensor_name in self.coordinator.data): - if self.sensor_name in self.coordinator.data: - self._attr_state = self.get_data_state(self.sensor_name) - if "value" in self.coordinator.data[self.sensor_name]: - self._attr_extra_state_attributes["value"] = self.get_data_value(self.sensor_name) - if self.attributes: - for attr in self.attributes: - if attr in self.coordinator.data: - attr_name = attr.replace(f"{self.sensor_name} ", "") - self._attr_extra_state_attributes[attr_name] = self.get_data_state(attr) - -class SolarmanSensor(SolarmanSensorBase): - def __init__(self, coordinator, sensor, battery_life_cycle_rating): - SolarmanSensorBase.__init__(self, coordinator, sensor) - if "class" in sensor and (device_class := sensor["class"]): self._attr_device_class = device_class diff --git a/custom_components/solarman/services.py b/custom_components/solarman/services.py index 87a311a..ce9959e 100644 --- a/custom_components/solarman/services.py +++ b/custom_components/solarman/services.py @@ -2,7 +2,7 @@ import voluptuous as vol -from homeassistant.core import HomeAssistant +from homeassistant.core import HomeAssistant, ServiceCall, ServiceResponse, SupportsResponse from homeassistant.helpers import config_validation as cv from .const import * @@ -27,13 +27,13 @@ ) def register_services(hass: HomeAssistant, inverter: Inverter): - async def write_holding_register(call) -> None: + async def write_holding_register(call: ServiceCall) -> None: await inverter.service_write_holding_register( register = call.data.get(SERVICES_PARAM_REGISTER), value = call.data.get(SERVICES_PARAM_VALUE)) return - async def write_multiple_holding_registers(call) -> None: + async def write_multiple_holding_registers(call: ServiceCall) -> None: await inverter.service_write_multiple_holding_registers( register = call.data.get(SERVICES_PARAM_REGISTER), values = call.data.get(SERVICES_PARAM_VALUES)) diff --git a/custom_components/solarman/switch.py b/custom_components/solarman/switch.py new file mode 100644 index 0000000..4512b78 --- /dev/null +++ b/custom_components/solarman/switch.py @@ -0,0 +1,98 @@ +from __future__ import annotations + +import logging +import asyncio +import voluptuous as vol + +from functools import cached_property, partial + +from homeassistant.components.template.sensor import SensorTemplate +from homeassistant.components.template.sensor import TriggerSensorEntity +from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription +from homeassistant.helpers.template import Template + +from homeassistant.core import HomeAssistant, callback +from homeassistant.config_entries import ConfigEntry +from homeassistant.const import CONF_NAME, EntityCategory, STATE_OFF, STATE_ON +from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo, format_mac +from homeassistant.helpers.entity import Entity, ToggleEntity +from homeassistant.helpers.entity_platform import AddEntitiesCallback +from homeassistant.helpers.update_coordinator import CoordinatorEntity + +from .const import * +from .common import * +from .services import * +from .api import Inverter +from .coordinator import InverterCoordinator +from .entity import SolarmanCoordinatorEntity, SolarmanBaseEntity, SolarmanEntity +from .sensor import SolarmanSensor + +_LOGGER = logging.getLogger(__name__) + +def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating): + try: + entity = SolarmanSwitchSensor(coordinator, sensor, battery_life_cycle_rating) + + entity.update() + + return entity + except BaseException as e: + _LOGGER.error(f"Configuring {sensor} failed. [{format_exception(e)}]") + raise + +async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry, async_add_entities: AddEntitiesCallback) -> bool: + _LOGGER.debug(f"async_setup_entry: {config.options}") + coordinator = hass.data[DOMAIN][config.entry_id] + + options = config.options + + battery_nominal_voltage = options.get(CONF_BATTERY_NOMINAL_VOLTAGE) + battery_life_cycle_rating = options.get(CONF_BATTERY_LIFE_CYCLE_RATING) + + sensors = coordinator.inverter.get_sensors() + + # Add entities. + # + _LOGGER.debug(f"async_setup: async_add_entities") + + async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors if "switch" in sensor) + return True + +async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: + _LOGGER.debug(f"async_unload_entry: {config.options}") + return True + +class SolarmanSwitchSensor(SolarmanSensor, SwitchEntity): + def __init__(self, coordinator, sensor, battery_life_cycle_rating): + SolarmanSensor.__init__(self, coordinator, sensor, battery_life_cycle_rating) + + # Set the category of the sensor. + self._attr_entity_category = (EntityCategory.CONFIG) + + self._attr_device_class = "switch" + + registers = sensor["registers"] + registers_length = len(registers) + + if registers_length > 0: + self.register = sensor["registers"][0] + + if registers_length > 1: + _LOGGER.warning(f"SolarmanSwitchSensor.__init__: Contains more than 1 register!") + + @property + def is_on(self) -> bool | None: + """Return True if entity is on.""" + return self._attr_state != 0 + + async def async_turn_on(self, **kwargs: Any) -> None: + """Turn the entity on.""" + await self.coordinator.inverter.service_write_multiple_holding_registers(self.register, [65280,]) + self._attr_state = 1 + self.async_write_ha_state() + + async def async_turn_off(self, **kwargs: Any) -> None: + """Turn the entity off.""" + await self.coordinator.inverter.service_write_multiple_holding_registers(self.register, [0,]) + self._attr_state = 0 + self.async_write_ha_state() From c0016bb24781da12ffa454b3fc995c6c006d39d0 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Wed, 17 Jul 2024 11:12:15 +0200 Subject: [PATCH 25/39] fix: Template component dependency --- custom_components/solarman/manifest.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/custom_components/solarman/manifest.json b/custom_components/solarman/manifest.json index 3a04488..49cc92d 100644 --- a/custom_components/solarman/manifest.json +++ b/custom_components/solarman/manifest.json @@ -3,7 +3,7 @@ "name": "Solarman", "codeowners": ["@davidrapan"], "config_flow": true, - "dependencies": ["network", "dhcp"], + "dependencies": ["network", "template", "dhcp"], "documentation": "https://github.com/davidrapan/ha-solarman", "integration_type": "device", "iot_class": "local_polling", From 16723536821234476571d3b9a4b33a97457a46d9 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Wed, 17 Jul 2024 18:25:42 +0200 Subject: [PATCH 26/39] fix: Disconnect when register writing fails - Only when auto_reconnect is disabled --- custom_components/solarman/api.py | 15 ++++++++++----- custom_components/solarman/const.py | 2 ++ custom_components/solarman/sensor.py | 2 +- custom_components/solarman/switch.py | 19 ++++++++----------- 4 files changed, 21 insertions(+), 17 deletions(-) diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index a98c132..0a60e6e 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -18,8 +18,8 @@ _LOGGER = logging.getLogger(__name__) class InverterApi(PySolarmanV5Async): - def __init__(self, address, serial, port, mb_slave_id): - super().__init__(address, serial, port = port, mb_slave_id = mb_slave_id, logger = _LOGGER, auto_reconnect = True, socket_timeout = TIMINGS_SOCKET_TIMEOUT) + def __init__(self, address, serial, port, mb_slave_id, auto_reconnect): + super().__init__(address, serial, port = port, mb_slave_id = mb_slave_id, logger = _LOGGER, auto_reconnect = auto_reconnect, socket_timeout = TIMINGS_SOCKET_TIMEOUT) self.status_lastUpdate = "N/A" self.status = -1 @@ -128,11 +128,12 @@ async def async_read(self, params, code, start, end) -> None: class Inverter(InverterApi): def __init__(self, address, serial, port, mb_slave_id, name, mac, lookup_path, lookup_file): - super().__init__(address, serial, port, mb_slave_id) + super().__init__(address, serial, port, mb_slave_id, AUTO_RECONNECT) self.name = name self.mac = mac self.lookup_path = lookup_path self.lookup_file = lookup_file if lookup_file and not lookup_file == "parameters.yaml" else "deye_hybrid.yaml" + self.auto_reconnect = AUTO_RECONNECT #execute_async(self.load()) @@ -197,6 +198,8 @@ async def async_get(self, runtime = 0): _LOGGER.warning(f"Querying ({start} - {end}) failed. #{runtime} [{format_exception(e)}]") await asyncio.sleep(TIMINGS_QUERY_EXCEPT_SLEEP) + #if (n := ACTION_RETRY_ATTEMPTS - attempts_left) >= 1: + # await asyncio.sleep(n) _LOGGER.debug(f"Querying {'succeeded.' if result == 1 else f'attempts left: {attempts_left}{'' if attempts_left > 0 else ', aborting.'}'}") @@ -226,7 +229,8 @@ async def service_write_holding_register(self, register, value) -> bool: _LOGGER.debug(f"service_write_holding_register: {register}, response: {response}") except Exception as e: _LOGGER.warning(f"service_write_holding_register: {register}, value: {value} failed. [{format_exception(e)}]") - #await self.async_disconnect() + if not self.auto_reconnect: + await self.async_disconnect() raise return True @@ -238,6 +242,7 @@ async def service_write_multiple_holding_registers(self, register, values) -> bo _LOGGER.debug(f"service_write_multiple_holding_register: {register}, response: {response}") except Exception as e: _LOGGER.warning(f"service_write_multiple_holding_registers: {register}, values: {values} failed. [{format_exception(e)}]") - #await self.async_disconnect() + if not self.auto_reconnect: + await self.async_disconnect() raise return True diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index a996a7a..3d44d82 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -35,6 +35,8 @@ DEFAULT_BATTERY_NOMINAL_VOLTAGE = 48 DEFAULT_BATTERY_LIFE_CYCLE_RATING = 6000 +AUTO_RECONNECT = True + ACTION_RETRY_ATTEMPTS = 5 TIMINGS_INTERVAL = 5 diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 1d5921d..7292ed9 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -35,7 +35,7 @@ def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cy elif sensor["name"] in ("Battery SOH", "Battery State", "Today Battery Life Cycles", "Total Battery Life Cycles"): entity = SolarmanBatterySensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) #elif "switch" in sensor and sensor["switch"]: - # entity = SolarmanSwitchSensor(coordinator, sensor, battery_life_cycle_rating) + # entity = SolarmanSwitchEntity(coordinator, sensor, battery_life_cycle_rating) else: entity = SolarmanSensor(coordinator, sensor, battery_life_cycle_rating) diff --git a/custom_components/solarman/switch.py b/custom_components/solarman/switch.py index 4512b78..ce14336 100644 --- a/custom_components/solarman/switch.py +++ b/custom_components/solarman/switch.py @@ -8,7 +8,7 @@ from homeassistant.components.template.sensor import SensorTemplate from homeassistant.components.template.sensor import TriggerSensorEntity -from homeassistant.components.switch import SwitchEntity, SwitchEntityDescription +from homeassistant.components.switch import SwitchEntity, SwitchDeviceClass, SwitchEntityDescription from homeassistant.helpers.template import Template from homeassistant.core import HomeAssistant, callback @@ -31,7 +31,7 @@ def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating): try: - entity = SolarmanSwitchSensor(coordinator, sensor, battery_life_cycle_rating) + entity = SolarmanSwitchEntity(coordinator, sensor, battery_life_cycle_rating) entity.update() @@ -62,23 +62,20 @@ async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: _LOGGER.debug(f"async_unload_entry: {config.options}") return True -class SolarmanSwitchSensor(SolarmanSensor, SwitchEntity): +class SolarmanSwitchEntity(SolarmanSensor, SwitchEntity): def __init__(self, coordinator, sensor, battery_life_cycle_rating): SolarmanSensor.__init__(self, coordinator, sensor, battery_life_cycle_rating) - - # Set the category of the sensor. - self._attr_entity_category = (EntityCategory.CONFIG) - - self._attr_device_class = "switch" + # Set The Device Class of the entity. + self._attr_device_class = SwitchDeviceClass.SWITCH + # Set The Category of the entity. + self._attr_entity_category = EntityCategory.CONFIG registers = sensor["registers"] registers_length = len(registers) - if registers_length > 0: self.register = sensor["registers"][0] - if registers_length > 1: - _LOGGER.warning(f"SolarmanSwitchSensor.__init__: Contains more than 1 register!") + _LOGGER.warning(f"SolarmanSwitchEntity.__init__: Contains more than 1 register!") @property def is_on(self) -> bool | None: From b23482e0851ccd62a1846e753b129005e0f8332c Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 00:07:22 +0200 Subject: [PATCH 27/39] feat: Inverter Power Switch --- custom_components/solarman/api.py | 2 -- custom_components/solarman/common.py | 6 ++++++ .../inverter_definitions/deye_sg01hp3.yaml | 17 ++++++---------- .../inverter_definitions/deye_sg04lp3.yaml | 17 ++++++---------- .../deye_sun-12k-sg04lp3.yaml | 20 +++++++------------ custom_components/solarman/sensor.py | 4 +--- custom_components/solarman/switch.py | 19 ++++++++---------- 7 files changed, 34 insertions(+), 51 deletions(-) diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index 0a60e6e..e153a45 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -198,8 +198,6 @@ async def async_get(self, runtime = 0): _LOGGER.warning(f"Querying ({start} - {end}) failed. #{runtime} [{format_exception(e)}]") await asyncio.sleep(TIMINGS_QUERY_EXCEPT_SLEEP) - #if (n := ACTION_RETRY_ATTEMPTS - attempts_left) >= 1: - # await asyncio.sleep(n) _LOGGER.debug(f"Querying {'succeeded.' if result == 1 else f'attempts left: {attempts_left}{'' if attempts_left > 0 else ', aborting.'}'}") diff --git a/custom_components/solarman/common.py b/custom_components/solarman/common.py index 0f3551f..f850828 100644 --- a/custom_components/solarman/common.py +++ b/custom_components/solarman/common.py @@ -4,6 +4,12 @@ from .const import * +def get_current_file_name(value): + result = value.rsplit('.', 1) + if len(result) > 0: + return result[-1] + return "" + async def async_execute(x): loop = asyncio.get_running_loop() return await loop.run_in_executor(None, x) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 0e87d9c..a7a9764 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -811,25 +811,20 @@ parameters: min: 0 max: 3000 - - group: Status + - group: "Controls" items: - # Device - Power on/off status - - name: "Device Power Status" + # Device - Power the Inverter On/Off + - name: "" update_interval: 30 - class: "enum" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0227] - icon: "mdi:information" - options: ["Off", "On"] - lookup: - - key: 0x0000 - value: "Off" - - key: 0x0001 - value: "On" + - group: Status + items: # Device - AC Relay status - name: "Device Relay Status" update_interval: 30 diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index d399e67..82c889d 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -816,25 +816,20 @@ parameters: min: 0 max: 3000 - - group: Status + - group: "Controls" items: - # Device - Power on/off status - - name: "Device Power Status" + # Device - Power the Inverter On/Off + - name: "" update_interval: 30 - class: "enum" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0227] - icon: "mdi:information" - options: ["Off", "On"] - lookup: - - key: 0x0000 - value: "Off" - - key: 0x0001 - value: "On" + - group: Status + items: # Device - AC Relay status - name: "Device Relay Status" update_interval: 30 diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 1573061..e541b7e 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -378,12 +378,11 @@ parameters: items: - name: "Solar Sell" update_interval: 30 - class: "" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 - switch: True registers: [0x0091] - group: BMS @@ -819,25 +818,20 @@ parameters: min: 0 max: 3000 - - group: Status + - group: "Controls" items: - # Device - Power on/off status - - name: "Device Power Status" + # Device - Power the Inverter On/Off + - name: "" update_interval: 30 - class: "enum" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0227] - icon: "mdi:information" - options: ["Off", "On"] - lookup: - - key: 0x0000 - value: "Off" - - key: 0x0001 - value: "On" + - group: Status + items: # Device - AC Relay status - name: "Device Relay Status" update_interval: 30 diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 7292ed9..2753a33 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -34,8 +34,6 @@ def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cy entity = SolarmanStatus(coordinator, sensor) elif sensor["name"] in ("Battery SOH", "Battery State", "Today Battery Life Cycles", "Total Battery Life Cycles"): entity = SolarmanBatterySensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) - #elif "switch" in sensor and sensor["switch"]: - # entity = SolarmanSwitchEntity(coordinator, sensor, battery_life_cycle_rating) else: entity = SolarmanSensor(coordinator, sensor, battery_life_cycle_rating) @@ -61,7 +59,7 @@ async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry, async_add_ # _LOGGER.debug(f"async_setup: async_add_entities") - async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors if not "switch" in sensor) + async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors if (not "class" in sensor or not sensor["class"] in PLATFORMS)) return True async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: diff --git a/custom_components/solarman/switch.py b/custom_components/solarman/switch.py index ce14336..fcd1bfa 100644 --- a/custom_components/solarman/switch.py +++ b/custom_components/solarman/switch.py @@ -29,9 +29,11 @@ _LOGGER = logging.getLogger(__name__) -def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating): +_PLATFORM = get_current_file_name(__name__) + +def _create_sensor(coordinator, sensor): try: - entity = SolarmanSwitchEntity(coordinator, sensor, battery_life_cycle_rating) + entity = SolarmanSwitchEntity(coordinator, sensor) entity.update() @@ -44,18 +46,13 @@ async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry, async_add_ _LOGGER.debug(f"async_setup_entry: {config.options}") coordinator = hass.data[DOMAIN][config.entry_id] - options = config.options - - battery_nominal_voltage = options.get(CONF_BATTERY_NOMINAL_VOLTAGE) - battery_life_cycle_rating = options.get(CONF_BATTERY_LIFE_CYCLE_RATING) - sensors = coordinator.inverter.get_sensors() # Add entities. # _LOGGER.debug(f"async_setup: async_add_entities") - async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors if "switch" in sensor) + async_add_entities(_create_sensor(coordinator, sensor) for sensor in sensors if ("class" in sensor and sensor["class"] == _PLATFORM)) return True async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: @@ -63,8 +60,8 @@ async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: return True class SolarmanSwitchEntity(SolarmanSensor, SwitchEntity): - def __init__(self, coordinator, sensor, battery_life_cycle_rating): - SolarmanSensor.__init__(self, coordinator, sensor, battery_life_cycle_rating) + def __init__(self, coordinator, sensor): + SolarmanSensor.__init__(self, coordinator, sensor, 0) # Set The Device Class of the entity. self._attr_device_class = SwitchDeviceClass.SWITCH # Set The Category of the entity. @@ -84,7 +81,7 @@ def is_on(self) -> bool | None: async def async_turn_on(self, **kwargs: Any) -> None: """Turn the entity on.""" - await self.coordinator.inverter.service_write_multiple_holding_registers(self.register, [65280,]) + await self.coordinator.inverter.service_write_multiple_holding_registers(self.register, [1,]) self._attr_state = 1 self.async_write_ha_state() From b836ff019a4079466edd62a311748483de17a603 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 01:25:50 +0200 Subject: [PATCH 28/39] feat: Added Number platform - Zero Export power as first configurable integer item --- custom_components/solarman/const.py | 2 +- .../inverter_definitions/deye_sg01hp3.yaml | 7 +- .../inverter_definitions/deye_sg04lp3.yaml | 5 +- .../deye_sun-12k-sg04lp3.yaml | 8 +- custom_components/solarman/number.py | 84 +++++++++++++++++++ custom_components/solarman/sensor.py | 2 +- custom_components/solarman/switch.py | 16 +--- 7 files changed, 101 insertions(+), 23 deletions(-) create mode 100644 custom_components/solarman/number.py diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index 3d44d82..e7fb2bb 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -1,7 +1,7 @@ from datetime import timedelta as td DOMAIN = "solarman" -PLATFORMS: list[str] = ["sensor", "switch"] +PLATFORMS: list[str] = ["sensor", "switch", "number"] IP_BROADCAST = "" IP_ANY = "0.0.0.0" diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index a7a9764..7182ef5 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -193,14 +193,16 @@ parameters: registers: [0x0067] icon: "mdi:battery" - - name: "Zero Export" - attribute: + - name: "Zero Export power" class: "power" state_class: "measurement" uom: "W" scale: 1 rule: 1 registers: [0x0068] + configurable: + min: 0 + max: 500 icon: "mdi:transmission-tower-import" - name: "Battery Equalization Cycle" @@ -1273,7 +1275,6 @@ parameters: rule: 4 registers: [0x0271, 0x02B2] icon: "mdi:transmission-tower" - attributes: ["Zero Export"] - group: Inverter items: diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 82c889d..991d5c6 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -199,13 +199,16 @@ parameters: registers: [0x0067] icon: "mdi:battery" - - name: "Zero Export Power" + - name: "Zero Export power" class: "power" state_class: "measurement" uom: "W" scale: 1 rule: 1 registers: [0x0068] + configurable: + min: 0 + max: 500 icon: "mdi:transmission-tower-import" - name: "Battery Equalization Cycle" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index e541b7e..20e1a1b 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -201,14 +201,16 @@ parameters: registers: [0x0067] icon: "mdi:battery" - - name: "Zero Export" - attribute: + - name: "Zero Export power" class: "power" state_class: "measurement" uom: "W" scale: 1 rule: 1 registers: [0x0068] + configurable: + min: 0 + max: 500 icon: "mdi:transmission-tower-import" - name: "Battery Equalization Cycle" @@ -1290,7 +1292,6 @@ parameters: rule: 4 registers: [0x0271, 0x02B2] icon: "mdi:transmission-tower" - attributes: ["Zero Export"] # Grid - The inverted power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power ∇" @@ -1304,7 +1305,6 @@ parameters: inverted: True registers: [0x0271, 0x02B2] icon: "mdi:transmission-tower" - attributes: ["Zero Export"] - group: Inverter items: diff --git a/custom_components/solarman/number.py b/custom_components/solarman/number.py new file mode 100644 index 0000000..2168ebd --- /dev/null +++ b/custom_components/solarman/number.py @@ -0,0 +1,84 @@ +from __future__ import annotations + +import logging +import asyncio +import voluptuous as vol + +from functools import cached_property, partial + +from homeassistant.config_entries import ConfigEntry +from homeassistant.core import HomeAssistant, callback +from homeassistant.const import CONF_NAME, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.components.number import NumberEntity, NumberDeviceClass, NumberEntityDescription +from homeassistant.helpers.entity_platform import AddEntitiesCallback + +from .const import * +from .common import * +from .services import * +from .sensor import SolarmanSensor + +_LOGGER = logging.getLogger(__name__) + +_PLATFORM = get_current_file_name(__name__) + +def _create_sensor(coordinator, sensor): + try: + entity = SolarmanNumberEntity(coordinator, sensor) + + entity.update() + + return entity + except BaseException as e: + _LOGGER.error(f"Configuring {sensor} failed. [{format_exception(e)}]") + raise + +async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry, async_add_entities: AddEntitiesCallback) -> bool: + _LOGGER.debug(f"async_setup_entry: {config.options}") + coordinator = hass.data[DOMAIN][config.entry_id] + + sensors = coordinator.inverter.get_sensors() + + # Add entities. + # + _LOGGER.debug(f"async_setup: async_add_entities") + + async_add_entities(_create_sensor(coordinator, sensor) for sensor in sensors if "configurable" in sensor) + #if ("class" in sensor and sensor["class"] == _PLATFORM) + return True + +async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: + _LOGGER.debug(f"async_unload_entry: {config.options}") + return True + +class SolarmanNumberEntity(SolarmanSensor, NumberEntity): + def __init__(self, coordinator, sensor): + SolarmanSensor.__init__(self, coordinator, sensor, 0) + # Set The Category of the entity. + self._attr_entity_category = EntityCategory.CONFIG + + registers = sensor["registers"] + registers_length = len(registers) + if registers_length > 0: + self.register = sensor["registers"][0] + if registers_length > 1: + _LOGGER.warning(f"SolarmanNumberEntity.__init__: Contains more than 1 register!") + + configurable = sensor["configurable"] + if "min" in configurable: + self._attr_native_min_value = configurable["min"] + if "max" in configurable: + self._attr_native_max_value = configurable["max"] + + @property + def native_value(self) -> float: + """Return the state of the setting entity.""" + return self._attr_state + + async def async_set_native_value(self, value: float) -> None: + """Update the setting.""" + int_value = int(value) + await self.coordinator.inverter.service_write_multiple_holding_registers(self.register, [int_value,]) + self._attr_state = int_value + self.async_write_ha_state() + #await self.entity_description.update_fn(self.coordinator., int(value)) + #await self.coordinator.async_request_refresh() diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 2753a33..c0b642a 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -59,7 +59,7 @@ async def async_setup_entry(hass: HomeAssistant, config: ConfigEntry, async_add_ # _LOGGER.debug(f"async_setup: async_add_entities") - async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors if (not "class" in sensor or not sensor["class"] in PLATFORMS)) + async_add_entities(_create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) for sensor in sensors if ((not "class" in sensor or not sensor["class"] in PLATFORMS) and not "configurable" in sensor)) return True async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: diff --git a/custom_components/solarman/switch.py b/custom_components/solarman/switch.py index fcd1bfa..b019ced 100644 --- a/custom_components/solarman/switch.py +++ b/custom_components/solarman/switch.py @@ -6,25 +6,15 @@ from functools import cached_property, partial -from homeassistant.components.template.sensor import SensorTemplate -from homeassistant.components.template.sensor import TriggerSensorEntity -from homeassistant.components.switch import SwitchEntity, SwitchDeviceClass, SwitchEntityDescription -from homeassistant.helpers.template import Template - -from homeassistant.core import HomeAssistant, callback from homeassistant.config_entries import ConfigEntry -from homeassistant.const import CONF_NAME, EntityCategory, STATE_OFF, STATE_ON -from homeassistant.helpers.device_registry import CONNECTION_NETWORK_MAC, DeviceInfo, format_mac -from homeassistant.helpers.entity import Entity, ToggleEntity +from homeassistant.core import HomeAssistant, callback +from homeassistant.const import CONF_NAME, STATE_OFF, STATE_ON, EntityCategory +from homeassistant.components.switch import SwitchEntity, SwitchDeviceClass, SwitchEntityDescription from homeassistant.helpers.entity_platform import AddEntitiesCallback -from homeassistant.helpers.update_coordinator import CoordinatorEntity from .const import * from .common import * from .services import * -from .api import Inverter -from .coordinator import InverterCoordinator -from .entity import SolarmanCoordinatorEntity, SolarmanBaseEntity, SolarmanEntity from .sensor import SolarmanSensor _LOGGER = logging.getLogger(__name__) From 6d3367d7260bfdb4f85a592d2afe596852b766fb Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 02:34:03 +0200 Subject: [PATCH 29/39] feat: Battery parameters made configurable --- custom_components/solarman/common.py | 3 + .../inverter_definitions/deye_sg01hp3.yaml | 78 ++++++++++--------- .../inverter_definitions/deye_sg04lp3.yaml | 78 ++++++++++--------- .../deye_sun-12k-sg04lp3.yaml | 78 ++++++++++--------- custom_components/solarman/number.py | 11 ++- 5 files changed, 134 insertions(+), 114 deletions(-) diff --git a/custom_components/solarman/common.py b/custom_components/solarman/common.py index f850828..0628d98 100644 --- a/custom_components/solarman/common.py +++ b/custom_components/solarman/common.py @@ -37,6 +37,9 @@ def format_exception(e): def Raise(exception) -> None: raise exception +def get_numbe(value): + return int(value) if isinstance(value, int) or (isinstance(value, float) and value.is_integer()) else float(value) + def get_number(value, digits): return int(value) if isinstance(value, int) or (isinstance(value, float) and value.is_integer()) else (n if (n := round(value, digits)) and not n.is_integer() else int(n)) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 7182ef5..f1e0bed 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -132,65 +132,80 @@ parameters: value: "Lithium" - name: "Battery Equalization" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0063] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Absorption" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0064] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Float" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0065] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Capacity" - attribute: class: "" state_class: "measurement" uom: "Ah" scale: 1 rule: 1 registers: [0x0066] + configurable: + min: 0 + max: 2000 icon: "mdi:battery" range: min: 0 max: 2000 + attributes: ["Battery Corrected Capacity"] - name: "Battery Empty" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0067] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" - name: "Zero Export power" @@ -206,99 +221,104 @@ parameters: icon: "mdi:transmission-tower-import" - name: "Battery Equalization Cycle" - attribute: class: "duration" state_class: "measurement" uom: "d" - display_precision: 0 scale: 1 rule: 1 registers: [0x0069] + configurable: + min: 0 + max: 90 icon: "mdi:battery" range: min: 0 max: 90 - name: "Battery Equalization Time" - attribute: class: "duration" state_class: "measurement" uom: "h" scale: 0.5 rule: 1 registers: [0x006A] + configurable: + min: 0 + max: 10 icon: "mdi:battery" range: min: 0 max: 20 - name: "Battery Temperature Compensation" - attribute: class: "" state_class: "measurement" uom: "mV/*C" scale: 1 rule: 2 registers: [0x006B] + configurable: + min: 0 + max: 50 + step: 0.1 icon: "mdi:battery" range: min: 0 max: 50 - name: "Battery Max Charging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x006C] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Max Discharging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x006D] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Grid Charging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x0080] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Grid Charging" - attribute: - class: "enum" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0082] icon: "mdi:battery" - options: ["Disabled", "Enabled"] - lookup: - - key: 0x0000 - value: "Disabled" - - key: 0x0001 - value: "Enabled" - name: "SmartLoad Mode" class: "enum" @@ -980,23 +1000,7 @@ parameters: validation: min: 0 max: 101 - attributes: - [ - "Battery Control Mode", - "Battery Capacity", - "Battery Corrected Capacity", - "Battery Absorption", - "Battery Float", - "Battery Empty", - "Battery Equalization", - "Battery Equalization Cycle", - "Battery Equalization Time", - "Battery Temperature Compensation", - "Battery Max Charging Current", - "Battery Max Discharging Current", - "Battery Grid Charging", - "Battery Grid Charging Current", - ] + attributes: ["Battery Control Mode"] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 991d5c6..ee59ed8 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -138,65 +138,80 @@ parameters: value: "Lithium" - name: "Battery Equalization" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0063] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Absorption" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0064] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Float" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0065] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Capacity" - attribute: class: "" state_class: "measurement" uom: "Ah" scale: 1 rule: 1 registers: [0x0066] + configurable: + min: 0 + max: 2000 icon: "mdi:battery" range: min: 0 max: 2000 + attributes: ["Battery Corrected Capacity"] - name: "Battery Empty" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0067] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" - name: "Zero Export power" @@ -212,99 +227,104 @@ parameters: icon: "mdi:transmission-tower-import" - name: "Battery Equalization Cycle" - attribute: class: "duration" state_class: "measurement" uom: "d" - display_precision: 0 scale: 1 rule: 1 registers: [0x0069] + configurable: + min: 0 + max: 90 icon: "mdi:battery" range: min: 0 max: 90 - name: "Battery Equalization Time" - attribute: class: "duration" state_class: "measurement" uom: "h" scale: 0.5 rule: 1 registers: [0x006A] + configurable: + min: 0 + max: 10 icon: "mdi:battery" range: min: 0 max: 20 - name: "Battery Temperature Compensation" - attribute: class: "" state_class: "measurement" uom: "mV/*C" scale: 1 rule: 2 registers: [0x006B] + configurable: + min: 0 + max: 50 + step: 0.1 icon: "mdi:battery" range: min: 0 max: 50 - name: "Battery Max Charging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x006C] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Max Discharging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x006D] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Grid Charging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x0080] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Grid Charging" - attribute: - class: "enum" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0082] icon: "mdi:battery" - options: ["Disabled", "Enabled"] - lookup: - - key: 0x0000 - value: "Disabled" - - key: 0x0001 - value: "Enabled" - name: "SmartLoad Mode" class: "enum" @@ -986,23 +1006,7 @@ parameters: validation: min: 0 max: 101 - attributes: - [ - "Battery Control Mode", - "Battery Capacity", - "Battery Corrected Capacity", - "Battery Absorption", - "Battery Float", - "Battery Empty", - "Battery Equalization", - "Battery Equalization Cycle", - "Battery Equalization Time", - "Battery Temperature Compensation", - "Battery Max Charging Current", - "Battery Max Discharging Current", - "Battery Grid Charging", - "Battery Grid Charging Current", - ] + attributes: ["Battery Control Mode"] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 20e1a1b..7051d6a 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -140,65 +140,80 @@ parameters: value: "Lithium" - name: "Battery Equalization" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0063] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Absorption" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0064] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Float" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0065] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" range: min: 3800 max: 6100 - name: "Battery Capacity" - attribute: class: "" state_class: "measurement" uom: "Ah" scale: 1 rule: 1 registers: [0x0066] + configurable: + min: 0 + max: 2000 icon: "mdi:battery" range: min: 0 max: 2000 + attributes: ["Battery Corrected Capacity"] - name: "Battery Empty" - attribute: class: "voltage" state_class: "measurement" uom: "V" scale: 0.01 rule: 1 registers: [0x0067] + configurable: + min: 38 + max: 61 + step: 0.1 icon: "mdi:battery" - name: "Zero Export power" @@ -214,99 +229,104 @@ parameters: icon: "mdi:transmission-tower-import" - name: "Battery Equalization Cycle" - attribute: class: "duration" state_class: "measurement" uom: "d" - display_precision: 0 scale: 1 rule: 1 registers: [0x0069] + configurable: + min: 0 + max: 90 icon: "mdi:battery" range: min: 0 max: 90 - name: "Battery Equalization Time" - attribute: class: "duration" state_class: "measurement" uom: "h" scale: 0.5 rule: 1 registers: [0x006A] + configurable: + min: 0 + max: 10 icon: "mdi:battery" range: min: 0 max: 20 - name: "Battery Temperature Compensation" - attribute: class: "" state_class: "measurement" uom: "mV/*C" scale: 1 rule: 2 registers: [0x006B] + configurable: + min: 0 + max: 50 + step: 0.1 icon: "mdi:battery" range: min: 0 max: 50 - name: "Battery Max Charging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x006C] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Max Discharging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x006D] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Grid Charging Current" - attribute: class: "current" state_class: "measurement" uom: "A" scale: 1 rule: 1 registers: [0x0080] + configurable: + min: 0 + max: 185 icon: "mdi:battery" range: min: 0 max: 185 - name: "Battery Grid Charging" - attribute: - class: "enum" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 registers: [0x0082] icon: "mdi:battery" - options: ["Disabled", "Enabled"] - lookup: - - key: 0x0000 - value: "Disabled" - - key: 0x0001 - value: "Enabled" - name: "SmartLoad Mode" class: "enum" @@ -987,23 +1007,7 @@ parameters: validation: min: 0 max: 101 - attributes: - [ - "Battery Control Mode", - "Battery Capacity", - "Battery Corrected Capacity", - "Battery Absorption", - "Battery Float", - "Battery Empty", - "Battery Equalization", - "Battery Equalization Cycle", - "Battery Equalization Time", - "Battery Temperature Compensation", - "Battery Max Charging Current", - "Battery Max Discharging Current", - "Battery Grid Charging", - "Battery Grid Charging Current", - ] + attributes: ["Battery Control Mode"] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/number.py b/custom_components/solarman/number.py index 2168ebd..645af18 100644 --- a/custom_components/solarman/number.py +++ b/custom_components/solarman/number.py @@ -56,6 +56,10 @@ def __init__(self, coordinator, sensor): # Set The Category of the entity. self._attr_entity_category = EntityCategory.CONFIG + self.scale = 1 + if "scale" in sensor: + self.scale = get_numbe(sensor["scale"]) + registers = sensor["registers"] registers_length = len(registers) if registers_length > 0: @@ -68,6 +72,8 @@ def __init__(self, coordinator, sensor): self._attr_native_min_value = configurable["min"] if "max" in configurable: self._attr_native_max_value = configurable["max"] + if "step" in configurable: + self._attr_native_step = configurable["step"] @property def native_value(self) -> float: @@ -76,9 +82,8 @@ def native_value(self) -> float: async def async_set_native_value(self, value: float) -> None: """Update the setting.""" - int_value = int(value) - await self.coordinator.inverter.service_write_multiple_holding_registers(self.register, [int_value,]) - self._attr_state = int_value + await self.coordinator.inverter.service_write_multiple_holding_registers(self.register, [int(value / self.scale),]) + self._attr_state = get_numbe(value) self.async_write_ha_state() #await self.entity_description.update_fn(self.coordinator., int(value)) #await self.coordinator.async_request_refresh() From 6c7832ac2814ba7d7a6ffdd42fd4cea2a40f669e Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 03:31:47 +0200 Subject: [PATCH 30/39] fix: Battery life cycles calculation --- .../inverter_definitions/deye_sg01hp3.yaml | 3 +-- .../inverter_definitions/deye_sg04lp3.yaml | 3 +-- .../deye_sun-12k-sg04lp3.yaml | 3 +-- custom_components/solarman/sensor.py | 18 ++++++++++++------ 4 files changed, 15 insertions(+), 12 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index f1e0bed..7f25f21 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -193,7 +193,6 @@ parameters: range: min: 0 max: 2000 - attributes: ["Battery Corrected Capacity"] - name: "Battery Empty" class: "voltage" @@ -1000,7 +999,7 @@ parameters: validation: min: 0 max: 101 - attributes: ["Battery Control Mode"] + attributes: ["Battery Control Mode", "Battery Corrected Capacity"] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index ee59ed8..bda565b 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -199,7 +199,6 @@ parameters: range: min: 0 max: 2000 - attributes: ["Battery Corrected Capacity"] - name: "Battery Empty" class: "voltage" @@ -1006,7 +1005,7 @@ parameters: validation: min: 0 max: 101 - attributes: ["Battery Control Mode"] + attributes: ["Battery Control Mode", "Battery Corrected Capacity"] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 7051d6a..8e43199 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -201,7 +201,6 @@ parameters: range: min: 0 max: 2000 - attributes: ["Battery Corrected Capacity"] - name: "Battery Empty" class: "voltage" @@ -1007,7 +1006,7 @@ parameters: validation: min: 0 max: 101 - attributes: ["Battery Control Mode"] + attributes: ["Battery Control Mode", "Battery Corrected Capacity"] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index c0b642a..43cb45b 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -131,9 +131,10 @@ def update(self): if c > 1 or (c == 1 and self.sensor_name in self.coordinator.data): match self.sensor_name: case "Battery SOH": - battery_capacity = self.get_data("Battery Capacity", None) total_battery_charge = self.get_data("Total Battery Charge", None) - today_battery_charge = self.get_data("Today Battery Charge", None) + battery_capacity = self.get_data("Battery Corrected Capacity", None) + if battery_capacity <= 0: + battery_capacity = self.get_data("Battery Capacity", None) if total_battery_charge and battery_capacity and self._battery_nominal_voltage and self._battery_life_cycle_rating: self._attr_state = get_number(100 - total_battery_charge / get_battery_power_capacity(battery_capacity, self._battery_nominal_voltage) / (self._battery_life_cycle_rating * 0.05), self._digits) case "Battery State": @@ -141,14 +142,19 @@ def update(self): if battery_power: self._attr_state = "discharging" if battery_power > 50 else "charging" if battery_power < -50 else "standby" case "Today Battery Life Cycles": - battery_capacity = self.get_data("Battery Capacity", None) - total_battery_charge = self.get_data("Total Battery Charge", None) today_battery_charge = self.get_data("Today Battery Charge", None) + if today_battery_charge == 0: + self._attr_state = get_number(0, self._digits) + return + battery_capacity = self.get_data("Battery Corrected Capacity", None) + if battery_capacity <= 0: + battery_capacity = self.get_data("Battery Capacity", None) if today_battery_charge and battery_capacity and self._battery_nominal_voltage: self._attr_state = get_number(get_battery_cycles(today_battery_charge, battery_capacity, self._battery_nominal_voltage), self._digits) case "Total Battery Life Cycles": - battery_capacity = self.get_data("Battery Capacity", None) total_battery_charge = self.get_data("Total Battery Charge", None) - today_battery_charge = self.get_data("Today Battery Charge", None) + battery_capacity = self.get_data("Battery Corrected Capacity", None) + if battery_capacity <= 0: + battery_capacity = self.get_data("Battery Capacity", None) if total_battery_charge and battery_capacity and self._battery_nominal_voltage: self._attr_state = get_number(get_battery_cycles(total_battery_charge, battery_capacity, self._battery_nominal_voltage), self._digits) From 7ddc9868d808ad648d682c116a228c64580e3018 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 04:36:18 +0200 Subject: [PATCH 31/39] refactor: Moved BMS under Battery as attributes - Except Alarm which were also renamed to Battery BMS Alarm --- .../inverter_definitions/deye_sg01hp3.yaml | 36 ++++++++++++------- .../inverter_definitions/deye_sg04lp3.yaml | 36 ++++++++++++------- .../deye_sun-12k-sg04lp3.yaml | 36 ++++++++++++------- custom_components/solarman/number.py | 2 +- custom_components/solarman/sensor.py | 8 ++--- custom_components/solarman/switch.py | 2 +- 6 files changed, 75 insertions(+), 45 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 7f25f21..6a00aad 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -441,7 +441,8 @@ parameters: registers: [0x00D5] icon: "mdi:battery" - - name: "BMS" + - name: "BMS SOC" + attribute: class: "" state_class: "measurement" uom: "%" @@ -452,18 +453,9 @@ parameters: validation: min: 0 max: 101 - attributes: - [ - "BMS Type", - "BMS Charging Voltage", - "BMS Discharging Voltage", - "BMS Charging Current Limit", - "BMS Discharging Current Limit", - "BMS Max Charging Current", - "BMS Max Discharging Current", - ] - name: "BMS Voltage" + attribute: class: "voltage" state_class: "measurement" uom: "V" @@ -472,6 +464,7 @@ parameters: registers: [0x00D7] - name: "BMS Current" + attribute: class: "current" state_class: "measurement" uom: "A" @@ -499,7 +492,7 @@ parameters: registers: [0x00DB] icon: "mdi:battery" - - name: "BMS Alarm" + - name: "Battery BMS Alarm" class: "enum" state_class: "" uom: "" @@ -515,8 +508,10 @@ parameters: value: "Active" - key: "default" value: "Active" + attributes: ["BMS Fault Location"] - name: "BMS Fault Location" + attribute: class: "" state_class: "" uom: "" @@ -999,7 +994,22 @@ parameters: validation: min: 0 max: 101 - attributes: ["Battery Control Mode", "Battery Corrected Capacity"] + attributes: + [ + "Battery Control Mode", + "Battery Corrected Capacity", + "BMS SOC", + "BMS Current", + "BMS Voltage", + "BMS Type", + "BMS Other Symbol", + "BMS Charged Voltage", + "BMS Discharged Voltage", + "BMS Charging Current Limit", + "BMS Discharging Current Limit", + "BMS Max Charging Current", + "BMS Max Discharging Current" + ] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index bda565b..8a95d79 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -447,7 +447,8 @@ parameters: registers: [0x00D5] icon: "mdi:battery" - - name: "BMS" + - name: "BMS SOC" + attribute: class: "" state_class: "measurement" uom: "%" @@ -458,18 +459,9 @@ parameters: validation: min: 0 max: 101 - attributes: - [ - "BMS Type", - "BMS Charged Voltage", - "BMS Discharged Voltage", - "BMS Charging Current Limit", - "BMS Discharging Current Limit", - "BMS Max Charging Current", - "BMS Max Discharging Current", - ] - name: "BMS Voltage" + attribute: class: "voltage" state_class: "measurement" uom: "V" @@ -478,6 +470,7 @@ parameters: registers: [0x00D7] - name: "BMS Current" + attribute: class: "current" state_class: "measurement" uom: "A" @@ -505,7 +498,7 @@ parameters: registers: [0x00DB] icon: "mdi:battery" - - name: "BMS Alarm" + - name: "Battery BMS Alarm" class: "enum" state_class: "" uom: "" @@ -521,8 +514,10 @@ parameters: value: "Active" - key: "default" value: "Active" + attributes: ["BMS Fault Location"] - name: "BMS Fault Location" + attribute: class: "" state_class: "" uom: "" @@ -1005,7 +1000,22 @@ parameters: validation: min: 0 max: 101 - attributes: ["Battery Control Mode", "Battery Corrected Capacity"] + attributes: + [ + "Battery Control Mode", + "Battery Corrected Capacity", + "BMS SOC", + "BMS Current", + "BMS Voltage", + "BMS Type", + "BMS Other Symbol", + "BMS Charged Voltage", + "BMS Discharged Voltage", + "BMS Charging Current Limit", + "BMS Discharging Current Limit", + "BMS Max Charging Current", + "BMS Max Discharging Current" + ] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 8e43199..b2907da 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -448,7 +448,8 @@ parameters: registers: [0x00D5] icon: "mdi:battery" - - name: "BMS" + - name: "BMS SOC" + attribute: class: "" state_class: "measurement" uom: "%" @@ -459,18 +460,9 @@ parameters: validation: min: 0 max: 101 - attributes: - [ - "BMS Type", - "BMS Charged Voltage", - "BMS Discharged Voltage", - "BMS Charging Current Limit", - "BMS Discharging Current Limit", - "BMS Max Charging Current", - "BMS Max Discharging Current", - ] - name: "BMS Voltage" + attribute: class: "voltage" state_class: "measurement" uom: "V" @@ -479,6 +471,7 @@ parameters: registers: [0x00D7] - name: "BMS Current" + attribute: class: "current" state_class: "measurement" uom: "A" @@ -506,7 +499,7 @@ parameters: registers: [0x00DB] icon: "mdi:battery" - - name: "BMS Alarm" + - name: "Battery BMS Alarm" class: "enum" state_class: "" uom: "" @@ -522,8 +515,10 @@ parameters: value: "Active" - key: "default" value: "Active" + attributes: ["BMS Fault Location"] - name: "BMS Fault Location" + attribute: class: "" state_class: "" uom: "" @@ -1006,7 +1001,22 @@ parameters: validation: min: 0 max: 101 - attributes: ["Battery Control Mode", "Battery Corrected Capacity"] + attributes: + [ + "Battery Control Mode", + "Battery Corrected Capacity", + "BMS SOC", + "BMS Current", + "BMS Voltage", + "BMS Type", + "BMS Other Symbol", + "BMS Charged Voltage", + "BMS Discharged Voltage", + "BMS Charging Current Limit", + "BMS Discharging Current Limit", + "BMS Max Charging Current", + "BMS Max Discharging Current" + ] # Battery - The power of battery is S16bit - name: "Battery Power" diff --git a/custom_components/solarman/number.py b/custom_components/solarman/number.py index 645af18..6666c99 100644 --- a/custom_components/solarman/number.py +++ b/custom_components/solarman/number.py @@ -52,7 +52,7 @@ async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: class SolarmanNumberEntity(SolarmanSensor, NumberEntity): def __init__(self, coordinator, sensor): - SolarmanSensor.__init__(self, coordinator, sensor, 0) + SolarmanSensor.__init__(self, coordinator, sensor, 0, 0) # Set The Category of the entity. self._attr_entity_category = EntityCategory.CONFIG diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 43cb45b..4d9c9e3 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -35,7 +35,7 @@ def _create_sensor(coordinator, sensor, battery_nominal_voltage, battery_life_cy elif sensor["name"] in ("Battery SOH", "Battery State", "Today Battery Life Cycles", "Total Battery Life Cycles"): entity = SolarmanBatterySensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) else: - entity = SolarmanSensor(coordinator, sensor, battery_life_cycle_rating) + entity = SolarmanSensor(coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) entity.update() @@ -82,7 +82,7 @@ def update(self): self._attr_extra_state_attributes["updated"] = self.coordinator.inverter.status_lastUpdate class SolarmanSensor(SolarmanBaseEntity): - def __init__(self, coordinator, sensor, battery_life_cycle_rating): + def __init__(self, coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating): super().__init__(coordinator, sensor) self._attr_entity_registry_enabled_default = not "disabled" in sensor @@ -117,11 +117,11 @@ def __init__(self, coordinator, sensor, battery_life_cycle_rating): self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "options": options } if "name" in sensor and sensor["name"] == "Battery": - self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Life Cycle Rating": battery_life_cycle_rating } + self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Nominal Voltage": battery_nominal_voltage, "Life Cycle Rating": battery_life_cycle_rating } class SolarmanBatterySensor(SolarmanSensor): def __init__(self, coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating): - SolarmanSensor.__init__(self, coordinator, sensor, battery_life_cycle_rating) + SolarmanSensor.__init__(self, coordinator, sensor, battery_nominal_voltage, battery_life_cycle_rating) self._battery_nominal_voltage = battery_nominal_voltage self._battery_life_cycle_rating = battery_life_cycle_rating diff --git a/custom_components/solarman/switch.py b/custom_components/solarman/switch.py index b019ced..b1bcca3 100644 --- a/custom_components/solarman/switch.py +++ b/custom_components/solarman/switch.py @@ -51,7 +51,7 @@ async def async_unload_entry(hass: HomeAssistant, config: ConfigEntry) -> bool: class SolarmanSwitchEntity(SolarmanSensor, SwitchEntity): def __init__(self, coordinator, sensor): - SolarmanSensor.__init__(self, coordinator, sensor, 0) + SolarmanSensor.__init__(self, coordinator, sensor, 0, 0) # Set The Device Class of the entity. self._attr_device_class = SwitchDeviceClass.SWITCH # Set The Category of the entity. From 99f2dc38023fcecbf78c97d32ff65a9d56edccd4 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 05:06:23 +0200 Subject: [PATCH 32/39] refactor: Inverter profiles formatting --- .../afore_BNTxxxKTL-2mppt.yaml | 2 + .../inverter_definitions/deye_2mppt.yaml | 9 +- .../inverter_definitions/deye_4mppt.yaml | 2 + .../inverter_definitions/deye_hybrid.yaml | 2 +- .../inverter_definitions/deye_string.yaml | 7 +- .../hyd-zss-hp-3k-6k.yaml | 6 + .../inverter_definitions/kstar_hybrid.yaml | 8 +- .../inverter_definitions/sofar_g3hyd.yaml | 828 +++--- .../sofar_hyd3k-6k-es.yaml | 2287 ++++++++--------- .../inverter_definitions/sofar_lsw3.yaml | 1198 +++++---- .../inverter_definitions/sofar_wifikit.yaml | 32 +- .../solarman_dtsd422-d3.yaml | 4 + .../inverter_definitions/solis_1p8k-5g.yaml | 385 +-- .../inverter_definitions/solis_3p-4g.yaml | 438 ++-- .../inverter_definitions/solis_hybrid.yaml | 1882 +++++++------- .../inverter_definitions/solis_s6-gr1p.yaml | 579 ++--- .../zcs_azzurro-ktl-v3.yaml | 8 +- 17 files changed, 3875 insertions(+), 3802 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/afore_BNTxxxKTL-2mppt.yaml b/custom_components/solarman/inverter_definitions/afore_BNTxxxKTL-2mppt.yaml index 1589d74..a667215 100644 --- a/custom_components/solarman/inverter_definitions/afore_BNTxxxKTL-2mppt.yaml +++ b/custom_components/solarman/inverter_definitions/afore_BNTxxxKTL-2mppt.yaml @@ -1,4 +1,6 @@ +# # To use modbus function in Afore BNTxxxKTL inverters, You first need to change protocol from RS485 to MODBUS in inverter menu +# default: update_interval: 60 diff --git a/custom_components/solarman/inverter_definitions/deye_2mppt.yaml b/custom_components/solarman/inverter_definitions/deye_2mppt.yaml index 5b67fe2..636f91a 100644 --- a/custom_components/solarman/inverter_definitions/deye_2mppt.yaml +++ b/custom_components/solarman/inverter_definitions/deye_2mppt.yaml @@ -1,18 +1,15 @@ +# # First version: 22.02.2023 # Latest update: 08.09.2023 # Microinverter SUN600G3 (DEYE/VESDAS) # 2x MPPT, 2x inverter # 1x Logger, 2x Module, +# default: - update_interval: 60 + update_interval: 5 digits: 6 -requests: - - start: 0x0001 - end: 0x007D - mb_functioncode: 0x03 - parameters: - group: solar items: diff --git a/custom_components/solarman/inverter_definitions/deye_4mppt.yaml b/custom_components/solarman/inverter_definitions/deye_4mppt.yaml index 1e947c2..b5b76d5 100644 --- a/custom_components/solarman/inverter_definitions/deye_4mppt.yaml +++ b/custom_components/solarman/inverter_definitions/deye_4mppt.yaml @@ -1,8 +1,10 @@ +# # First version: 08.05.2022 # Latest update: 08.09.2023 # Microinverter SUN2000G3 (DEYE/VESDAS) # 4x MPPT, 4x inverter # 1x Logger, 4x Module, +# default: update_interval: 60 diff --git a/custom_components/solarman/inverter_definitions/deye_hybrid.yaml b/custom_components/solarman/inverter_definitions/deye_hybrid.yaml index c949743..acd9dd2 100644 --- a/custom_components/solarman/inverter_definitions/deye_hybrid.yaml +++ b/custom_components/solarman/inverter_definitions/deye_hybrid.yaml @@ -1,5 +1,5 @@ default: - update_interval: 60 + update_interval: 10 digits: 6 requests: diff --git a/custom_components/solarman/inverter_definitions/deye_string.yaml b/custom_components/solarman/inverter_definitions/deye_string.yaml index 64b78cc..4afa678 100644 --- a/custom_components/solarman/inverter_definitions/deye_string.yaml +++ b/custom_components/solarman/inverter_definitions/deye_string.yaml @@ -1,7 +1,6 @@ -requests: - - start: 0x0003 - end: 0x0070 - mb_functioncode: 0x03 +default: + update_interval: 5 + digits: 6 parameters: - group: PV diff --git a/custom_components/solarman/inverter_definitions/hyd-zss-hp-3k-6k.yaml b/custom_components/solarman/inverter_definitions/hyd-zss-hp-3k-6k.yaml index f230bc0..e5a7c58 100644 --- a/custom_components/solarman/inverter_definitions/hyd-zss-hp-3k-6k.yaml +++ b/custom_components/solarman/inverter_definitions/hyd-zss-hp-3k-6k.yaml @@ -1,5 +1,11 @@ +# # ZCS Azzurro 3-phase hybrid inverters # with LSW-3 WiFi logger with SN 27xxxxxxxx and FW LSW3_15_270A_1.53: +# + +default: + update_interval: 10 + digits: 6 requests: - start: 0x0404 diff --git a/custom_components/solarman/inverter_definitions/kstar_hybrid.yaml b/custom_components/solarman/inverter_definitions/kstar_hybrid.yaml index 0e57904..850c1e7 100644 --- a/custom_components/solarman/inverter_definitions/kstar_hybrid.yaml +++ b/custom_components/solarman/inverter_definitions/kstar_hybrid.yaml @@ -1,6 +1,7 @@ +# # KSTAR Hybrid Inverter # Modbus information taken from "MODBUS RS485 Communication Protocol V2.5" document provided by KSTAR - +# # This inverter exposes its data in the following registers (although not all of them are used by this definition file): # # - INPUT_REGISTERS 3000 - 3660 decimal, 0x0BB8 - 0x0E4C hexadecimal @@ -8,6 +9,11 @@ # # Each request can get a maximum of 125 registers as per modbus protocol (start and end included), so we need to # split up the list of used registers into multiple requests of maximum 125 registers each. +# + +default: + update_interval: 10 + digits: 6 requests: # Start requesting from the first needed register (3000) diff --git a/custom_components/solarman/inverter_definitions/sofar_g3hyd.yaml b/custom_components/solarman/inverter_definitions/sofar_g3hyd.yaml index f64afc9..9aa6064 100644 --- a/custom_components/solarman/inverter_definitions/sofar_g3hyd.yaml +++ b/custom_components/solarman/inverter_definitions/sofar_g3hyd.yaml @@ -1,6 +1,12 @@ +# # Sofar G3 also HYD 5-20KTL-3PH # This works also for rebranded ZCS Azzurro 3-Phase inverters such as the 3PH HYD6000 ZSS, or single phase such as 1PH HY6000 ZSS HP # Note that this won't work if your ZCS inverter is connected via Connext, you have to be using a Wi-Fi or Ethernet Kit such as ZSM-WIFI-USB. +# + +default: + update_interval: 10 + digits: 6 requests: - start: 0x0404 # inverter and faults @@ -32,7 +38,6 @@ requests: mb_functioncode: 0x03 parameters: - - group: Inverter items: - name: "Inverter status" @@ -41,7 +46,7 @@ parameters: uom: "" scale: 1 rule: 1 - registers: [ 0x0404 ] + registers: [0x0404] isstr: true lookup: - key: 0 @@ -60,155 +65,164 @@ parameters: value: "upgrade" - key: 7 value: "self-charging" - icon: 'mdi:wrench' + icon: "mdi:wrench" - name: "Ambient temperature 1" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x0418 ] - icon: 'mdi:thermometer' + registers: [0x0418] + icon: "mdi:thermometer" - name: "Ambient temperature 2" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x0419 ] - icon: 'mdi:thermometer' + registers: [0x0419] + icon: "mdi:thermometer" - name: "Radiator temperature 1" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x041A ] - icon: 'mdi:thermometer' + registers: [0x041A] + icon: "mdi:thermometer" - name: "Radiator temperature 2" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x041B ] - icon: 'mdi:thermometer' + registers: [0x041B] + icon: "mdi:thermometer" - name: "Radiator temperature 3" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x041C ] - icon: 'mdi:thermometer' + registers: [0x041C] + icon: "mdi:thermometer" - name: "Radiator temperature 4" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x041D ] - icon: 'mdi:thermometer' + registers: [0x041D] + icon: "mdi:thermometer" - name: "Radiator temperature 5" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x041E ] - icon: 'mdi:thermometer' + registers: [0x041E] + icon: "mdi:thermometer" - name: "Radiator temperature 6" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x041F ] - icon: 'mdi:thermometer' + registers: [0x041F] + icon: "mdi:thermometer" - name: "Module temperature 1" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x0420 ] - icon: 'mdi:thermometer' + registers: [0x0420] + icon: "mdi:thermometer" - name: "Module temperature 2" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x0421 ] - icon: 'mdi:thermometer' + registers: [0x0421] + icon: "mdi:thermometer" - name: "Module temperature 3" class: "temperature" uom: "°C" scale: 1 rule: 2 - registers: [ 0x0422 ] - icon: 'mdi:thermometer' + registers: [0x0422] + icon: "mdi:thermometer" - name: "Generation Time Today" class: "duration" state_class: "measurement" uom: "min" scale: 1 rule: 1 - registers: [ 0x0426 ] - icon: 'mdi:clock' + registers: [0x0426] + icon: "mdi:clock" - name: "Insulation resistance" class: "" state_class: "measurement" uom: "kΩ" scale: 1 rule: 1 - registers: [ 0x042B ] - icon: 'mdi:omega' + registers: [0x042B] + icon: "mdi:omega" - name: "Serial Number" class: "" uom: "" scale: 1 rule: 5 isstr: true - registers: [ 0x0445,0x0446,0x0447,0x0448,0x0449,0x044A,0x044B,0x044C ] # serial number 17th to 20th digits are in 0x0470 and 0x0471 - icon: 'mdi:barcode' + registers: [ + 0x0445, + 0x0446, + 0x0447, + 0x0448, + 0x0449, + 0x044A, + 0x044B, + 0x044C, + ] # serial number 17th to 20th digits are in 0x0470 and 0x0471 + icon: "mdi:barcode" - name: "Hardware Version" class: "" uom: "" scale: 1 rule: 5 isstr: true - registers: [ 0x044D,0x044E ] - icon: 'mdi:alpha-v' + registers: [0x044D, 0x044E] + icon: "mdi:alpha-v" - name: "Software Version Master" class: "" uom: "" scale: 1 rule: 5 isstr: true - registers: [ 0x0453,0x0454,0x0455,0x0456 ] - icon: 'mdi:alpha-v' + registers: [0x0453, 0x0454, 0x0455, 0x0456] + icon: "mdi:alpha-v" - name: "Software Version Slave" class: "" uom: "" scale: 1 rule: 5 isstr: true - registers: [ 0x0457,0x0458,0x0459,0x045A ] - icon: 'mdi:alpha-v' + registers: [0x0457, 0x0458, 0x0459, 0x045A] + icon: "mdi:alpha-v" - name: "Safety Version" class: "" uom: "" scale: 1 rule: 7 - registers: [ 0x045B,0x045C ] - icon: 'mdi:alpha-v' + registers: [0x045B, 0x045C] + icon: "mdi:alpha-v" - name: "Safety Firmware Version" class: "" uom: "" scale: 1 rule: 5 isstr: true - registers: [ 0x0460,0x0461,0x0462,0x0463 ] - icon: 'mdi:alpha-v' + registers: [0x0460, 0x0461, 0x0462, 0x0463] + icon: "mdi:alpha-v" - name: "Safety Hardware Version" class: "" uom: "" scale: 1 rule: 5 isstr: true - registers: [ 0x0464,0x0465 ] - icon: 'mdi:alpha-v' + registers: [0x0464, 0x0465] + icon: "mdi:alpha-v" - group: InverterDC items: @@ -218,48 +232,48 @@ parameters: uom: "V" scale: 0.1 rule: 1 - registers: [ 0x0584 ] - icon: 'mdi:solar-power' + registers: [0x0584] + icon: "mdi:solar-power" - name: "PV1 Current" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x0585 ] - icon: 'mdi:solar-power' + registers: [0x0585] + icon: "mdi:solar-power" - name: "PV1 Power" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 1 - registers: [ 0x0586 ] - icon: 'mdi:solar-power' + registers: [0x0586] + icon: "mdi:solar-power" - name: "PV2 Voltage" class: "voltage" state_class: "measurement" uom: "V" scale: 0.1 rule: 1 - registers: [ 0x0587 ] - icon: 'mdi:solar-power' + registers: [0x0587] + icon: "mdi:solar-power" - name: "PV2 Current" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x0588 ] - icon: 'mdi:solar-power' + registers: [0x0588] + icon: "mdi:solar-power" - name: "PV2 Power" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 1 - registers: [ 0x0589 ] - icon: 'mdi:solar-power' + registers: [0x0589] + icon: "mdi:solar-power" - group: Battery items: @@ -269,80 +283,80 @@ parameters: uom: "V" scale: 0.1 rule: 1 - registers: [ 0x0604 ] - icon: 'mdi:battery' + registers: [0x0604] + icon: "mdi:battery" - name: "Battery 1 Current" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 2 - registers: [ 0x0605 ] - icon: 'mdi:current-dc' + registers: [0x0605] + icon: "mdi:current-dc" - name: "Battery 1 Power" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0606 ] - icon: 'mdi:battery-charging' + registers: [0x0606] + icon: "mdi:battery-charging" - name: "Battery 1 Temperature" class: "temperature" state_class: "measurement" uom: "°C" scale: 1 rule: 2 - registers: [ 0x0607 ] - icon: 'mdi:battery' + registers: [0x0607] + icon: "mdi:battery" - name: "Battery 1 SOC" class: "battery" state_class: "measurement" uom: "%" scale: 1 rule: 1 - registers: [ 0x0608 ] - icon: 'mdi:battery' + registers: [0x0608] + icon: "mdi:battery" - name: "Battery 1 SOH" class: "battery" state_class: "measurement" uom: "%" scale: 1 rule: 1 - registers: [ 0x0609 ] - icon: 'mdi:battery' + registers: [0x0609] + icon: "mdi:battery" - name: "Battery 1 Number of Cycles" class: "" state_class: "measurement" uom: "cycle" scale: 1 rule: 1 - registers: [ 0x060A ] - icon: 'mdi:battery' + registers: [0x060A] + icon: "mdi:battery" - name: "Battery DOD" class: "" state_class: "measurement" uom: "%" scale: 1 rule: 1 - registers: [ 0x104D ] - icon: 'mdi:battery' + registers: [0x104D] + icon: "mdi:battery" - name: "Battery EOD" class: "" state_class: "measurement" uom: "%" scale: 1 rule: 1 - registers: [ 0x104E ] - icon: 'mdi:battery' + registers: [0x104E] + icon: "mdi:battery" - name: "Battery EPS Buffer" class: "" state_class: "measurement" uom: "%" scale: 1 rule: 1 - registers: [ 0x1052 ] - icon: 'mdi:battery-low' + registers: [0x1052] + icon: "mdi:battery-low" - group: GridAC items: @@ -352,288 +366,288 @@ parameters: uom: "Hz" scale: 0.01 rule: 1 - registers: [ 0x0484 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0484] + icon: "mdi:home-lightning-bolt" - name: "ActivePower_Output_Total" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0485 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0485] + icon: "mdi:home-lightning-bolt" - name: "ReactivePower_Output_Total" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0486 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0486] + icon: "mdi:home-lightning-bolt" - name: "ApparentPower_Output_Total" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0487 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0487] + icon: "mdi:home-lightning-bolt" - name: "ActivePower_PCC_Total" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0488 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0488] + icon: "mdi:home-lightning-bolt" - name: "ReactivePower_PCC_Total" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0489 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0489] + icon: "mdi:home-lightning-bolt" - name: "ApparentPower_PCC_Total" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x048A ] - icon: 'mdi:home-lightning-bolt' + registers: [0x048A] + icon: "mdi:home-lightning-bolt" - name: "Voltage_Phase_R" class: "voltage" state_class: "measurement" uom: "V" scale: 0.1 rule: 1 - registers: [ 0x048D ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x048D] + icon: "mdi:lightning-bolt-outline" - name: "Current_Output_R" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x048E ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x048E] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_Output_R" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x048F ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x048F] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_Output_R" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0490 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0490] + icon: "mdi:lightning-bolt-outline" - name: "PowerFactor_Output_R" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.001 rule: 2 - registers: [ 0x0491 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0491] + icon: "mdi:lightning-bolt-outline" - name: "Current_PCC_R" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x0492 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0492] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_PCC_R" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0493 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0493] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_PCC_R" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0494 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0494] + icon: "mdi:lightning-bolt-outline" - name: "PowerFactor_PCC_R" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.001 rule: 2 - registers: [ 0x0495 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0495] + icon: "mdi:lightning-bolt-outline" - name: "Voltage_Phase_S" class: "voltage" state_class: "measurement" uom: "V" scale: 0.1 rule: 1 - registers: [ 0x0498 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0498] + icon: "mdi:lightning-bolt-outline" - name: "Current_Output_S" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x0499 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0499] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_Output_S" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x049A ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x049A] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_Output_S" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x049B ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x049B] + icon: "mdi:lightning-bolt-outline" - name: "PowerFactor_Output_S" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.001 rule: 2 - registers: [ 0x049C ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x049C] + icon: "mdi:lightning-bolt-outline" - name: "Current_PCC_S" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x049D ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x049D] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_PCC_S" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x049E ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x049E] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_PCC_S" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x049F ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x049F] + icon: "mdi:lightning-bolt-outline" - name: "PowerFactor_PCC_S" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.001 rule: 2 - registers: [ 0x04A0 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04A0] + icon: "mdi:lightning-bolt-outline" - name: "Voltage_Phase_T" class: "voltage" state_class: "measurement" uom: "V" scale: 0.1 rule: 1 - registers: [ 0x04A3 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04A3] + icon: "mdi:lightning-bolt-outline" - name: "Current_Output_T" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x04A4 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04A4] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_Output_T" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x04A5 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04A5] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_Output_T" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x04A6 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04A6] + icon: "mdi:lightning-bolt-outline" - name: "PowerFactor_Output_T" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.001 rule: 2 - registers: [ 0x04A7 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04A7] + icon: "mdi:lightning-bolt-outline" - name: "Current_PCC_T" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x04A8 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04A8] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_PCC_T" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x04A9 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04A9] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_PCC_T" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x04AA ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04AA] + icon: "mdi:lightning-bolt-outline" - name: "PowerFactor_PCC_T" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.001 rule: 2 - registers: [ 0x04AB ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04AB] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_PV_Ext" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 1 - registers: [ 0x04AE ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04AE] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_Load_Sys" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x04AF ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x04AF] + icon: "mdi:lightning-bolt-outline" - group: GridEPS items: @@ -643,176 +657,176 @@ parameters: uom: "W" scale: 10 rule: 2 - registers: [ 0x0504 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0504] + icon: "mdi:home-lightning-bolt" - name: "ReactivePower_Load_Total_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0505 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0505] + icon: "mdi:home-lightning-bolt" - name: "ApparentPower_Load_Total_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0506 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0506] + icon: "mdi:home-lightning-bolt" - name: "Frequency_Output_EPS" class: "current" state_class: "measurement" uom: "Hz" scale: 0.01 rule: 1 - registers: [ 0x0507 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0507] + icon: "mdi:home-lightning-bolt" - name: "Voltage_Output_R_EPS" class: "voltage" state_class: "measurement" uom: "V" scale: 0.1 rule: 1 - registers: [ 0x050A ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x050A] + icon: "mdi:lightning-bolt-outline" - name: "Current_Load_R_EPS" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x050B ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x050B] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_Load_R_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x050C ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x050C] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_Load_R_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x050D ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x050D] + icon: "mdi:lightning-bolt-outline" - name: "ApparentPower_Load_R_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x050E ] - icon: 'mdi:home-lightning-bolt' + registers: [0x050E] + icon: "mdi:home-lightning-bolt" - name: "LoadPeakRatio_R_EPS" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.01 rule: 2 - registers: [ 0x050F ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x050F] + icon: "mdi:lightning-bolt-outline" - name: "Voltage_Output_S_EPS" class: "voltage" state_class: "measurement" uom: "V" scale: 0.1 rule: 1 - registers: [ 0x0512 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0512] + icon: "mdi:lightning-bolt-outline" - name: "Current_Load_S_EPS" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x0513 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0513] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_Load_S_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0514 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0514] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_Load_S_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0515 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0515] + icon: "mdi:lightning-bolt-outline" - name: "ApparentPower_Load_S_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x0516 ] - icon: 'mdi:home-lightning-bolt' + registers: [0x0516] + icon: "mdi:home-lightning-bolt" - name: "LoadPeakRatio_S_EPS" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.01 rule: 2 - registers: [ 0x0517 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0517] + icon: "mdi:lightning-bolt-outline" - name: "Voltage_Output_T_EPS" class: "voltage" state_class: "measurement" uom: "V" scale: 0.1 rule: 1 - registers: [ 0x051A ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x051A] + icon: "mdi:lightning-bolt-outline" - name: "Current_Load_T_EPS" class: "current" state_class: "measurement" uom: "A" scale: 0.01 rule: 1 - registers: [ 0x051B ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x051B] + icon: "mdi:lightning-bolt-outline" - name: "ActivePower_Load_T_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x051C ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x051C] + icon: "mdi:lightning-bolt-outline" - name: "ReactivePower_Load_T_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x051D ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x051D] + icon: "mdi:lightning-bolt-outline" - name: "ApparentPower_Load_T_EPS" class: "power" state_class: "measurement" uom: "W" scale: 10 rule: 2 - registers: [ 0x051E ] - icon: 'mdi:home-lightning-bolt' + registers: [0x051E] + icon: "mdi:home-lightning-bolt" - name: "LoadPeakRatio_T_EPS" class: "powerfactor" state_class: "measurement" uom: "p.u." scale: 0.01 rule: 2 - registers: [ 0x051F ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x051F] + icon: "mdi:lightning-bolt-outline" - group: Generation items: @@ -822,96 +836,96 @@ parameters: uom: "kWh" scale: 0.01 rule: 3 - registers: [ 0x0685,0x0684 ] - icon: 'mdi:solar-power' + registers: [0x0685, 0x0684] + icon: "mdi:solar-power" - name: "Total PV Generation" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.1 rule: 3 - registers: [ 0x0687,0x0686 ] - icon: 'mdi:solar-power' + registers: [0x0687, 0x0686] + icon: "mdi:solar-power" - name: "Daily Load Consumption" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.01 rule: 3 - registers: [ 0x0689,0x0688 ] - icon: 'mdi:lightning-bolt-outline' + registers: [0x0689, 0x0688] + icon: "mdi:lightning-bolt-outline" - name: "Total Load Consumption" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.1 rule: 3 - registers: [ 0x068B,0x068A ] - icon: 'mdi:solar-power' + registers: [0x068B, 0x068A] + icon: "mdi:solar-power" - name: "Daily Energy Bought" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.01 rule: 3 - registers: [ 0x068D,0x068C ] - icon: 'mdi:transmission-tower-export' + registers: [0x068D, 0x068C] + icon: "mdi:transmission-tower-export" - name: "Total Energy Bought" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.1 rule: 3 - registers: [ 0x068F,0x068E ] - icon: 'mdi:transmission-tower-export' + registers: [0x068F, 0x068E] + icon: "mdi:transmission-tower-export" - name: "Daily Energy Sold" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.01 rule: 3 - registers: [ 0x0691,0x0690 ] - icon: 'mdi:transmission-tower-import' + registers: [0x0691, 0x0690] + icon: "mdi:transmission-tower-import" - name: "Total Energy Sold" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.1 rule: 3 - registers: [ 0x0693,0x0692 ] - icon: 'mdi:transmission-tower-import' + registers: [0x0693, 0x0692] + icon: "mdi:transmission-tower-import" - name: "Daily Battery Charge" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.01 rule: 3 - registers: [ 0x0695,0x0694 ] - icon: 'mdi:battery-plus' + registers: [0x0695, 0x0694] + icon: "mdi:battery-plus" - name: "Total Battery Charge" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.1 rule: 3 - registers: [ 0x0697,0x0696 ] - icon: 'mdi:battery-plus' + registers: [0x0697, 0x0696] + icon: "mdi:battery-plus" - name: "Daily Battery Discharge" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.01 rule: 3 - registers: [ 0x0699,0x0698 ] - icon: 'mdi:battery-minus' + registers: [0x0699, 0x0698] + icon: "mdi:battery-minus" - name: "Total Battery Discharge" class: "energy" state_class: "total_increasing" uom: "kWh" scale: 0.1 rule: 3 - registers: [ 0x069b,0x069A ] - icon: 'mdi:battery-minus' + registers: [0x069b, 0x069A] + icon: "mdi:battery-minus" - group: Alert items: @@ -921,7 +935,21 @@ parameters: uom: "" scale: 1 rule: 6 - registers: [ 0x0405,0x0406,0x0407,0x0408,0x0409,0x040A,0x040B,0x040C,0x040D,0x040E,0x040F,0x0410 ] + registers: + [ + 0x0405, + 0x0406, + 0x0407, + 0x0408, + 0x0409, + 0x040A, + 0x040B, + 0x040C, + 0x040D, + 0x040E, + 0x040F, + 0x0410, + ] - name: "Fault 1" class: "" @@ -929,9 +957,9 @@ parameters: uom: "" scale: 1 rule: 1 - registers: [ 0x0405 ] + registers: [0x0405] isstr: true - icon: 'mdi:wrench' + icon: "mdi:wrench" lookup: - key: 0 value: "No error" @@ -977,9 +1005,9 @@ parameters: uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' + icon: "mdi:wrench" isstr: true - registers: [ 0x0406 ] + registers: [0x0406] lookup: - key: 0 value: "No error" @@ -1021,221 +1049,221 @@ parameters: uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' + icon: "mdi:wrench" isstr: true - registers: [ 0x0407 ] + registers: [0x0407] lookup: - key: 0 value: "No error" - key: 1 - value: 'ID033 SPI communication error (DC side)' + value: "ID033 SPI communication error (DC side)" - key: 2 - value: 'ID034 SPI communication error (AC side)' + value: "ID034 SPI communication error (AC side)" - key: 4 - value: 'ID035 Chip error (DC side)' + value: "ID035 Chip error (DC side)" - key: 8 - value: 'ID036 Chip error (AC side)' + value: "ID036 Chip error (AC side)" - key: 16 - value: 'ID037 Auxiliary power error' + value: "ID037 Auxiliary power error" - key: 32 - value: 'ID038 Inverter soft start failure' + value: "ID038 Inverter soft start failure" - key: 64 - value: 'ID039 ' + value: "ID039 " - key: 128 - value: 'ID040 ' + value: "ID040 " - key: 256 - value: 'ID041 Relay detection failure' + value: "ID041 Relay detection failure" - key: 512 - value: 'ID042 Low insulation impedance' + value: "ID042 Low insulation impedance" - key: 1024 - value: 'ID043 Grounding error' + value: "ID043 Grounding error" - key: 2048 - value: 'ID044 Input mode setting error' + value: "ID044 Input mode setting error" - key: 4096 - value: 'ID045 CT error' + value: "ID045 CT error" - key: 8192 - value: 'ID046 Input reversal error' + value: "ID046 Input reversal error" - key: 16384 - value: 'ID047 Parallel error' + value: "ID047 Parallel error" - key: 32768 - value: 'ID048 Serial number error' + value: "ID048 Serial number error" - name: "Fault 4" class: "" state_class: "" uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' - registers: [ 0x0408 ] + icon: "mdi:wrench" + registers: [0x0408] isstr: true lookup: - key: 0 value: "No error" - key: 1 - value: 'ID049 Battery temperature protection' + value: "ID049 Battery temperature protection" - key: 2 - value: 'ID050 Heat sink 1 temperature protection' + value: "ID050 Heat sink 1 temperature protection" - key: 4 - value: 'ID051 Heater 2 temperature protection' + value: "ID051 Heater 2 temperature protection" - key: 8 - value: 'ID052 Heater 3 temperature protection' + value: "ID052 Heater 3 temperature protection" - key: 16 - value: 'ID053 Heatsink 4 temperature protection' + value: "ID053 Heatsink 4 temperature protection" - key: 32 - value: 'ID054 Heatsink 5 temperature protection' + value: "ID054 Heatsink 5 temperature protection" - key: 64 - value: 'ID055 Radiator 6 temperature protection' + value: "ID055 Radiator 6 temperature protection" - key: 128 - value: 'ID056 ' + value: "ID056 " - key: 256 - value: 'ID057 Ambient temperature 1 protection' + value: "ID057 Ambient temperature 1 protection" - key: 512 - value: 'ID058 Ambient temperature 2 protection' + value: "ID058 Ambient temperature 2 protection" - key: 1024 - value: 'ID059 Module 1 temperature protection' + value: "ID059 Module 1 temperature protection" - key: 2048 - value: 'ID060 Module 2 temperature protection' + value: "ID060 Module 2 temperature protection" - key: 4096 - value: 'ID061 Module 3 temperature protection' + value: "ID061 Module 3 temperature protection" - key: 8192 - value: 'ID062 Module temperature difference is too large' + value: "ID062 Module temperature difference is too large" - key: 16384 - value: 'ID063 ' + value: "ID063 " - key: 32768 - value: 'ID064 ' + value: "ID064 " - name: "Fault 5" class: "" state_class: "" uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' - registers: [ 0x0409 ] + icon: "mdi:wrench" + registers: [0x0409] isstr: true lookup: - key: 0 value: "No error" - key: 1 - value: 'ID065 Bus voltage RMS unbalance' + value: "ID065 Bus voltage RMS unbalance" - key: 2 - value: 'ID066 Bus voltage transient value unbalance' + value: "ID066 Bus voltage transient value unbalance" - key: 4 - value: 'ID067 Undervoltage of busbar during grid connection' + value: "ID067 Undervoltage of busbar during grid connection" - key: 8 - value: 'ID068 Bus bar low voltage' + value: "ID068 Bus bar low voltage" - key: 16 - value: 'ID069 PV overvoltage' + value: "ID069 PV overvoltage" - key: 32 - value: 'ID070 Battery over-voltage' + value: "ID070 Battery over-voltage" - key: 64 - value: 'ID071 LLCBus overvoltage protection' + value: "ID071 LLCBus overvoltage protection" - key: 128 - value: 'ID072 Inverter bus voltage RMS software overvoltage' + value: "ID072 Inverter bus voltage RMS software overvoltage" - key: 256 - value: 'ID073 Inverter bus voltage transient value software overvoltage' + value: "ID073 Inverter bus voltage transient value software overvoltage" - key: 512 - value: 'ID074 Flying Cross Capacitor Overvoltage Protection' + value: "ID074 Flying Cross Capacitor Overvoltage Protection" - key: 1024 - value: 'ID075 Flying Cross capacitor undervoltage protection' + value: "ID075 Flying Cross capacitor undervoltage protection" - key: 2048 - value: 'ID076 ' + value: "ID076 " - key: 4096 - value: 'ID077 ' + value: "ID077 " - key: 8192 - value: 'ID078 ' + value: "ID078 " - key: 16384 - value: 'ID079 ' + value: "ID079 " - key: 32768 - value: 'ID080 ' + value: "ID080 " - name: "Fault 6" class: "" state_class: "" uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' + icon: "mdi:wrench" isstr: true - registers: [ 0x040A ] + registers: [0x040A] lookup: - key: 0 value: "No error" - key: 1 - value: 'ID081 Battery overcurrent software protection' + value: "ID081 Battery overcurrent software protection" - key: 2 - value: 'ID082 Dci overcurrent protection' + value: "ID082 Dci overcurrent protection" - key: 4 - value: 'ID083 Output transient current protection' + value: "ID083 Output transient current protection" - key: 8 - value: 'ID084 BuckBoost software overcurrent' + value: "ID084 BuckBoost software overcurrent" - key: 16 - value: 'ID085 Output RMS current protection' + value: "ID085 Output RMS current protection" - key: 32 - value: 'ID086 PV instantaneous current overcurrent software protection' + value: "ID086 PV instantaneous current overcurrent software protection" - key: 64 - value: 'ID087 PV parallel uneven current' + value: "ID087 PV parallel uneven current" - key: 128 - value: 'ID088 Output current unbalance' + value: "ID088 Output current unbalance" - key: 256 - value: 'ID089 PV software overcurrent protection' + value: "ID089 PV software overcurrent protection" - key: 512 - value: 'ID090 Balanced circuit overcurrent protection' + value: "ID090 Balanced circuit overcurrent protection" - key: 1024 - value: 'ID091 Resonance protection' + value: "ID091 Resonance protection" - key: 2048 - value: 'ID092 ' + value: "ID092 " - key: 4096 - value: 'ID093 ' + value: "ID093 " - key: 8192 - value: 'ID094 ' + value: "ID094 " - key: 16384 - value: 'ID095 ' + value: "ID095 " - key: 32768 - value: 'ID096 ' + value: "ID096 " - name: "Fault 7" class: "" state_class: "" uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' + icon: "mdi:wrench" isstr: true - registers: [ 0x040B ] + registers: [0x040B] lookup: - key: 0 value: "No error" - key: 1 - value: 'ID097 LLC bus hardware overvoltage' + value: "ID097 LLC bus hardware overvoltage" - key: 2 - value: 'ID098 Inverter bus hardware overvoltage' + value: "ID098 Inverter bus hardware overvoltage" - key: 4 - value: 'ID099 BuckBoost hardware overcurrent' + value: "ID099 BuckBoost hardware overcurrent" - key: 8 - value: 'ID100 Battery hardware overcurrent' + value: "ID100 Battery hardware overcurrent" - key: 16 - value: 'ID101 ' + value: "ID101 " - key: 32 - value: 'ID102 PV hardware overcurrent' + value: "ID102 PV hardware overcurrent" - key: 64 - value: 'ID103 AC output hardware overcurrent' + value: "ID103 AC output hardware overcurrent" - key: 128 - value: 'ID104 ' + value: "ID104 " - key: 256 - value: 'ID105 Power meter error' + value: "ID105 Power meter error" - key: 512 - value: 'ID106 Serial number model error' + value: "ID106 Serial number model error" - key: 1024 - value: 'ID107 ' + value: "ID107 " - key: 2048 - value: 'ID108 ' + value: "ID108 " - key: 4096 - value: 'ID109 ' + value: "ID109 " - key: 8192 - value: 'ID110 Overload protection 1' + value: "ID110 Overload protection 1" - key: 16384 - value: 'ID111 Overload protection 2' + value: "ID111 Overload protection 2" - key: 32768 - value: 'ID112 Overload protection 3' + value: "ID112 Overload protection 3" - name: "Fault 8" class: "" @@ -1243,218 +1271,218 @@ parameters: uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' - registers: [ 0x040C ] + icon: "mdi:wrench" + registers: [0x040C] isstr: true lookup: - key: 0 value: "No error" - key: 1 - value: 'ID113 Overtemperature derating' + value: "ID113 Overtemperature derating" - key: 2 - value: 'ID114 Frequency down load' + value: "ID114 Frequency down load" - key: 4 - value: 'ID115 Frequency loading' + value: "ID115 Frequency loading" - key: 8 - value: 'ID116 Voltage down load' + value: "ID116 Voltage down load" - key: 16 - value: 'ID117 Voltage loading' + value: "ID117 Voltage loading" - key: 32 - value: 'ID118 ' + value: "ID118 " - key: 64 - value: 'ID119 ' + value: "ID119 " - key: 128 - value: 'ID120 ' + value: "ID120 " - key: 256 - value: 'ID121 Lightning protection failure (DC)' + value: "ID121 Lightning protection failure (DC)" - key: 512 - value: 'ID122 Lightning protection failure (AC)' + value: "ID122 Lightning protection failure (AC)" - key: 1024 - value: 'ID123 ' + value: "ID123 " - key: 2048 - value: 'ID124 Battery low voltage protection' + value: "ID124 Battery low voltage protection" - key: 4096 - value: 'ID125 Battery low voltage shutdown' + value: "ID125 Battery low voltage shutdown" - key: 8192 - value: 'ID126 Battery low voltage pre-alarm' + value: "ID126 Battery low voltage pre-alarm" - key: 16384 - value: 'ID127 ' + value: "ID127 " - key: 32768 - value: 'ID128 ' + value: "ID128 " - name: "Fault 9" class: "" state_class: "" uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' + icon: "mdi:wrench" isstr: true - registers: [ 0x040D ] + registers: [0x040D] lookup: - key: 0 value: "No error" - key: 1 - value: 'ID129 Output hardware overcurrent permanent fault' + value: "ID129 Output hardware overcurrent permanent fault" - key: 2 - value: 'ID130 Bus overvoltage permanent fault' + value: "ID130 Bus overvoltage permanent fault" - key: 4 - value: 'ID131 Bus hardware over-voltage permanent fault' + value: "ID131 Bus hardware over-voltage permanent fault" - key: 8 - value: 'ID132 PV uneven flow permanent fault' + value: "ID132 PV uneven flow permanent fault" - key: 16 - value: 'ID133 Battery overcurrent permanent fault in EPS mode' + value: "ID133 Battery overcurrent permanent fault in EPS mode" - key: 32 - value: 'ID134 Output transient overcurrent permanent fault' + value: "ID134 Output transient overcurrent permanent fault" - key: 64 - value: 'ID135 Output current unbalance permanent fault' + value: "ID135 Output current unbalance permanent fault" - key: 128 - value: 'ID136 ' + value: "ID136 " - key: 256 - value: 'ID137 Input mode setting error permanent fault' + value: "ID137 Input mode setting error permanent fault" - key: 512 - value: 'ID138 Input overcurrent permanent fault' + value: "ID138 Input overcurrent permanent fault" - key: 1024 - value: 'ID139 Input hardware overcurrent permanent fault' + value: "ID139 Input hardware overcurrent permanent fault" - key: 2048 - value: 'ID140 Relay permanent fault' + value: "ID140 Relay permanent fault" - key: 4096 - value: 'ID141 Bus unbalance permanent fault' + value: "ID141 Bus unbalance permanent fault" - key: 8192 - value: 'ID142 Lightning protection permanent fault - DC side' + value: "ID142 Lightning protection permanent fault - DC side" - key: 16384 - value: 'ID143 Lightning protection permanent fault - AC side' + value: "ID143 Lightning protection permanent fault - AC side" - key: 32768 - value: 'ID144 ' + value: "ID144 " - name: "Fault 10" class: "" state_class: "" uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' + icon: "mdi:wrench" isstr: true - registers: [ 0x040E ] + registers: [0x040E] lookup: - key: 0 value: "No error" - key: 1 - value: 'ID145 USB fault' + value: "ID145 USB fault" - key: 2 - value: 'ID146 WIFI fault' + value: "ID146 WIFI fault" - key: 4 - value: 'ID147 Bluetooth fault' + value: "ID147 Bluetooth fault" - key: 8 - value: 'ID148 RTC clock fault' + value: "ID148 RTC clock fault" - key: 16 - value: 'ID149 Communication board EEPROM error' + value: "ID149 Communication board EEPROM error" - key: 32 - value: 'ID150 Communication board FLASH error' + value: "ID150 Communication board FLASH error" - key: 64 - value: 'ID151 ' + value: "ID151 " - key: 128 - value: 'ID152 Safety regulation version error' + value: "ID152 Safety regulation version error" - key: 256 - value: 'ID153 SCI communication error (DC side)' + value: "ID153 SCI communication error (DC side)" - key: 512 - value: 'ID154 SCI communication error (AC side)' + value: "ID154 SCI communication error (AC side)" - key: 1024 - value: 'ID155 SCI communication error (convergence board side)' + value: "ID155 SCI communication error (convergence board side)" - key: 2048 - value: 'ID156 Software version inconsistency' + value: "ID156 Software version inconsistency" - key: 4096 - value: 'ID157 Lithium battery 1 communication error' + value: "ID157 Lithium battery 1 communication error" - key: 8192 - value: 'ID158 Li-ion battery 2 communication error' + value: "ID158 Li-ion battery 2 communication error" - key: 16384 - value: 'ID159 Lithium battery 3 communication error' + value: "ID159 Lithium battery 3 communication error" - key: 32768 - value: 'ID160 Lithium battery 4 communication failure' + value: "ID160 Lithium battery 4 communication failure" - name: "Fault 11" class: "" state_class: "" uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' - registers: [ 0x040F ] + icon: "mdi:wrench" + registers: [0x040F] isstr: true lookup: - key: 0 value: "No error" - key: 1 - value: 'ID161 Forced shutdown' + value: "ID161 Forced shutdown" - key: 2 - value: 'ID162 Remote shutdown' + value: "ID162 Remote shutdown" - key: 4 - value: 'ID163 Drms0 shutdown' + value: "ID163 Drms0 shutdown" - key: 8 - value: 'ID164 ' + value: "ID164 " - key: 16 - value: 'ID165 Remote down load' + value: "ID165 Remote down load" - key: 32 - value: 'ID166 Logic interface down load' + value: "ID166 Logic interface down load" - key: 64 - value: 'ID167 Anti-Reverse Flow Downgrade' + value: "ID167 Anti-Reverse Flow Downgrade" - key: 128 - value: 'ID168 ' + value: "ID168 " - key: 256 - value: 'ID169 Fan 1 failure' + value: "ID169 Fan 1 failure" - key: 512 - value: 'ID170 Fan 2 failure' + value: "ID170 Fan 2 failure" - key: 1024 - value: 'ID171 Fan 3 failure' + value: "ID171 Fan 3 failure" - key: 2048 - value: 'ID172 Fan 4 failure' + value: "ID172 Fan 4 failure" - key: 4096 - value: 'ID173 Fan 5 failure' + value: "ID173 Fan 5 failure" - key: 8192 - value: 'ID174 Fan 6 failure' + value: "ID174 Fan 6 failure" - key: 16384 - value: 'ID175 Fan 7 fault' + value: "ID175 Fan 7 fault" - key: 32768 - value: 'ID176 Meter communication failure' + value: "ID176 Meter communication failure" - name: "Fault 12" class: "" state_class: "" uom: "" scale: 1 rule: 1 - icon: 'mdi:wrench' - registers: [ 0x0410 ] + icon: "mdi:wrench" + registers: [0x0410] isstr: true lookup: - key: 0 value: "No error" - key: 1 - value: 'ID177 BMS over-voltage alarm' + value: "ID177 BMS over-voltage alarm" - key: 2 - value: 'ID178 BMS undervoltage alarm' + value: "ID178 BMS undervoltage alarm" - key: 4 - value: 'ID179 BMS high temperature alarm' + value: "ID179 BMS high temperature alarm" - key: 8 - value: 'ID180 BMS low temperature alarm' + value: "ID180 BMS low temperature alarm" - key: 16 - value: 'ID181 BMS charge/discharge overload alarm' + value: "ID181 BMS charge/discharge overload alarm" - key: 32 - value: 'ID182 BMS short circuit alarm' + value: "ID182 BMS short circuit alarm" - key: 64 - value: 'ID183 BMS version inconsistency' + value: "ID183 BMS version inconsistency" - key: 128 - value: 'ID184 BMS CAN version inconsistency' + value: "ID184 BMS CAN version inconsistency" - key: 256 - value: 'ID185 BMS CAN version is too low' + value: "ID185 BMS CAN version is too low" - key: 512 - value: 'ID186 ' + value: "ID186 " - key: 1024 - value: 'ID187 ' + value: "ID187 " - key: 2048 - value: 'ID188 ' + value: "ID188 " - key: 4096 - value: 'ID189 Arc device communication failure' + value: "ID189 Arc device communication failure" - key: 8192 - value: 'ID190 DC arc alarm fault' + value: "ID190 DC arc alarm fault" - key: 16384 - value: 'ID191 PID repair failed' + value: "ID191 PID repair failed" - key: 32768 - value: 'ID192 PLC module heartbeat loss' + value: "ID192 PLC module heartbeat loss" diff --git a/custom_components/solarman/inverter_definitions/sofar_hyd3k-6k-es.yaml b/custom_components/solarman/inverter_definitions/sofar_hyd3k-6k-es.yaml index 150a1e9..09541e3 100644 --- a/custom_components/solarman/inverter_definitions/sofar_hyd3k-6k-es.yaml +++ b/custom_components/solarman/inverter_definitions/sofar_hyd3k-6k-es.yaml @@ -1,1153 +1,1152 @@ -# Configuration file for Sofar HYD3000/4000/5000/6000-ES -# inverter family. +# +# Configuration file for Sofar HYD3000/4000/5000/6000-ES inverter family. +# + +default: + update_interval: 5 + digits: 6 requests: - start: 0x0200 - end: 0x0255 + end: 0x0255 mb_functioncode: 0x03 - start: 0x10B0 end: 0x10BC mb_functioncode: 0x04 - parameters: - - group: solar - items: - - name: "PV Instant Generated PW" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.01 - rule: 1 - registers: [0x0215] - icon: 'mdi:solar-power' - - - - name: "PV1 Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.01 - rule: 1 - registers: [0x0252] - icon: 'mdi:solar-power' - - - name: "PV2 Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.01 - rule: 1 - registers: [0x0255] - icon: 'mdi:solar-power' - - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0250] - icon: 'mdi:solar-power' - - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0253] - icon: 'mdi:solar-power' - - - name: "PV1 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0251] - icon: 'mdi:solar-power' - - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0254] - icon: 'mdi:solar-power' - - - name: "Daily Production" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.01 - rule: 1 - registers: [0x0218] - icon: 'mdi:solar-power' - - - name: "Total Production" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 1 - rule: 3 - registers: [0x021D,0x021C] - icon: 'mdi:solar-power' - - - name: "Total generation time" - class: "" - state_class: "measurement" - uom: "h" - scale: 1 - rule: 3 - registers: [0x0245,0x0244] - icon: 'mdi:clock-outline' - - - name: "Today generation time" - class: "" - state_class: "total_increasing" - uom: "min" - scale: 1 - rule: 1 - registers: [0x0243] - icon: 'mdi:clock-outline' - - - name: "Today Grid Return" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.01 - rule: 1 - registers: [0x0219] - icon: 'mdi:transmission-tower-export' - - - name: "Today Grid Consumption" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.01 - rule: 1 - registers: [0x021A] - icon: 'mdi:transmission-tower-import' - - - name: "Today Power Consumption" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.01 - rule: 1 - registers: [0x021B] - icon: 'mdi:lightning-bolt' - - - name: "Total Grid Return" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 1 - rule: 3 - registers: [0x021F,0x021E] - icon: 'mdi:transmission-tower-export' - - - name: "Total Grid Consumption" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 1 - rule: 3 - registers: [0x0221,0x0220] - icon: 'mdi:transmission-tower-import' - - - name: "Total Power Consumption" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 1 - rule: 3 - registers: [0x0223,0x0222] - icon: 'mdi:lightning-bolt' - - - group: Output - items: - - - name: "Power Consumption" - class: "" - state_class: "" - uom: "kW" - scale: 0.01 - rule: 1 - registers: [0x0213] - icon: '' - -# - name: "Output active power" -# class: "power" -# state_class: "measurement" -# uom: "W" -# scale: 10 -# rule: 1 -# registers: [0x000C] -# icon: 'mdi:home-lightning-bolt' - -# - name: "Output reactive power" -# class: "" -# state_class: "measurement" -# uom: "kVar" -# scale: 0.01 -# rule: 1 -# registers: [0x000D] -# icon: 'mdi:home-lightning-bolt' - - - name: "Grid frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x020C] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0206] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 2 - registers: [0x0207] - icon: 'mdi:home-lightning-bolt' - - - - group: batteries - items: - - name: "Battery Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x020E] - icon: 'mdi:battery-charging' - - - name: "Battery Charge / Discharge current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 2 - registers: [0x020F] - icon: 'mdi:battery-charging-10' - - - name: "Battery Percentage" - class: "battery" - state_class: "measurement" - uom: "%" - scale: 1 - rule: 1 - registers: [0x0210] - icon: 'mdi:battery' - - - name: "Battery Temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 1 - #se non funziona cambia questo in 2 - rule: 1 - registers: [0x0211] - icon: 'mdi:battery-heart-outline' - - - name: "Battery Daily Charge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.01 - rule: 1 - registers: [0x0224] - icon: 'mdi:battery-clock' - - - name: "Battery Total Energy Charged" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 1 - rule: 1 - registers: [0x0227] - icon: 'mdi:battery-clock' - - - name: "Battery Total Energy Dischaged" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 1 - rule: 1 - registers: [0x0229] - icon: 'mdi:battery-clock-outline' - - - name: "Battery Cicles" - class: "" - state_class: "" - uom: "Charges" - scale: 1 - rule: 1 - registers: [0x022C] - icon: 'mdi:battery-check-outline' - - - name: "Battery Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.01 - rule: 2 - registers: [0x0237] - icon: 'mdi:battery-charging-high' - - - name: "Battery Type" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x10B0] - icon: 'mdi:battery' - - - name: "Battery Capacity" - class: "" - state_class: "" - uom: "Ah" - scale: 1 - rule: 1 - registers: [0x10B1] - icon: 'mdi:battery' - - - name: "Battery Daily Discharge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.01 - rule: 1 - registers: [0x0225] - icon: 'mdi:battery' - - - name: "Battery Total Charge" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 1 - rule: 3 - registers: [0x0227,0x0226] - icon: 'mdi:battery' - - - name: "Battery Total Discharge" - class: "energy" - state_class: "total" - uom: "kWh" - scale: 1 - rule: 3 - registers: [0x0229,0x0228] - icon: 'mdi:battery' - - - name: "Max Charge Voltage" - class: "" - state_class: "" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x10B3] - icon: 'mdi:battery' - - - name: "Max Charge Current" - class: "" - state_class: "" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x10B4] - icon: 'mdi:battery' - - - name: "Over Voltage Protection" - class: "" - state_class: "" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x10B5] - icon: 'mdi:battery' - - - name: "Min Discharge Voltage" - class: "" - state_class: "" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x10B6] - icon: 'mdi:battery' - - - name: "Max Discharge Current" - class: "" - state_class: "" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x10B7] - icon: 'mdi:battery' - - - name: "Undervoltage Protection" - class: "" - state_class: "" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x10B8] - icon: 'mdi:battery' - - - name: "Discharge Depth" - class: "" - state_class: "" - uom: "%" - scale: 1 - rule: 1 - registers: [0x10B9] - icon: 'mdi:battery' - - - name: "Periods Of Discharge Time" - class: "" - state_class: "" - uom: "h" - scale: 1 - rule: 1 - registers: [0x10BA] - icon: 'mdi:battery' - - - name: "Empty Battery Voltage" - class: "" - state_class: "" - uom: "V" - scale: 0.01 - rule: 1 - registers: [0x10BB] - icon: 'mdi:battery' - - - name: "Full Battery Voltage" - class: "" - state_class: "" - uom: "V" - scale: 0.01 - rule: 1 - registers: [0x10BC] - icon: 'mdi:battery' - - - group: Inverter - items: - - name: "Inverter status" - class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0200] - isstr: true - lookup: - - key: 0 - value: "Stand-by" - - key: 1 - value: "Self-Checking" - - key: 2 - value: "Normal" - - key: 3 - value: "Discharging Check State" - - key: 4 - value: "Discharging State" - - key: 5 - value: "EPS State" - - key: 6 - value: "Fault State" - - key: 7 - value: "Permanent State" - icon: 'mdi:state-machine' - - - name: "Inverter module temperature" - class: "temperature" - uom: "°C" - scale: 1 - rule: 2 - registers: [0x0239] - icon: 'mdi:thermometer' - - - name: "Inverter inner temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 1 - rule: 2 - registers: [0x0238] - icon: 'mdi:thermometer' - - - name: "Inverter bus voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 2 - registers: [0x022D] - icon: 'mdi:home-lightning-bolt' - -# - name: "PV1 voltage sample by slave CPU" -# class: "voltage" -# state_class: "measurement" -# uom: "V" -# scale: 0.1 -# rule: 1 -# registers: [0x001E] -# icon: 'mdi:home-lightning-bolt' - -# - name: "PV1 current sample by slave CPU" -# class: "current" -# state_class: "measurement" -# uom: "A" -# scale: 0.1 -# rule: 1 -# registers: [0x001F] -# icon: 'mdi:home-lightning-bolt' - - - name: "Countdown time" - class: "" - state_class: "measurement" - uom: "s" - scale: 1 - rule: 1 - registers: [0x022A] - icon: '' - -# - name: "Input mode" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 1 -# registers: [0x0022] -# icon: '' - - - name: "Communication Board inner message" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0242] - icon: '' - - - name: "Insulation of PV1+ to ground" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [0x0246] - icon: '' - - - name: "Insulation of PV2+ to ground" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [0x0247] - icon: '' - - - name: "Insulation of PV- to ground" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [0x0248] - icon: '' - - - name: "Country" - class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x023A] - isstr: true - lookup: - - key: 0 - value: "Germany" - - key: 1 - value: "CEI0-21 Internal" - - key: 2 - value: "Australia" - - key: 3 - value: "Spain RD1699" - - key: 4 - value: "Turkey" - - key: 5 - value: "Denmark" - - key: 6 - value: "Greece" - - key: 7 - value: "Netherland" - - key: 8 - value: "Belgium" - - key: 9 - value: "UK-G59" - - key: 10 - value: "China" - - key: 11 - value: "France" - - key: 12 - value: "Poland" - - key: 13 - value: "Germany BDEW" - - key: 14 - value: "Germany VDE0126" - - key: 15 - value: "Italy CEI0-16" - - key: 16 - value: "UK-G83" - - key: 17 - value: "Greece Islands" - - key: 18 - value: "EU EN50438" - - key: 19 - value: "EU EN61727" - - key: 20 - value: "Korea" - - key: 21 - value: "Sweden" - - key: 22 - value: "Europe General" - - key: 23 - value: "CEI0-21 External" - - key: 24 - value: "Cyprus" - - key: 25 - value: "India" - - key: 26 - value: "Philippines" - - key: 27 - value: "New Zeland" - - key: 28 - value: "Reserve" - - key: 29 - value: "Reserve" - icon: '' - - - group: Alert - items: - - name: "Inverter alert message" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x022B] - isstr: true - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID01 The power grid voltage is too high" - - key: 2 - value: "ID02 The power grid voltage is too low" - - key: 3 - value: "ID03 The power grid frequency is too high" - - key: 4 - value: "ID04 The power grid frequency is too low" - - key: 5 - value: "ID05 The battery voltage is too high" - - key: 7 - value: "ID07 GridLVRT fault" - - key: 8 - value: "ID08 The PV voltage is too high" - - key: 9 - value: "ID09 LLCBus voltage is too high and has triggered hardware protection" - - key: 10 - value: "ID10 Boost voltage is too high and has triggered hardware protection" - - key: 11 - value: "ID11 BuckBoost current is too high and has triggered hardware protection" - - key: 12 - value: "ID12 The battery current is too high and has triggered hardware protection" - - key: 13 - value: "ID13 The GFCI sampling value between the master DSP and slave DSP is not consistent" - - key: 14 - value: "ID14 The PV current is too high and has triggered hardware protection" - - key: 15 - value: "ID15 The grid current is too high and has triggered hardware protection" - - key: 16 - value: "ID16 Input current is not balanced" - - key: 17 - value: "ID17 Grid current sampling error" - - key: 18 - value: "ID18 DCI sampling error" - - key: 19 - value: "ID19 Grid voltage sampling error" - - key: 20 - value: "ID20 GFCI sampling error" - - key: 21 - value: "ID21 Master chip fault" - - key: 22 - value: "ID22 Auxiliary voltage error" - - key: 25 - value: "ID25 LLCBus voltage is too high" - - key: 26 - value: "ID26 Bus voltage is too high and has triggered software protection" - - key: 27 - value: "ID27 Battery current is too high" - - key: 28 - value: "ID28 The DCI is too high" - - key: 29 - value: "ID29 The grid current is too high" - - key: 30 - value: "ID30 Bunk current is too high" - - key: 31 - value: "ID31 The output current is too high" - - key: 32 - value: "ID32 The input current is too high" - - key: 33 - value: "ID33 Incorrect input mode" - - key: 48 - value: "ID48 The GFCI sampling value between the master DSP and slave DSP is not consistent" - - key: 49 - value: "ID49 The grid voltage sampling value between the master DSP and slave DSP is no consistent" - - key: 50 - value: "ID50 The grid frequency sampling value between the master DSP and slave DSP is no consistent" - - key: 51 - value: "ID51 The DCI sampling value between the master DSP and slave DSP is no consistent" - - key: 52 - value: "ID52 HYD-ES inverter can't communicate with Lithium battery BMS correctly" - - key: 53 - value: "ID53 SPI communication fault" - - key: 54 - value: "ID54 SCI communication fault" - - key: 55 - value: "ID55 Relays fault" - - key: 56 - value: "ID56 Insulation resistance is too low" - - key: 57 - value: "ID57 Battery temperature is too high" - - key: 58 - value: "ID58 Heat sink temperature is too high" - - key: 59 - value: "ID59 Environment temperature is too high" - - key: 60 - value: "ID60 PE connectFault" - - key: 65 - value: "ID65 The grid current is too high and has caused unrecoverable hardware fault" - - key: 66 - value: "ID66 The bus voltage is too high and has caused unrecoverable fault" - - key: 67 - value: "ID67 Unrecoverable fault of battery overcurrent in EPS mode" - - key: 68 - value: "ID68 The input current is unbalanced and has triggered an unrecoverable fault" - - key: 70 - value: "ID70 The grid current is too high and has triggered an unrecoverable fault" - - key: 73 - value: "ID73 The input current is too high and has triggered an unrecoverable fault" - - key: 74 - value: "ID74 Incorrect input mode" - - key: 75 - value: "ID75 Unrecoverable EEPROM write" - - key: 76 - value: "ID76 Unrecoverable EEPROM read" - - key: 77 - value: "ID77 Relay has triggered permanent fault" - - key: 81 - value: "ID81 Internal temperature is too high" - - key: 82 - value: "ID82 AC frequency is too high" - - key: 83 - value: "ID83 Remote power derate" - - key: 84 - value: "ID84 Switch OFF HYD series inverter remotely" - - key: 85 - value: "ID85 SOC <= 1 - DOD or Low battery voltage" - - key: 86 - value: "ID86 Battery voltage is too low and caused HYD series inverter to switch OFF" - - key: 94 - value: "ID94 Software version is not consistent" - - key: 95 - value: "ID95 The communication board EEPROM is faulty" - - key: 96 - value: "ID96 RTC clock chip fault" - - key: 98 - value: "ID98 SD card fault" - - key: 100 - value: "ID100 Battery overcurrent discharging protection" - - key: 101 - value: "ID101 Discharging short circuit protection" - - key: 102 - value: "ID102 Battery high voltage protection" - - key: 103 - value: "ID103 Battery low voltage protection" - - key: 104 - value: "ID104 Battery high temperature protection while discharging" - - key: 105 - value: "ID105 Battery high temperature protection while charging" - - key: 106 - value: "ID106 Battery low temperature protection while discharging" - - key: 107 - value: "ID107 Battery low temperature protection while charging" - icon: 'mdi:alert' - - - name: "Fault 1" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0201] - isstr: true - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID01 Grid Over Voltage Protection" - - key: 2 - value: "ID02 Grid Under Voltage Protection" - - key: 4 - value: "ID03 Grid Over Frequency Protection" - - key: 8 - value: "ID04 Grid Under Frequency Protection" - - key: 16 - value: "ID05 Battery Over Voltage" - - key: 32 - value: "ID06" - - key: 64 - value: "ID07" - - key: 128 - value: "ID08" - - key: 256 - value: "ID09 LLCBus Over Voltage Hardware" - - key: 512 - value: "ID10 Bus Over Voltage Hardware" - - key: 1024 - value: "ID11 BuckBoost over Current Hardware" - - key: 2048 - value: "ID12 Battery over Current Hardware" - - key: 4096 - value: "ID13" - - key: 8192 - value: "ID14" - - key: 16384 - value: "ID15 Output Current Hardware" - - key: 32768 - value: "ID16" - icon: 'mdi:wrench' - - - - name: "Fault 2" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0202] - isstr: true - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID17 Grid current sampling error" - - key: 2 - value: "ID18 DCI sampling error" - - key: 4 - value: "ID19 Grid voltage sampling error" - - key: 8 - value: "ID20" - - key: 16 - value: "ID21 Main chip fault" - - key: 32 - value: "ID22 Hardware auxiliary power fault" - - key: 64 - value: "ID23" - - key: 128 - value: "ID24" - - key: 256 - value: "ID25 LLCBus Over Current protection" - - key: 512 - value: "ID26 Bus over voltage protection" - - key: 1024 - value: "ID27 Battery Over Current protection" - - key: 2048 - value: "ID28 Dci Over Current Protection" - - key: 4096 - value: "ID29 Output over current software" - - key: 8192 - value: "ID30 Buck Over Current" - - key: 16384 - value: "ID31 Output over current protection" - - key: 32768 - value: "ID32 The input current is too high" - icon: 'mdi:wrench' - - - name: "Fault 3" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0203] - isstr: true - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID33 Reserved" - - key: 2 - value: "ID34 Reserved" - - key: 4 - value: "ID35 Reserved" - - key: 8 - value: "ID36 Reserved" - - key: 16 - value: "ID37 Reserved" - - key: 32 - value: "ID38 Reserved" - - key: 64 - value: "ID39 Reserved" - - key: 128 - value: "ID40 Reserved" - - key: 256 - value: "ID41 Reserved" - - key: 512 - value: "ID42 Reserved" - - key: 1024 - value: "ID43 Reserved" - - key: 2048 - value: "ID44 Reserved" - - key: 4096 - value: "ID45 Reserved" - - key: 8192 - value: "ID46 Reserved" - - key: 16384 - value: "ID47 Reserved" - - key: 32768 - value: "ID48 Reserved" - icon: 'mdi:wrench' - - - name: "Fault 4" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0204] - isstr: true - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID49 Grid voltage sampling value between master and slave DSP vary widely" - - key: 2 - value: "ID50 Grid frequency sampling value between master and slave DSP vary widely" - - key: 4 - value: "ID51 DCI sampling value between master and slave DSP vary widely" - - key: 8 - value: "ID52 GFCI sampling value between master and slave DSP vary widely" - - key: 16 - value: "ID53 Communication failure between master and slave DSP failure" - - key: 32 - value: "ID53 Communication failure between slave and communication board" - - key: 64 - value: "ID55 Relay fault" - - key: 128 - value: "ID56" - - key: 256 - value: "ID57 Inverter temp is too high" - - key: 512 - value: "ID58 Boost temp is too high" - - key: 1024 - value: "ID59 Environment temp is too high" - - key: 2048 - value: "ID60" - - key: 4096 - value: "ID61 Reserved" - - key: 8192 - value: "ID62 Reserved" - - key: 16384 - value: "ID63 Reserved" - - key: 32768 - value: "ID64 Reserved" - icon: 'mdi:wrench' - - - name: "Fault 5" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0205] - isstr: true - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID65 Grid current is too high and causes unrecoverable fault" - - key: 2 - value: "ID66 Bus voltage is too high and causes unrecoverable fault" - - key: 4 - value: "ID67 EPS Mode Battery Over current,and has cause unrecoverable fault" - - key: 8 - value: "ID68" - - key: 16 - value: "ID69" - - key: 32 - value: "ID70 The Output current is too high,and has cause unrecoverable fault" - - key: 64 - value: "ID71" - - key: 128 - value: "ID72 Reserved" - - key: 256 - value: "ID73 Reserved" - - key: 512 - value: "ID74" - - key: 1024 - value: "ID75 Error writing from EEPROM" - - key: 2048 - value: "ID76 Error reading to EEPROM" - - key: 4096 - value: "ID77 Relay fauilure causes unrecoverable fault" - - key: 8192 - value: "ID78 Reserved" - - key: 16384 - value: "ID79 Reserved" - - key: 32768 - value: "ID80 Reserved" - icon: 'mdi:wrench' - - - group: Other energy - items: - - name: "Buck Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x022F] - icon: 'mdi:lightning-bolt' - - - name: "Grid R Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0230] - icon: 'mdi:lightning-bolt' - - - name: "Grid R Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0231] - icon: 'mdi:lightning-bolt' - - - name: "Generation Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0236] - icon: 'mdi:lightning-bolt' - - - - name: "Charge / Discharge Power" - class: "" - state_class: "" - uom: "kW" - scale: 0.01 - rule: 2 - registers: [0x020D] - icon: '' - - - name: "Feed in / out power" - class: "" - state_class: "" - uom: "kW" - scale: 0.01 - rule: 2 - registers: [0x0212] - icon: '' - - - name: "Input/Output Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.01 - rule: 2 - registers: [0x0214] - icon: 'mdi:lightning-bolt' - - - name: "Energy Management Model" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x10B2] - icon: '' - - - name: "DCI Current" - class: "current" - state_class: "measurement" - uom: "mA" - scale: 1 - rule: 1 - registers: [0x023B] - icon: 'mdi:lightning-bolt' - - - name: "DCI Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x023C] - icon: 'mdi:lightning-bolt' - - - name: "Grid S Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0232] - icon: 'mdi:lightning-bolt' - - - name: "Grid S Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0233] - icon: 'mdi:lightning-bolt' - - - name: "Grid T voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0234] - icon: 'mdi:lightning-bolt' - - - name: "Grid T current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0235] - icon: 'mdi:lightning-bolt' + - group: solar + items: + - name: "PV Instant Generated PW" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.01 + rule: 1 + registers: [0x0215] + icon: "mdi:solar-power" + + - name: "PV1 Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.01 + rule: 1 + registers: [0x0252] + icon: "mdi:solar-power" + + - name: "PV2 Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.01 + rule: 1 + registers: [0x0255] + icon: "mdi:solar-power" + + - name: "PV1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0250] + icon: "mdi:solar-power" + + - name: "PV2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0253] + icon: "mdi:solar-power" + + - name: "PV1 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0251] + icon: "mdi:solar-power" + + - name: "PV2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0254] + icon: "mdi:solar-power" + + - name: "Daily Production" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.01 + rule: 1 + registers: [0x0218] + icon: "mdi:solar-power" + + - name: "Total Production" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 1 + rule: 3 + registers: [0x021D, 0x021C] + icon: "mdi:solar-power" + + - name: "Total generation time" + class: "" + state_class: "measurement" + uom: "h" + scale: 1 + rule: 3 + registers: [0x0245, 0x0244] + icon: "mdi:clock-outline" + + - name: "Today generation time" + class: "" + state_class: "total_increasing" + uom: "min" + scale: 1 + rule: 1 + registers: [0x0243] + icon: "mdi:clock-outline" + + - name: "Today Grid Return" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.01 + rule: 1 + registers: [0x0219] + icon: "mdi:transmission-tower-export" + + - name: "Today Grid Consumption" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.01 + rule: 1 + registers: [0x021A] + icon: "mdi:transmission-tower-import" + + - name: "Today Power Consumption" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.01 + rule: 1 + registers: [0x021B] + icon: "mdi:lightning-bolt" + + - name: "Total Grid Return" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 1 + rule: 3 + registers: [0x021F, 0x021E] + icon: "mdi:transmission-tower-export" + + - name: "Total Grid Consumption" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 1 + rule: 3 + registers: [0x0221, 0x0220] + icon: "mdi:transmission-tower-import" + + - name: "Total Power Consumption" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 1 + rule: 3 + registers: [0x0223, 0x0222] + icon: "mdi:lightning-bolt" + + - group: Output + items: + - name: "Power Consumption" + class: "" + state_class: "" + uom: "kW" + scale: 0.01 + rule: 1 + registers: [0x0213] + icon: "" + + # - name: "Output active power" + # class: "power" + # state_class: "measurement" + # uom: "W" + # scale: 10 + # rule: 1 + # registers: [0x000C] + # icon: 'mdi:home-lightning-bolt' + + # - name: "Output reactive power" + # class: "" + # state_class: "measurement" + # uom: "kVar" + # scale: 0.01 + # rule: 1 + # registers: [0x000D] + # icon: 'mdi:home-lightning-bolt' + + - name: "Grid frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x020C] + icon: "mdi:home-lightning-bolt" + + - name: "Grid Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0206] + icon: "mdi:home-lightning-bolt" + + - name: "Grid Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 2 + registers: [0x0207] + icon: "mdi:home-lightning-bolt" + + - group: batteries + items: + - name: "Battery Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x020E] + icon: "mdi:battery-charging" + + - name: "Battery Charge / Discharge current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 2 + registers: [0x020F] + icon: "mdi:battery-charging-10" + + - name: "Battery Percentage" + class: "battery" + state_class: "measurement" + uom: "%" + scale: 1 + rule: 1 + registers: [0x0210] + icon: "mdi:battery" + + - name: "Battery Temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 1 + #se non funziona cambia questo in 2 + rule: 1 + registers: [0x0211] + icon: "mdi:battery-heart-outline" + + - name: "Battery Daily Charge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.01 + rule: 1 + registers: [0x0224] + icon: "mdi:battery-clock" + + - name: "Battery Total Energy Charged" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 1 + rule: 1 + registers: [0x0227] + icon: "mdi:battery-clock" + + - name: "Battery Total Energy Dischaged" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 1 + rule: 1 + registers: [0x0229] + icon: "mdi:battery-clock-outline" + + - name: "Battery Cicles" + class: "" + state_class: "" + uom: "Charges" + scale: 1 + rule: 1 + registers: [0x022C] + icon: "mdi:battery-check-outline" + + - name: "Battery Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.01 + rule: 2 + registers: [0x0237] + icon: "mdi:battery-charging-high" + + - name: "Battery Type" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x10B0] + icon: "mdi:battery" + + - name: "Battery Capacity" + class: "" + state_class: "" + uom: "Ah" + scale: 1 + rule: 1 + registers: [0x10B1] + icon: "mdi:battery" + + - name: "Battery Daily Discharge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.01 + rule: 1 + registers: [0x0225] + icon: "mdi:battery" + + - name: "Battery Total Charge" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 1 + rule: 3 + registers: [0x0227, 0x0226] + icon: "mdi:battery" + + - name: "Battery Total Discharge" + class: "energy" + state_class: "total" + uom: "kWh" + scale: 1 + rule: 3 + registers: [0x0229, 0x0228] + icon: "mdi:battery" + + - name: "Max Charge Voltage" + class: "" + state_class: "" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x10B3] + icon: "mdi:battery" + + - name: "Max Charge Current" + class: "" + state_class: "" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x10B4] + icon: "mdi:battery" + + - name: "Over Voltage Protection" + class: "" + state_class: "" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x10B5] + icon: "mdi:battery" + + - name: "Min Discharge Voltage" + class: "" + state_class: "" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x10B6] + icon: "mdi:battery" + + - name: "Max Discharge Current" + class: "" + state_class: "" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x10B7] + icon: "mdi:battery" + + - name: "Undervoltage Protection" + class: "" + state_class: "" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x10B8] + icon: "mdi:battery" + + - name: "Discharge Depth" + class: "" + state_class: "" + uom: "%" + scale: 1 + rule: 1 + registers: [0x10B9] + icon: "mdi:battery" + + - name: "Periods Of Discharge Time" + class: "" + state_class: "" + uom: "h" + scale: 1 + rule: 1 + registers: [0x10BA] + icon: "mdi:battery" + + - name: "Empty Battery Voltage" + class: "" + state_class: "" + uom: "V" + scale: 0.01 + rule: 1 + registers: [0x10BB] + icon: "mdi:battery" + + - name: "Full Battery Voltage" + class: "" + state_class: "" + uom: "V" + scale: 0.01 + rule: 1 + registers: [0x10BC] + icon: "mdi:battery" + + - group: Inverter + items: + - name: "Inverter status" + class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0200] + isstr: true + lookup: + - key: 0 + value: "Stand-by" + - key: 1 + value: "Self-Checking" + - key: 2 + value: "Normal" + - key: 3 + value: "Discharging Check State" + - key: 4 + value: "Discharging State" + - key: 5 + value: "EPS State" + - key: 6 + value: "Fault State" + - key: 7 + value: "Permanent State" + icon: "mdi:state-machine" + + - name: "Inverter module temperature" + class: "temperature" + uom: "°C" + scale: 1 + rule: 2 + registers: [0x0239] + icon: "mdi:thermometer" + + - name: "Inverter inner temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 1 + rule: 2 + registers: [0x0238] + icon: "mdi:thermometer" + + - name: "Inverter bus voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 2 + registers: [0x022D] + icon: "mdi:home-lightning-bolt" + + # - name: "PV1 voltage sample by slave CPU" + # class: "voltage" + # state_class: "measurement" + # uom: "V" + # scale: 0.1 + # rule: 1 + # registers: [0x001E] + # icon: 'mdi:home-lightning-bolt' + + # - name: "PV1 current sample by slave CPU" + # class: "current" + # state_class: "measurement" + # uom: "A" + # scale: 0.1 + # rule: 1 + # registers: [0x001F] + # icon: 'mdi:home-lightning-bolt' + + - name: "Countdown time" + class: "" + state_class: "measurement" + uom: "s" + scale: 1 + rule: 1 + registers: [0x022A] + icon: "" + + # - name: "Input mode" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 1 + # registers: [0x0022] + # icon: '' + + - name: "Communication Board inner message" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0242] + icon: "" + + - name: "Insulation of PV1+ to ground" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [0x0246] + icon: "" + + - name: "Insulation of PV2+ to ground" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [0x0247] + icon: "" + + - name: "Insulation of PV- to ground" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [0x0248] + icon: "" + + - name: "Country" + class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x023A] + isstr: true + lookup: + - key: 0 + value: "Germany" + - key: 1 + value: "CEI0-21 Internal" + - key: 2 + value: "Australia" + - key: 3 + value: "Spain RD1699" + - key: 4 + value: "Turkey" + - key: 5 + value: "Denmark" + - key: 6 + value: "Greece" + - key: 7 + value: "Netherland" + - key: 8 + value: "Belgium" + - key: 9 + value: "UK-G59" + - key: 10 + value: "China" + - key: 11 + value: "France" + - key: 12 + value: "Poland" + - key: 13 + value: "Germany BDEW" + - key: 14 + value: "Germany VDE0126" + - key: 15 + value: "Italy CEI0-16" + - key: 16 + value: "UK-G83" + - key: 17 + value: "Greece Islands" + - key: 18 + value: "EU EN50438" + - key: 19 + value: "EU EN61727" + - key: 20 + value: "Korea" + - key: 21 + value: "Sweden" + - key: 22 + value: "Europe General" + - key: 23 + value: "CEI0-21 External" + - key: 24 + value: "Cyprus" + - key: 25 + value: "India" + - key: 26 + value: "Philippines" + - key: 27 + value: "New Zeland" + - key: 28 + value: "Reserve" + - key: 29 + value: "Reserve" + icon: "" + + - group: Alert + items: + - name: "Inverter alert message" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x022B] + isstr: true + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID01 The power grid voltage is too high" + - key: 2 + value: "ID02 The power grid voltage is too low" + - key: 3 + value: "ID03 The power grid frequency is too high" + - key: 4 + value: "ID04 The power grid frequency is too low" + - key: 5 + value: "ID05 The battery voltage is too high" + - key: 7 + value: "ID07 GridLVRT fault" + - key: 8 + value: "ID08 The PV voltage is too high" + - key: 9 + value: "ID09 LLCBus voltage is too high and has triggered hardware protection" + - key: 10 + value: "ID10 Boost voltage is too high and has triggered hardware protection" + - key: 11 + value: "ID11 BuckBoost current is too high and has triggered hardware protection" + - key: 12 + value: "ID12 The battery current is too high and has triggered hardware protection" + - key: 13 + value: "ID13 The GFCI sampling value between the master DSP and slave DSP is not consistent" + - key: 14 + value: "ID14 The PV current is too high and has triggered hardware protection" + - key: 15 + value: "ID15 The grid current is too high and has triggered hardware protection" + - key: 16 + value: "ID16 Input current is not balanced" + - key: 17 + value: "ID17 Grid current sampling error" + - key: 18 + value: "ID18 DCI sampling error" + - key: 19 + value: "ID19 Grid voltage sampling error" + - key: 20 + value: "ID20 GFCI sampling error" + - key: 21 + value: "ID21 Master chip fault" + - key: 22 + value: "ID22 Auxiliary voltage error" + - key: 25 + value: "ID25 LLCBus voltage is too high" + - key: 26 + value: "ID26 Bus voltage is too high and has triggered software protection" + - key: 27 + value: "ID27 Battery current is too high" + - key: 28 + value: "ID28 The DCI is too high" + - key: 29 + value: "ID29 The grid current is too high" + - key: 30 + value: "ID30 Bunk current is too high" + - key: 31 + value: "ID31 The output current is too high" + - key: 32 + value: "ID32 The input current is too high" + - key: 33 + value: "ID33 Incorrect input mode" + - key: 48 + value: "ID48 The GFCI sampling value between the master DSP and slave DSP is not consistent" + - key: 49 + value: "ID49 The grid voltage sampling value between the master DSP and slave DSP is no consistent" + - key: 50 + value: "ID50 The grid frequency sampling value between the master DSP and slave DSP is no consistent" + - key: 51 + value: "ID51 The DCI sampling value between the master DSP and slave DSP is no consistent" + - key: 52 + value: "ID52 HYD-ES inverter can't communicate with Lithium battery BMS correctly" + - key: 53 + value: "ID53 SPI communication fault" + - key: 54 + value: "ID54 SCI communication fault" + - key: 55 + value: "ID55 Relays fault" + - key: 56 + value: "ID56 Insulation resistance is too low" + - key: 57 + value: "ID57 Battery temperature is too high" + - key: 58 + value: "ID58 Heat sink temperature is too high" + - key: 59 + value: "ID59 Environment temperature is too high" + - key: 60 + value: "ID60 PE connectFault" + - key: 65 + value: "ID65 The grid current is too high and has caused unrecoverable hardware fault" + - key: 66 + value: "ID66 The bus voltage is too high and has caused unrecoverable fault" + - key: 67 + value: "ID67 Unrecoverable fault of battery overcurrent in EPS mode" + - key: 68 + value: "ID68 The input current is unbalanced and has triggered an unrecoverable fault" + - key: 70 + value: "ID70 The grid current is too high and has triggered an unrecoverable fault" + - key: 73 + value: "ID73 The input current is too high and has triggered an unrecoverable fault" + - key: 74 + value: "ID74 Incorrect input mode" + - key: 75 + value: "ID75 Unrecoverable EEPROM write" + - key: 76 + value: "ID76 Unrecoverable EEPROM read" + - key: 77 + value: "ID77 Relay has triggered permanent fault" + - key: 81 + value: "ID81 Internal temperature is too high" + - key: 82 + value: "ID82 AC frequency is too high" + - key: 83 + value: "ID83 Remote power derate" + - key: 84 + value: "ID84 Switch OFF HYD series inverter remotely" + - key: 85 + value: "ID85 SOC <= 1 - DOD or Low battery voltage" + - key: 86 + value: "ID86 Battery voltage is too low and caused HYD series inverter to switch OFF" + - key: 94 + value: "ID94 Software version is not consistent" + - key: 95 + value: "ID95 The communication board EEPROM is faulty" + - key: 96 + value: "ID96 RTC clock chip fault" + - key: 98 + value: "ID98 SD card fault" + - key: 100 + value: "ID100 Battery overcurrent discharging protection" + - key: 101 + value: "ID101 Discharging short circuit protection" + - key: 102 + value: "ID102 Battery high voltage protection" + - key: 103 + value: "ID103 Battery low voltage protection" + - key: 104 + value: "ID104 Battery high temperature protection while discharging" + - key: 105 + value: "ID105 Battery high temperature protection while charging" + - key: 106 + value: "ID106 Battery low temperature protection while discharging" + - key: 107 + value: "ID107 Battery low temperature protection while charging" + icon: "mdi:alert" + + - name: "Fault 1" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0201] + isstr: true + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID01 Grid Over Voltage Protection" + - key: 2 + value: "ID02 Grid Under Voltage Protection" + - key: 4 + value: "ID03 Grid Over Frequency Protection" + - key: 8 + value: "ID04 Grid Under Frequency Protection" + - key: 16 + value: "ID05 Battery Over Voltage" + - key: 32 + value: "ID06" + - key: 64 + value: "ID07" + - key: 128 + value: "ID08" + - key: 256 + value: "ID09 LLCBus Over Voltage Hardware" + - key: 512 + value: "ID10 Bus Over Voltage Hardware" + - key: 1024 + value: "ID11 BuckBoost over Current Hardware" + - key: 2048 + value: "ID12 Battery over Current Hardware" + - key: 4096 + value: "ID13" + - key: 8192 + value: "ID14" + - key: 16384 + value: "ID15 Output Current Hardware" + - key: 32768 + value: "ID16" + icon: "mdi:wrench" + + - name: "Fault 2" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0202] + isstr: true + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID17 Grid current sampling error" + - key: 2 + value: "ID18 DCI sampling error" + - key: 4 + value: "ID19 Grid voltage sampling error" + - key: 8 + value: "ID20" + - key: 16 + value: "ID21 Main chip fault" + - key: 32 + value: "ID22 Hardware auxiliary power fault" + - key: 64 + value: "ID23" + - key: 128 + value: "ID24" + - key: 256 + value: "ID25 LLCBus Over Current protection" + - key: 512 + value: "ID26 Bus over voltage protection" + - key: 1024 + value: "ID27 Battery Over Current protection" + - key: 2048 + value: "ID28 Dci Over Current Protection" + - key: 4096 + value: "ID29 Output over current software" + - key: 8192 + value: "ID30 Buck Over Current" + - key: 16384 + value: "ID31 Output over current protection" + - key: 32768 + value: "ID32 The input current is too high" + icon: "mdi:wrench" + + - name: "Fault 3" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0203] + isstr: true + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID33 Reserved" + - key: 2 + value: "ID34 Reserved" + - key: 4 + value: "ID35 Reserved" + - key: 8 + value: "ID36 Reserved" + - key: 16 + value: "ID37 Reserved" + - key: 32 + value: "ID38 Reserved" + - key: 64 + value: "ID39 Reserved" + - key: 128 + value: "ID40 Reserved" + - key: 256 + value: "ID41 Reserved" + - key: 512 + value: "ID42 Reserved" + - key: 1024 + value: "ID43 Reserved" + - key: 2048 + value: "ID44 Reserved" + - key: 4096 + value: "ID45 Reserved" + - key: 8192 + value: "ID46 Reserved" + - key: 16384 + value: "ID47 Reserved" + - key: 32768 + value: "ID48 Reserved" + icon: "mdi:wrench" + + - name: "Fault 4" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0204] + isstr: true + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID49 Grid voltage sampling value between master and slave DSP vary widely" + - key: 2 + value: "ID50 Grid frequency sampling value between master and slave DSP vary widely" + - key: 4 + value: "ID51 DCI sampling value between master and slave DSP vary widely" + - key: 8 + value: "ID52 GFCI sampling value between master and slave DSP vary widely" + - key: 16 + value: "ID53 Communication failure between master and slave DSP failure" + - key: 32 + value: "ID53 Communication failure between slave and communication board" + - key: 64 + value: "ID55 Relay fault" + - key: 128 + value: "ID56" + - key: 256 + value: "ID57 Inverter temp is too high" + - key: 512 + value: "ID58 Boost temp is too high" + - key: 1024 + value: "ID59 Environment temp is too high" + - key: 2048 + value: "ID60" + - key: 4096 + value: "ID61 Reserved" + - key: 8192 + value: "ID62 Reserved" + - key: 16384 + value: "ID63 Reserved" + - key: 32768 + value: "ID64 Reserved" + icon: "mdi:wrench" + + - name: "Fault 5" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0205] + isstr: true + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID65 Grid current is too high and causes unrecoverable fault" + - key: 2 + value: "ID66 Bus voltage is too high and causes unrecoverable fault" + - key: 4 + value: "ID67 EPS Mode Battery Over current,and has cause unrecoverable fault" + - key: 8 + value: "ID68" + - key: 16 + value: "ID69" + - key: 32 + value: "ID70 The Output current is too high,and has cause unrecoverable fault" + - key: 64 + value: "ID71" + - key: 128 + value: "ID72 Reserved" + - key: 256 + value: "ID73 Reserved" + - key: 512 + value: "ID74" + - key: 1024 + value: "ID75 Error writing from EEPROM" + - key: 2048 + value: "ID76 Error reading to EEPROM" + - key: 4096 + value: "ID77 Relay fauilure causes unrecoverable fault" + - key: 8192 + value: "ID78 Reserved" + - key: 16384 + value: "ID79 Reserved" + - key: 32768 + value: "ID80 Reserved" + icon: "mdi:wrench" + + - group: Other energy + items: + - name: "Buck Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x022F] + icon: "mdi:lightning-bolt" + + - name: "Grid R Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0230] + icon: "mdi:lightning-bolt" + + - name: "Grid R Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0231] + icon: "mdi:lightning-bolt" + + - name: "Generation Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0236] + icon: "mdi:lightning-bolt" + + - name: "Charge / Discharge Power" + class: "" + state_class: "" + uom: "kW" + scale: 0.01 + rule: 2 + registers: [0x020D] + icon: "" + + - name: "Feed in / out power" + class: "" + state_class: "" + uom: "kW" + scale: 0.01 + rule: 2 + registers: [0x0212] + icon: "" + + - name: "Input/Output Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.01 + rule: 2 + registers: [0x0214] + icon: "mdi:lightning-bolt" + + - name: "Energy Management Model" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x10B2] + icon: "" + + - name: "DCI Current" + class: "current" + state_class: "measurement" + uom: "mA" + scale: 1 + rule: 1 + registers: [0x023B] + icon: "mdi:lightning-bolt" + + - name: "DCI Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x023C] + icon: "mdi:lightning-bolt" + + - name: "Grid S Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0232] + icon: "mdi:lightning-bolt" + + - name: "Grid S Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0233] + icon: "mdi:lightning-bolt" + + - name: "Grid T voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0234] + icon: "mdi:lightning-bolt" + + - name: "Grid T current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0235] + icon: "mdi:lightning-bolt" diff --git a/custom_components/solarman/inverter_definitions/sofar_lsw3.yaml b/custom_components/solarman/inverter_definitions/sofar_lsw3.yaml index 2e47e7b..39f2832 100644 --- a/custom_components/solarman/inverter_definitions/sofar_lsw3.yaml +++ b/custom_components/solarman/inverter_definitions/sofar_lsw3.yaml @@ -1,602 +1,600 @@ -requests: - - start: 0x0000 - end: 0x0027 - mb_functioncode: 0x03 - +default: + update_interval: 5 + digits: 6 parameters: - - group: solar - items: - - name: "PV1 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 10 - rule: 1 - registers: [0x000A] - icon: 'mdi:solar-power' - - - name: "PV2 Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 10 - rule: 1 - registers: [0x000B] - icon: 'mdi:solar-power' - - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0006] - icon: 'mdi:solar-power' - - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0008] - icon: 'mdi:solar-power' - - - name: "PV1 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0007] - icon: 'mdi:solar-power' - - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0009] - icon: 'mdi:solar-power' - - - name: "Daily Production" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.01 - rule: 1 - registers: [0x0019] - icon: 'mdi:solar-power' - - - name: "Total Production" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [0x0016,0x0015] - icon: 'mdi:solar-power' - - - name: "Total generation time" - class: "" - state_class: "measurement" - uom: "h" - scale: 1 - rule: 3 - registers: [0x0018,0x0017] - icon: 'mdi:clock-outline' - - - name: "Today generation time" - class: "" - state_class: "measurement" - uom: "min" - scale: 1 - rule: 1 - registers: [0x001A] - icon: 'mdi:clock-outline' - - - group: Output - items: - - name: "Output active power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 10 - rule: 1 - registers: [0x000C] - icon: 'mdi:home-lightning-bolt' - - - name: "Output reactive power" - class: "" - state_class: "measurement" - uom: "kVar" - scale: 0.01 - rule: 1 - registers: [0x000D] - icon: 'mdi:home-lightning-bolt' - - - name: "Grid frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [0x000E] - icon: 'mdi:home-lightning-bolt' - - - name: "L1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x000F] - icon: 'mdi:home-lightning-bolt' - - - name: "L1 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0010] - icon: 'mdi:home-lightning-bolt' - - - name: "L2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0011] - icon: 'mdi:home-lightning-bolt' - - - name: "L2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0012] - icon: 'mdi:home-lightning-bolt' - - - name: "L3 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x0013] - icon: 'mdi:home-lightning-bolt' - - - name: "L3 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [0x0014] - icon: 'mdi:home-lightning-bolt' - - - group: Inverter - items: - - name: "Inverter status" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [0x0000] - lookup: - - key: 0 - value: "Stand-by" - - key: 1 - value: "Self-checking" - - key: 2 - value: "Normal" - - key: 3 - value: "FAULT" - - key: 4 - value: "Permanent" - icon: 'mdi:wrench' - - - name: "Inverter module temperature" - class: "temperature" - uom: "°C" - scale: 1 - rule: 1 - registers: [0x001B] - icon: 'mdi:thermometer' - - - name: "Inverter inner temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 1 - rule: 1 - registers: [0x001C] - icon: 'mdi:thermometer' - - - name: "Inverter bus voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x001D] - icon: 'mdi:home-lightning-bolt' - - - name: "PV1 voltage sample by slave CPU" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [0x001E] - icon: 'mdi:home-lightning-bolt' - - - name: "PV1 current sample by slave CPU" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [0x001F] - icon: 'mdi:home-lightning-bolt' - - - name: "Countdown time" - class: "" - state_class: "measurement" - uom: "s" - scale: 1 - rule: 1 - registers: [0x0020] - icon: '' - - - name: "Inverter alert message" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0021] - icon: '' - - - name: "Input mode" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0022] - icon: '' - - - name: "Communication Board inner message" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0023] - icon: '' - - - name: "Insulation of PV1+ to ground" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [0x0024] - icon: '' - - - name: "Insulation of PV2+ to ground" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [0x0025] - icon: '' - - - name: "Insulation of PV- to ground" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [0x0026] - icon: '' - - - name: "Country" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0027] - lookup: - - key: 0 - value: "Germany" - - key: 1 - value: "CEI0-21 Internal" - - key: 2 - value: "Australia" - - key: 3 - value: "Spain RD1699" - - key: 4 - value: "Turkey" - - key: 5 - value: "Denmark" - - key: 6 - value: "Greece" - - key: 7 - value: "Netherland" - - key: 8 - value: "Belgium" - - key: 9 - value: "UK-G59" - - key: 10 - value: "China" - - key: 11 - value: "France" - - key: 12 - value: "Poland" - - key: 13 - value: "Germany BDEW" - - key: 14 - value: "Germany VDE0126" - - key: 15 - value: "Italy CEI0-16" - - key: 16 - value: "UK-G83" - - key: 17 - value: "Greece Islands" - - key: 18 - value: "EU EN50438" - - key: 19 - value: "EU EN61727" - - key: 20 - value: "Korea" - - key: 21 - value: "Sweden" - - key: 22 - value: "Europe General" - - key: 23 - value: "CEI0-21 External" - - key: 24 - value: "Cyprus" - - key: 25 - value: "India" - - key: 26 - value: "Philippines" - - key: 27 - value: "New Zeland" - - key: 28 - value: "Reserve" - - key: 29 - value: "Reserve" - icon: '' - - - group: Alert - items: - - name: "Fault 1" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0001] - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID01 Grid Over Voltage Protection" - - key: 2 - value: "ID02 Grid Under Voltage Protection" - - key: 4 - value: "ID03 Grid Over Frequency Protection" - - key: 8 - value: "ID04 Grid Under Frequency Protection" - - key: 16 - value: "ID05 PV Under Voltage Protection" - - key: 32 - value: "ID06 Grid Low Voltage Ride through" - - key: 64 - value: "ID07" - - key: 128 - value: "ID08" - - key: 256 - value: "ID09 PV Over Voltage Protection" - - key: 512 - value: "ID10 PV Input Current Unbalanced" - - key: 1024 - value: "ID11 PV Input Mode wrong configuration" - - key: 2048 - value: "ID12 Ground-Fault circuit interrupters fault" - - key: 4096 - value: "ID13 Phase sequence fault" - - key: 8192 - value: "ID14 Hardware boost over current protection" - - key: 16384 - value: "ID15 Hardware AC over current protection" - - key: 32768 - value: "ID16 Grid current is too high" - icon: 'mdi:wrench' - - - name: "Fault 2" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0002] - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID17 Grid current sampling error" - - key: 2 - value: "ID18 DCI sampling error" - - key: 4 - value: "ID19 Grid voltage sampling error" - - key: 8 - value: "ID20 GFCI device sampling error" - - key: 16 - value: "ID21 Main chip fault" - - key: 32 - value: "ID22 Hardware auxiliary power fault" - - key: 64 - value: "ID23 Bus voltage zero fault" - - key: 128 - value: "ID24 Output current not balanced" - - key: 256 - value: "ID25 Bus under voltage protection" - - key: 512 - value: "ID26 Bus over voltage protection" - - key: 1024 - value: "ID27 Bus voltage unbalanced" - - key: 2048 - value: "ID28 DCI is too high" - - key: 4096 - value: "ID29 Grid current is too high" - - key: 8192 - value: "ID30 Input current is too high" - - key: 16384 - value: "ID31" - - key: 32768 - value: "ID32" - icon: 'mdi:wrench' - - - name: "Fault 3" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0003] - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID33 Reserved" - - key: 2 - value: "ID34 Reserved" - - key: 4 - value: "ID35 Reserved" - - key: 8 - value: "ID36 Reserved" - - key: 16 - value: "ID37 Reserved" - - key: 32 - value: "ID38 Reserved" - - key: 64 - value: "ID39 Reserved" - - key: 128 - value: "ID40 Reserved" - - key: 256 - value: "ID41 Reserved" - - key: 512 - value: "ID42 Reserved" - - key: 1024 - value: "ID43 Reserved" - - key: 2048 - value: "ID44 Reserved" - - key: 4096 - value: "ID45 Reserved" - - key: 8192 - value: "ID46 Reserved" - - key: 16384 - value: "ID47 Reserved" - - key: 32768 - value: "ID48 Reserved" - icon: 'mdi:wrench' - - - name: "Fault 4" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0004] - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID49 Grid voltage sampling value between master and slave DSP vary widely" - - key: 2 - value: "ID50 Grid frequency sampling value between master and slave DSP vary widely" - - key: 4 - value: "ID51 DCI sampling value between master and slave DSP vary widely" - - key: 8 - value: "ID52 GFCI sampling value between master and slave DSP vary widely" - - key: 16 - value: "ID53 Communication failure between master and slave DSP failure" - - key: 32 - value: "ID53 Communication failure between slave and communication board" - - key: 64 - value: "ID55 Relay fault" - - key: 128 - value: "ID56 Insulation resistance between PV array and the earth is too low" - - key: 256 - value: "ID57 Inverter temp is too high" - - key: 512 - value: "ID58 Boost temp is too high" - - key: 1024 - value: "ID59 Environment temp is too high" - - key: 2048 - value: "ID60 Brak podłączenie falownika do kabla PE" - - key: 4096 - value: "ID61 Reserved" - - key: 8192 - value: "ID62 Reserved" - - key: 16384 - value: "ID63 Reserved" - - key: 32768 - value: "ID64 Reserved" - icon: 'mdi:wrench' - - - name: "Fault 5" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [0x0005] - lookup: - - key: 0 - value: "No error" - - key: 1 - value: "ID65 Grid current is too high and causes unrecoverable fault" - - key: 2 - value: "ID66 Bus voltage is too high and causes unrecoverable fault" - - key: 4 - value: "ID67 Grid current is unbalanced and causes unrecoverable fault" - - key: 8 - value: "ID68 Input current is unbalanced and causes unrecoverable fault" - - key: 16 - value: "ID69 Bus voltage is unbalanced and causes unrecoverable fault" - - key: 32 - value: "ID70 Grid current is too high and causes unrecoverable fault" - - key: 64 - value: "ID65 PV Input Mode Configuration is wrong and causes unrecoverable fault" - - key: 128 - value: "ID72 Reserved" - - key: 256 - value: "ID73 Reserved" - - key: 512 - value: "ID74 Input current is too high and causes unrecoverable fault" - - key: 1024 - value: "ID75 Error reading from EEPROM" - - key: 2048 - value: "ID76 Error writing to EEPROM" - - key: 4096 - value: "ID77 Relay fauilure causes unrecoverable fault" - - key: 8192 - value: "ID78 Reserved" - - key: 16384 - value: "ID79 Reserved" - - key: 32768 - value: "ID80 Reserved" - icon: 'mdi:wrench' + - group: solar + items: + - name: "PV1 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 10 + rule: 1 + registers: [0x000A] + icon: "mdi:solar-power" + + - name: "PV2 Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 10 + rule: 1 + registers: [0x000B] + icon: "mdi:solar-power" + + - name: "PV1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0006] + icon: "mdi:solar-power" + + - name: "PV2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0008] + icon: "mdi:solar-power" + + - name: "PV1 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0007] + icon: "mdi:solar-power" + + - name: "PV2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0009] + icon: "mdi:solar-power" + + - name: "Daily Production" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.01 + rule: 1 + registers: [0x0019] + icon: "mdi:solar-power" + + - name: "Total Production" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [0x0016, 0x0015] + icon: "mdi:solar-power" + + - name: "Total generation time" + class: "" + state_class: "measurement" + uom: "h" + scale: 1 + rule: 3 + registers: [0x0018, 0x0017] + icon: "mdi:clock-outline" + + - name: "Today generation time" + class: "" + state_class: "measurement" + uom: "min" + scale: 1 + rule: 1 + registers: [0x001A] + icon: "mdi:clock-outline" + + - group: Output + items: + - name: "Output active power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 10 + rule: 1 + registers: [0x000C] + icon: "mdi:home-lightning-bolt" + + - name: "Output reactive power" + class: "" + state_class: "measurement" + uom: "kVar" + scale: 0.01 + rule: 1 + registers: [0x000D] + icon: "mdi:home-lightning-bolt" + + - name: "Grid frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [0x000E] + icon: "mdi:home-lightning-bolt" + + - name: "L1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x000F] + icon: "mdi:home-lightning-bolt" + + - name: "L1 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0010] + icon: "mdi:home-lightning-bolt" + + - name: "L2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0011] + icon: "mdi:home-lightning-bolt" + + - name: "L2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0012] + icon: "mdi:home-lightning-bolt" + + - name: "L3 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x0013] + icon: "mdi:home-lightning-bolt" + + - name: "L3 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [0x0014] + icon: "mdi:home-lightning-bolt" + + - group: Inverter + items: + - name: "Inverter status" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [0x0000] + lookup: + - key: 0 + value: "Stand-by" + - key: 1 + value: "Self-checking" + - key: 2 + value: "Normal" + - key: 3 + value: "FAULT" + - key: 4 + value: "Permanent" + icon: "mdi:wrench" + + - name: "Inverter module temperature" + class: "temperature" + uom: "°C" + scale: 1 + rule: 1 + registers: [0x001B] + icon: "mdi:thermometer" + + - name: "Inverter inner temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 1 + rule: 1 + registers: [0x001C] + icon: "mdi:thermometer" + + - name: "Inverter bus voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x001D] + icon: "mdi:home-lightning-bolt" + + - name: "PV1 voltage sample by slave CPU" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [0x001E] + icon: "mdi:home-lightning-bolt" + + - name: "PV1 current sample by slave CPU" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [0x001F] + icon: "mdi:home-lightning-bolt" + + - name: "Countdown time" + class: "" + state_class: "measurement" + uom: "s" + scale: 1 + rule: 1 + registers: [0x0020] + icon: "" + + - name: "Inverter alert message" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0021] + icon: "" + + - name: "Input mode" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0022] + icon: "" + + - name: "Communication Board inner message" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0023] + icon: "" + + - name: "Insulation of PV1+ to ground" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [0x0024] + icon: "" + + - name: "Insulation of PV2+ to ground" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [0x0025] + icon: "" + + - name: "Insulation of PV- to ground" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [0x0026] + icon: "" + + - name: "Country" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0027] + lookup: + - key: 0 + value: "Germany" + - key: 1 + value: "CEI0-21 Internal" + - key: 2 + value: "Australia" + - key: 3 + value: "Spain RD1699" + - key: 4 + value: "Turkey" + - key: 5 + value: "Denmark" + - key: 6 + value: "Greece" + - key: 7 + value: "Netherland" + - key: 8 + value: "Belgium" + - key: 9 + value: "UK-G59" + - key: 10 + value: "China" + - key: 11 + value: "France" + - key: 12 + value: "Poland" + - key: 13 + value: "Germany BDEW" + - key: 14 + value: "Germany VDE0126" + - key: 15 + value: "Italy CEI0-16" + - key: 16 + value: "UK-G83" + - key: 17 + value: "Greece Islands" + - key: 18 + value: "EU EN50438" + - key: 19 + value: "EU EN61727" + - key: 20 + value: "Korea" + - key: 21 + value: "Sweden" + - key: 22 + value: "Europe General" + - key: 23 + value: "CEI0-21 External" + - key: 24 + value: "Cyprus" + - key: 25 + value: "India" + - key: 26 + value: "Philippines" + - key: 27 + value: "New Zeland" + - key: 28 + value: "Reserve" + - key: 29 + value: "Reserve" + icon: "" + + - group: Alert + items: + - name: "Fault 1" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0001] + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID01 Grid Over Voltage Protection" + - key: 2 + value: "ID02 Grid Under Voltage Protection" + - key: 4 + value: "ID03 Grid Over Frequency Protection" + - key: 8 + value: "ID04 Grid Under Frequency Protection" + - key: 16 + value: "ID05 PV Under Voltage Protection" + - key: 32 + value: "ID06 Grid Low Voltage Ride through" + - key: 64 + value: "ID07" + - key: 128 + value: "ID08" + - key: 256 + value: "ID09 PV Over Voltage Protection" + - key: 512 + value: "ID10 PV Input Current Unbalanced" + - key: 1024 + value: "ID11 PV Input Mode wrong configuration" + - key: 2048 + value: "ID12 Ground-Fault circuit interrupters fault" + - key: 4096 + value: "ID13 Phase sequence fault" + - key: 8192 + value: "ID14 Hardware boost over current protection" + - key: 16384 + value: "ID15 Hardware AC over current protection" + - key: 32768 + value: "ID16 Grid current is too high" + icon: "mdi:wrench" + + - name: "Fault 2" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0002] + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID17 Grid current sampling error" + - key: 2 + value: "ID18 DCI sampling error" + - key: 4 + value: "ID19 Grid voltage sampling error" + - key: 8 + value: "ID20 GFCI device sampling error" + - key: 16 + value: "ID21 Main chip fault" + - key: 32 + value: "ID22 Hardware auxiliary power fault" + - key: 64 + value: "ID23 Bus voltage zero fault" + - key: 128 + value: "ID24 Output current not balanced" + - key: 256 + value: "ID25 Bus under voltage protection" + - key: 512 + value: "ID26 Bus over voltage protection" + - key: 1024 + value: "ID27 Bus voltage unbalanced" + - key: 2048 + value: "ID28 DCI is too high" + - key: 4096 + value: "ID29 Grid current is too high" + - key: 8192 + value: "ID30 Input current is too high" + - key: 16384 + value: "ID31" + - key: 32768 + value: "ID32" + icon: "mdi:wrench" + + - name: "Fault 3" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0003] + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID33 Reserved" + - key: 2 + value: "ID34 Reserved" + - key: 4 + value: "ID35 Reserved" + - key: 8 + value: "ID36 Reserved" + - key: 16 + value: "ID37 Reserved" + - key: 32 + value: "ID38 Reserved" + - key: 64 + value: "ID39 Reserved" + - key: 128 + value: "ID40 Reserved" + - key: 256 + value: "ID41 Reserved" + - key: 512 + value: "ID42 Reserved" + - key: 1024 + value: "ID43 Reserved" + - key: 2048 + value: "ID44 Reserved" + - key: 4096 + value: "ID45 Reserved" + - key: 8192 + value: "ID46 Reserved" + - key: 16384 + value: "ID47 Reserved" + - key: 32768 + value: "ID48 Reserved" + icon: "mdi:wrench" + + - name: "Fault 4" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0004] + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID49 Grid voltage sampling value between master and slave DSP vary widely" + - key: 2 + value: "ID50 Grid frequency sampling value between master and slave DSP vary widely" + - key: 4 + value: "ID51 DCI sampling value between master and slave DSP vary widely" + - key: 8 + value: "ID52 GFCI sampling value between master and slave DSP vary widely" + - key: 16 + value: "ID53 Communication failure between master and slave DSP failure" + - key: 32 + value: "ID53 Communication failure between slave and communication board" + - key: 64 + value: "ID55 Relay fault" + - key: 128 + value: "ID56 Insulation resistance between PV array and the earth is too low" + - key: 256 + value: "ID57 Inverter temp is too high" + - key: 512 + value: "ID58 Boost temp is too high" + - key: 1024 + value: "ID59 Environment temp is too high" + - key: 2048 + value: "ID60 Brak podłączenie falownika do kabla PE" + - key: 4096 + value: "ID61 Reserved" + - key: 8192 + value: "ID62 Reserved" + - key: 16384 + value: "ID63 Reserved" + - key: 32768 + value: "ID64 Reserved" + icon: "mdi:wrench" + + - name: "Fault 5" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [0x0005] + lookup: + - key: 0 + value: "No error" + - key: 1 + value: "ID65 Grid current is too high and causes unrecoverable fault" + - key: 2 + value: "ID66 Bus voltage is too high and causes unrecoverable fault" + - key: 4 + value: "ID67 Grid current is unbalanced and causes unrecoverable fault" + - key: 8 + value: "ID68 Input current is unbalanced and causes unrecoverable fault" + - key: 16 + value: "ID69 Bus voltage is unbalanced and causes unrecoverable fault" + - key: 32 + value: "ID70 Grid current is too high and causes unrecoverable fault" + - key: 64 + value: "ID65 PV Input Mode Configuration is wrong and causes unrecoverable fault" + - key: 128 + value: "ID72 Reserved" + - key: 256 + value: "ID73 Reserved" + - key: 512 + value: "ID74 Input current is too high and causes unrecoverable fault" + - key: 1024 + value: "ID75 Error reading from EEPROM" + - key: 2048 + value: "ID76 Error writing to EEPROM" + - key: 4096 + value: "ID77 Relay fauilure causes unrecoverable fault" + - key: 8192 + value: "ID78 Reserved" + - key: 16384 + value: "ID79 Reserved" + - key: 32768 + value: "ID80 Reserved" + icon: "mdi:wrench" diff --git a/custom_components/solarman/inverter_definitions/sofar_wifikit.yaml b/custom_components/solarman/inverter_definitions/sofar_wifikit.yaml index 050233f..21d2497 100644 --- a/custom_components/solarman/inverter_definitions/sofar_wifikit.yaml +++ b/custom_components/solarman/inverter_definitions/sofar_wifikit.yaml @@ -1,3 +1,22 @@ +# +# Tested with Solarman ME3000-SP with an embedded +# "wifikit" logger. Might work for other devices +# too. + +# The ME3000-SP is basically a glorified battery +# charger - it is not directly connected to any +# generation infrastructure, but can calculate +# generated energy based on any CT clamps it is +# connected to. For most people this entity will +# be a generally accurate representation of their +# PV panel output, but since this tracks generation +# from _any_ source, it is named generically. +# + +default: + update_interval: 5 + digits: 6 + requests: # Inverter State - start: 0x0200 @@ -12,19 +31,6 @@ requests: end: 0x200B mb_functioncode: 0x04 -# Tested with Solarman ME3000-SP with an embedded -# "wifikit" logger. Might work for other devices -# too. - -# The ME3000-SP is basically a glorified battery -# charger - it is not directly connected to any -# generation infrastructure, but can calculate -# generated energy based on any CT clamps it is -# connected to. For most people this entity will -# be a generally accurate representation of their -# PV panel output, but since this tracks generation -# from _any_ source, it is named generically. - parameters: - group: Generation items: diff --git a/custom_components/solarman/inverter_definitions/solarman_dtsd422-d3.yaml b/custom_components/solarman/inverter_definitions/solarman_dtsd422-d3.yaml index 67851dd..8e6f757 100644 --- a/custom_components/solarman/inverter_definitions/solarman_dtsd422-d3.yaml +++ b/custom_components/solarman/inverter_definitions/solarman_dtsd422-d3.yaml @@ -2,6 +2,10 @@ # Solarman Smart Meter DTSD422-D3 # +default: + update_interval: 5 + digits: 6 + parameters: - group: Voltage items: diff --git a/custom_components/solarman/inverter_definitions/solis_1p8k-5g.yaml b/custom_components/solarman/inverter_definitions/solis_1p8k-5g.yaml index 22ca58d..0a9535b 100644 --- a/custom_components/solarman/inverter_definitions/solis_1p8k-5g.yaml +++ b/custom_components/solarman/inverter_definitions/solis_1p8k-5g.yaml @@ -1,204 +1,209 @@ +# # Solis Single Phase Inverter # 1P8K-5G # Modbus information derived by test and comparing to Solis Cloud # Gedger V.0.1 May 2022 # + +default: + update_interval: 5 + digits: 6 + requests: - start: 2999 - end: 3024 + end: 3024 mb_functioncode: 0x04 - start: 3035 - end: 3043 + end: 3043 mb_functioncode: 0x04 - start: 3071 - end: 3071 + end: 3071 mb_functioncode: 0x04 parameters: - - group: InverterStatus - items: - - name: "Inverter Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 6 - registers: [3043] - icon: 'mdi:home-lightning-bolt' - - - name: "Operating Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 6 - registers: [3071] - icon: 'mdi:home-lightning-bolt' - - - name: "Inverter Temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 0.1 - rule: 2 - registers: [3041] - icon: 'mdi:thermometer' - -# - name: "Inverter ID" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 5 -# registers: [33004,33005,33006,33007,33008,33009,33010,33011,33012,33013,33014,33015,33016,33017,33018,33019] -# isstr: true - - - name: "Product Model" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 6 - registers: [2999] - isstr: true - - - name: "DSP Software Version" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 6 - registers: [3000] - isstr: true - - - name: "LCD Software Version" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 6 - registers: [3001] - isstr: true - - - group: InverterDC - items: - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3021] - icon: 'mdi:solar-power' - - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3023] - icon: 'mdi:solar-power' - - - name: "PV1 Current" - class: "current" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3022] - icon: 'mdi:current-dc' - - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3024] - icon: 'mdi:current-dc' - - - name: "Total DC Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.001 - rule: 3 - registers: [3007, 3006] - icon: 'mdi:solar-power' - - - group: InverterAC - items: - - name: "Inverter AC Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.001 - rule: 3 - registers: [3005, 3004] - icon: 'mdi:solar-power' - - - name: "Inverter Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3035] - icon: 'mdi:transmission-tower' - - - name: "Inverter Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3038] - icon: 'mdi:current-ac' - - - name: "Inverter Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [3042] - icon: 'mdi:sine-wave' - - - group: Generation - items: - - name: "Daily Generation" - class: "energy" - state_class: "measurement" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [3014] - icon: 'mdi:solar-power' - - - name: "Monthly Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3011, 3010] - icon: 'mdi:solar-power' - - - name: "Yearly Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3017, 3016] - icon: 'mdi:solar-power' - - - name: "Total Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3009, 3008] - icon: 'mdi:solar-power' - + - group: InverterStatus + items: + - name: "Inverter Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 6 + registers: [3043] + icon: "mdi:home-lightning-bolt" + + - name: "Operating Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 6 + registers: [3071] + icon: "mdi:home-lightning-bolt" + + - name: "Inverter Temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 0.1 + rule: 2 + registers: [3041] + icon: "mdi:thermometer" + + # - name: "Inverter ID" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 5 + # registers: [33004,33005,33006,33007,33008,33009,33010,33011,33012,33013,33014,33015,33016,33017,33018,33019] + # isstr: true + + - name: "Product Model" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 6 + registers: [2999] + isstr: true + + - name: "DSP Software Version" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 6 + registers: [3000] + isstr: true + + - name: "LCD Software Version" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 6 + registers: [3001] + isstr: true + + - group: InverterDC + items: + - name: "PV1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3021] + icon: "mdi:solar-power" + + - name: "PV2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3023] + icon: "mdi:solar-power" + + - name: "PV1 Current" + class: "current" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3022] + icon: "mdi:current-dc" + + - name: "PV2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3024] + icon: "mdi:current-dc" + + - name: "Total DC Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.001 + rule: 3 + registers: [3007, 3006] + icon: "mdi:solar-power" + + - group: InverterAC + items: + - name: "Inverter AC Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.001 + rule: 3 + registers: [3005, 3004] + icon: "mdi:solar-power" + + - name: "Inverter Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3035] + icon: "mdi:transmission-tower" + + - name: "Inverter Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3038] + icon: "mdi:current-ac" + + - name: "Inverter Frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [3042] + icon: "mdi:sine-wave" + + - group: Generation + items: + - name: "Daily Generation" + class: "energy" + state_class: "measurement" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [3014] + icon: "mdi:solar-power" + + - name: "Monthly Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3011, 3010] + icon: "mdi:solar-power" + + - name: "Yearly Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3017, 3016] + icon: "mdi:solar-power" + + - name: "Total Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3009, 3008] + icon: "mdi:solar-power" diff --git a/custom_components/solarman/inverter_definitions/solis_3p-4g.yaml b/custom_components/solarman/inverter_definitions/solis_3p-4g.yaml index ac34f64..83fd622 100644 --- a/custom_components/solarman/inverter_definitions/solis_3p-4g.yaml +++ b/custom_components/solarman/inverter_definitions/solis_3p-4g.yaml @@ -1,25 +1,31 @@ +# # Solis 4G Three Phase Inverter # Solis-3P(5-10)K-4G # refering to https://ginlongsolis.freshdesk.com/support/solutions/articles/36000340158-modbus-communication-for-solis-inverters # agirilovich June 2023 +# + +default: + update_interval: 5 + digits: 6 requests: - start: 2999 - end: 3044 + end: 3044 mb_functioncode: 0x04 parameters: - - group: Inverter - items: - - name: "Working Mode" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [3040] - icon: 'mdi:home-lightning-bolt' - lookup: + - group: Inverter + items: + - name: "Working Mode" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [3040] + icon: "mdi:home-lightning-bolt" + lookup: - key: 0 value: "No response mode" - key: 1 @@ -35,230 +41,228 @@ parameters: - key: 6 value: "Rule21Volt–watt" - - name: "Inverter Temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 0.1 - rule: 1 - registers: [3041] - icon: 'mdi:thermometer' - - - name: "Product Model" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [2999] - isstr: true + - name: "Inverter Temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 0.1 + rule: 1 + registers: [3041] + icon: "mdi:thermometer" - - name: "DSP Software Version" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [3000] - isstr: true + - name: "Product Model" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [2999] + isstr: true - - name: "LCD Software Version" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [3001] - isstr: true + - name: "DSP Software Version" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [3000] + isstr: true - - name: "Inverter Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [3043] - icon: 'mdi:list-status' - isstr: true - lookup: - - key: 0 - value: "Waiting" - - key: 1 - value: "OpenRun" - - key: 2 - value: "SoftRun" - - key: 3 - value: "Generating" - - key: 1004 - value: "Grid off" - - key: 2011 - value: "Fail Safe" + - name: "LCD Software Version" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [3001] + isstr: true - - group: InverterDC - items: - - name: "DC Voltage 1" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3021] - icon: 'mdi:solar-power' + - name: "Inverter Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [3043] + icon: "mdi:list-status" + isstr: true + lookup: + - key: 0 + value: "Waiting" + - key: 1 + value: "OpenRun" + - key: 2 + value: "SoftRun" + - key: 3 + value: "Generating" + - key: 1004 + value: "Grid off" + - key: 2011 + value: "Fail Safe" - - name: "DC Voltage 2" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3023] - icon: 'mdi:solar-power' + - group: InverterDC + items: + - name: "DC Voltage 1" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3021] + icon: "mdi:solar-power" - - name: "DC Current 1" - class: "current" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3022] - icon: 'mdi:current-dc' + - name: "DC Voltage 2" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3023] + icon: "mdi:solar-power" - - name: "DC Current 2" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3024] - icon: 'mdi:current-dc' + - name: "DC Current 1" + class: "current" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3022] + icon: "mdi:current-dc" - - name: "Total DC Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.001 - rule: 3 - registers: [3007, 3006] - icon: 'mdi:solar-power' + - name: "DC Current 2" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3024] + icon: "mdi:current-dc" - - group: InverterAC - items: - - name: "Active power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.001 - rule: 3 - registers: [3005, 3004] - icon: 'mdi:solar-power' + - name: "Total DC Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.001 + rule: 3 + registers: [3007, 3006] + icon: "mdi:solar-power" - - - name: "Inverter AC Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.001 - rule: 3 - registers: [3005, 3004] - icon: 'mdi:solar-power' + - group: InverterAC + items: + - name: "Active power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.001 + rule: 3 + registers: [3005, 3004] + icon: "mdi:solar-power" - - name: "A phase voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3033] - icon: 'mdi:transmission-tower' + - name: "Inverter AC Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.001 + rule: 3 + registers: [3005, 3004] + icon: "mdi:solar-power" - - name: "B phase voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3034] - icon: 'mdi:transmission-tower' + - name: "A phase voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3033] + icon: "mdi:transmission-tower" - - name: "C phase voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3035] - icon: 'mdi:transmission-tower' + - name: "B phase voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3034] + icon: "mdi:transmission-tower" - - name: "A phase current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3036] - icon: 'mdi:current-ac' + - name: "C phase voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3035] + icon: "mdi:transmission-tower" - - name: "B phase current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3037] - icon: 'mdi:current-ac' + - name: "A phase current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3036] + icon: "mdi:current-ac" - - name: "C phase current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3038] - icon: 'mdi:current-ac' + - name: "B phase current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3037] + icon: "mdi:current-ac" + - name: "C phase current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3038] + icon: "mdi:current-ac" - - name: "Inverter Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [3042] - icon: 'mdi:sine-wave' + - name: "Inverter Frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [3042] + icon: "mdi:sine-wave" - - group: Generation - items: - - name: "Daily Generation" - class: "energy" - state_class: "measurement" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [3014] - icon: 'mdi:solar-power' + - group: Generation + items: + - name: "Daily Generation" + class: "energy" + state_class: "measurement" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [3014] + icon: "mdi:solar-power" - - name: "Monthly Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3011, 3010] - icon: 'mdi:solar-power' + - name: "Monthly Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3011, 3010] + icon: "mdi:solar-power" - - name: "Yearly Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3017, 3016] - icon: 'mdi:solar-power' + - name: "Yearly Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3017, 3016] + icon: "mdi:solar-power" - - name: "Total Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3009, 3008] - icon: 'mdi:solar-power' + - name: "Total Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3009, 3008] + icon: "mdi:solar-power" diff --git a/custom_components/solarman/inverter_definitions/solis_hybrid.yaml b/custom_components/solarman/inverter_definitions/solis_hybrid.yaml index c27e1d1..a2a923e 100644 --- a/custom_components/solarman/inverter_definitions/solis_hybrid.yaml +++ b/custom_components/solarman/inverter_definitions/solis_hybrid.yaml @@ -1,955 +1,961 @@ +# # Solis Single Phase Hybrid # RHI-(3-6)K-48ES-5G # Modbus information retrieved from: # https://www.scss.tcd.ie/Brian.Coghlan/Elios4you/RS485_MODBUS-Hybrid-BACoghlan-201811228-1854.pdf +# + +default: + update_interval: 10 + digits: 6 requests: - start: 33029 - end: 33095 + end: 33095 mb_functioncode: 0x04 - start: 33116 - end: 33179 + end: 33179 mb_functioncode: 0x04 - start: 33206 - end: 33282 + end: 33282 mb_functioncode: 0x04 - start: 43000 end: 43150 mb_functioncode: 0x03 parameters: - - group: InverterStatus - items: - - name: "Inverter Status" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [33095] - icon: 'mdi:home-lightning-bolt' - isstr: true - lookup: - - key: 0x0 - value: "Waiting State" - - key: 0x1 - value: "Open Loop Operation" - - key: 0x2 - value: "Soft Start" - - key: 0x3 - value: "On Grid/Generating" - - key: 0x1004 - value: "Grid OverVoltage" - - key: 0x1010 - value: "Grid UnderVoltage" - - key: 0x1012 - value: "Grid OverFrequency" - - key: 0x1013 - value: "Grid UnderFrequency" - - key: 0x1014 - value: "Grid Imp too large" - - key: 0x1015 - value: "No Grid" - - key: 0x1016 - value: "Grid Imbalance" - - key: 0x1017 - value: "Grid Freq Jitter" - - key: 0x1018 - value: "Grid Overcurrent" - - key: 0x1019 - value: "Grid Tracking Fault" - - key: 0x1020 - value: "DC OverVoltage" - - key: 0x1021 - value: "DC Bus Overvoltage" - - key: 0x1022 - value: "DC Bus Uneven Voltage" - - key: 0x1024 - value: "DC Bus Uneven Voltage2" - - key: 0x1025 - value: "DC A path OverCurrent" - - key: 0x1026 - value: "DC B path OverCurrent" - - key: 0x1027 - value: "DC Input Disturbance" - - key: 0x1030 - value: "Grid Disturbance" - - key: 0x1031 - value: "DSP Initialization Protection" - - key: 0x1032 - value: "Over Temp Protection" - - key: 0x1033 - value: "PV Insulation Fault" - - key: 0x1034 - value: "Leakage Current Protection" - - key: 0x1035 - value: "Relay Detection Protection" - - key: 0x1036 - value: "DSP_B Protection" - - key: 0x1037 - value: "DC Component too Large" - - key: 0x1038 - value: "12v UnderVoltage Protection" - - key: 0x1039 - value: "Under Temperature Protection" - - key: 0x1040 - value: "Arc Self-Test Protection" - - key: 0x1041 - value: "Arc Protection" - - key: 0x1042 - value: "DSP on-chip SRAM exception" - - key: 0x1043 - value: "DSP on-chip FLASH exception" - - key: 0x1044 - value: "DSP on-chip PC pointer is abnormal" - - key: 0x1045 - value: "DSP key register exception" - - key: 0x1046 - value: "Grid disturbance 02" - - key: 0x1047 - value: "Grid current sampling abnormality" - - key: 0x1048 - value: "IGBT overcurrent" - - key: 0x1050 - value: "Network current transient overcurrent" - - key: 0x1051 - value: "Battery overvoltage hardware failure" - - key: 0x1052 - value: "LLC hardware overcurrent" - - key: 0x1053 - value: "Battery overvoltage detection" - - key: 0x1054 - value: "Battery undervoltage detection" - - key: 0x1055 - value: "Battery no connected" - - key: 0x1056 - value: "Bypass overvoltage fault" - - key: 0x1057 - value: "Bypass overload fault" - - - name: "Operating Status" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [33121] - icon: 'mdi:home-lightning-bolt' - isstr: true - lookup: - - key: 0x701 - value: "Normal Operation" - - key: 0x702 - value: "Initial Standby" - - key: 0x704 - value: "Control Shutdown" - - key: 0x708 - value: "Downtime" - - key: 0x710 - value: "Standby" - - key: 0x720 - value: "Derating Operation" - - key: 0x740 - value: "Limit Operation" - - key: 0x780 - value: "Bypass Overload" - - - name: "Grid Fault Status" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [33116] - icon: 'mdi:alert' - isstr: true - lookup: - - key: 0x0000 - value: "No Fault" - - key: 0x1 - value: "No Grid" - - key: 0x2 - value: "Grid OverVoltage" - - key: 0x4 - value: "Grid UnderVoltage" - - key: 0x8 - value: "Grid OverFrequency" - - key: 0x10 - value: "Grid UnderFrequency" - - key: 0x20 - value: "Grid Imbalance" - - key: 0x40 - value: "Grid Frequncy Jitter" - - key: 0x80 - value: "Grid Impedence too Large" - - key: 0x100 - value: "Grid Tracking Fault" - - key: 0x200 - value: "Meter Comm Failure" - - key: 0x400 - value: "Failsafe" - - - name: "Backup Load Fault Status" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [33117] - icon: 'mdi:alert' - isstr: true - lookup: - - key: 0x0 - value: "No Fault" - - key: 0x1 - value: "Bypass OverVoltage Fault" - - key: 0x2 - value: "Bypass Overload Fault" - - - name: "Battery Fault Status" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [33118] - icon: 'mdi:alert' - isstr: true - lookup: - - key: 0x0 - value: "No Fault" - - key: 0x1 - value: "Battery Not Connected" - - key: 0x2 - value: "Battery OverVoltage Detection" - - key: 0x4 - value: "Battery UnderVoltage Detection" - - - name: "Fault Status 04 (Device)" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [33119] - icon: 'mdi:alert' - isstr: true - lookup: - - key: 0x0000 - value: "No Fault" - - key: 0x1 - value: "DC OverVoltage" - - key: 0x2 - value: "DC Bus OverVoltage" - - key: 0x4 - value: "DC Bus Uneven Voltage" - - key: 0x8 - value: "DC Bus UnderVoltage" - - key: 0x10 - value: "DC Bus2 Uneven Voltage" - - key: 0x20 - value: "DC A path OverCurrent" - - key: 0x40 - value: "DC B path OverCurrent" - - key: 0x80 - value: "DC Input Disturbance" - - key: 0x100 - value: "Grid OverCurrent" - - key: 0x200 - value: "IGBT OverCurrent" - - key: 0x400 - value: "Grid Disturbance 2" - - key: 0x800 - value: "Arc Self-Test Protection" - - key: 0x1000 - value: "Arc Fault Reservation" - - key: 0x2000 - value: "Grid Current Sample Abnormality" - - - name: "Fault Status 05 (Device)" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [33120] - icon: 'mdi:alert' - isstr: true - lookup: - - key: 0x0000 - value: "No Fault" - - key: 0x1 - value: "Grid Disturbance" - - key: 0x2 - value: "DC Component Too Large" - - key: 0x4 - value: "Over Temp Protection" - - key: 0x8 - value: "Relay Detection Protection" - - key: 0x10 - value: "Under Temp Protection" - - key: 0x20 - value: "PV Insulation Fault" - - key: 0x40 - value: "12V UnderVoltage Protection" - - key: 0x80 - value: "Leakage Current Protection" - - key: 0x100 - value: "Leakage Current Self-Test" - - key: 0x200 - value: "DSP Initialization Protect" - - key: 0x400 - value: "DSP B Protection" - - key: 0x800 - value: "Battery Overvoltage H/W Failure" - - key: 0x1000 - value: "LLC Hardware OverCurrent" - - key: 0x2000 - value: "Network Side Transient OverCurrent" - - key: 0x4000 - value: "CAN Communication Failed" - - key: 0x8000 - value: "DSP Communication Failed" - - - name: "Inverter Temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 0.1 - rule: 2 - registers: [33093] - icon: 'mdi:thermometer' - -# Sensors below are outside of modbus request ranges. -# If enabling, ensure to amend the request start register. -# -# - name: "Inverter ID" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 5 -# registers: [33004,33005,33006,33007,33008,33009,33010,33011,33012,33013,33014,33015,33016,33017,33018,33019] -# isstr: true - -# - name: "Product Model" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 6 -# registers: [33000] -# isstr: true - -# - name: "DSP Software Version" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 6 -# registers: [33001] -# isstr: true - -# - name: "LCD Software Version" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 6 -# registers: [33002] -# isstr: true - -# - name: "Protocol Software Version" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 6 -# registers: [33003] -# isstr: true - - - name: "Storage Control Mode" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [33132] - icon: 'mdi:battery-clock' - isstr: true - lookup: - - key: 0x21 - value: "Self Use" - - key: 0x22 - value: "Optimized Revenue" - - key: 0x23 - value: "Time of Use" - - key: 0x24 - value: "Off-Grid Storage" - - key: 0x28 - value: "Battery Wake-Up" - - key: 0x60 - value: "Feed-In Priority" - - - group: InverterDC - items: - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [33049] - icon: 'mdi:solar-power' - - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [33051] - icon: 'mdi:solar-power' - - - name: "PV1 Current" - class: "current" - uom: "A" - scale: 0.1 - rule: 1 - registers: [33050] - icon: 'mdi:current-dc' - - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [33052] - icon: 'mdi:current-dc' - - - name: "Inverter DC Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 3 - registers: [33058,33057] - icon: 'mdi:solar-power' - - - name: "Inverting/Rectifing Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 10 - rule: 2 - registers: [33157] - icon: 'mdi:solar-power' - - - group: InverterAC - items: - - name: "Inverter AC Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 4 - registers: [33152,33151] - icon: 'mdi:solar-power' - - - name: "Inverter Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [33073] - icon: 'mdi:transmission-tower' - - - name: "Inverter Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [33076] - icon: 'mdi:current-ac' - - - name: "Inverter Active Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 4 - registers: [33080,33079] - icon: 'mdi:transmission-tower' - - # Inverter Reactive Power is defined as a signed 32 bit integer - # across 33082 and 33081, however the field appears to be only - # 20 bits wide i.e. the upper 12 bits are always zero. - # Define only the lower signed 16 bits for moment - - name: "Inverter Reactive Power" - class: "reactive_power" - state_class: "measurement" - uom: "var" - scale: 1 - rule: 4 - registers: [33082] - icon: 'mdi:transmission-tower' - - - name: "Inverter Apparent Power" - class: "apparent_power" - state_class: "measurement" - uom: "VA" - scale: 1 - rule: 4 - registers: [33084,33083] - icon: 'mdi:transmission-tower' - - - name: "Inverter Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [33094] - icon: 'mdi:sine-wave' - - - group: Generation - items: - - name: "Daily Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [33035] - icon: 'mdi:solar-power' - - - name: "Monthly Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [33032,33031] - icon: 'mdi:solar-power' - - - name: "Yearly Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [33038,33037] - icon: 'mdi:solar-power' - - - name: "Total Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [33030,33029] - icon: 'mdi:solar-power' - - - group: Grid - items: - - name: "Meter Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [33282] - icon: 'mdi:sine-wave' - - - name: "Meter Power Factor" - class: "power_factor" - state_class: "measurement" - uom: "" - scale: 0.01 - rule: 2 - registers: [33281] - icon: 'mdi:transmission-tower' - - - name: "Meter Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [33251] - icon: 'mdi:transmission-tower' - - - name: "Meter Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.01 - rule: 1 - registers: [33252] - icon: 'mdi:current-ac' - - - name: "Meter Active Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 4 - registers: [33258,33257] - icon: 'mdi:transmission-tower' - - - name: "Meter Reactive Power" - class: "reactive_power" - state_class: "measurement" - uom: "var" - scale: 1 - rule: 4 - registers: [33266,33265] - icon: 'mdi:transmission-tower' - - - name: "Meter Apparent Power" - class: "apparent_power" - state_class: "measurement" - uom: "VA" - scale: 1 - rule: 4 - registers: [33274,33273] - icon: 'mdi:transmission-tower' - - - name: "Daily Energy Imported" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [33171] - icon: 'mdi:home-import-outline' - - - name: "Total Energy Imported" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [33170,33169] - icon: 'mdi:home-import-outline' - - - name: "Daily Energy Exported" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [33175] - icon: 'mdi:home-export-outline' - - - name: "Total Energy Exported" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [33174,33173] - icon: 'mdi:home-export-outline' - - - group: Load - items: - - name: "House Load Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [33147] - icon: 'mdi:home-lightning-bolt' - - - name: "Backup Load Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [33148] - icon: 'mdi:home-battery' - - - name: "Daily House+Backup Load Consumption" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [33179] - icon: 'mdi:lightning-bolt-outline' - - - name: "Total House+Backup Load Consumption" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [33178,33177] - icon: 'mdi:lightning-bolt-outline' - - - group: Battery - items: - - name: "Battery Status" - class: "" - state_class: "measurement" - uom: "" - scale: 1 - rule: 1 - registers: [33135] - isstr: true - lookup: - - key: 0 - value: "Charge" - - key: 1 - value: "Discharge" - icon: 'mdi:battery' - - - name: "Battery Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 4 - registers: [33150,33149] - icon: 'mdi:battery-charging' - - - name: "Battery SOC" - class: "battery" - state_class: "measurement" - uom: "%" - scale: 1 - rule: 1 - registers: [33139] - icon: 'mdi:battery' - - - name: "Battery SOH" - class: "battery" - state_class: "measurement" - uom: "%" - scale: 1 - rule: 1 - registers: [33140] - icon: 'mdi:battery' - - - name: "Battery Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 2 - registers: [33134] - icon: 'mdi:current-dc' - - - name: "Battery Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [33133] - icon: 'mdi:battery' - - - name: "Today Battery Charge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [33163] - icon: 'mdi:battery-plus' - - - name: "Today Battery Discharge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [33167] - icon: 'mdi:battery-minus' - - - name: "Total Battery Charge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [33162,33161] - icon: 'mdi:battery-plus' - - - name: "Total Battery Discharge" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [33166,33165] - icon: 'mdi:battery-minus' - - - name: "Battery Charge Current Limit" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [33206] - icon: 'mdi:battery-arrow-up' - - - name: "Battery Discharge Current Limit" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [33207] - icon: 'mdi:battery-arrow-down' - - - name: "BMS Battery Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 2 - registers: [33142] - icon: 'mdi:current-dc' - - - name: "BMS Battery Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.01 - rule: 1 - registers: [33141] - icon: 'mdi:battery' - - - name: "BMS Battery Charge Current Limit" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [33143] - icon: 'mdi:battery-arrow-up' - - - name: "BMS Battery Discharge Current Limit" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [33144] - icon: 'mdi:battery-arrow-down' - - - name: "Backup Mode SOC" - class: "battery" - state_class: "measurement" - uom: "%" - scale: 1 - rule: 1 - registers: [43024] - icon: 'mdi:battery' - - - name: "Overdischarge SOC" - class: "battery" - state_class: "measurement" - uom: "%" - scale: 1 - rule: 1 - registers: [43011] - icon: 'mdi:battery' - - - group: TimedCharge - items: - - name: "Timed Charge Current" - class: "" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [43141] - icon: 'mdi:wrench-clock' - - - name: "Timed Discharge Current" - class: "" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [43142] - icon: 'mdi:wrench-clock' - - - name: "Timed Charge Start Hour" - class: "" - state_class: "measurement" - uom: "H" - scale: 1 - rule: 1 - registers: [43143] - icon: 'mdi:wrench-clock' - - - name: "Timed Charge Start Minute" - class: "" - state_class: "measurement" - uom: "M" - scale: 1 - rule: 1 - registers: [43144] - icon: 'mdi:wrench-clock' - - - name: "Timed Charge End Hour" - class: "" - state_class: "measurement" - uom: "H" - scale: 1 - rule: 1 - registers: [43145] - icon: 'mdi:wrench-clock' - - - name: "Timed Charge End Minute" - class: "" - state_class: "measurement" - uom: "M" - scale: 1 - rule: 1 - registers: [43146] - icon: 'mdi:wrench-clock' - - - name: "Timed Discharge Start Hour" - class: "" - state_class: "measurement" - uom: "H" - scale: 1 - rule: 1 - registers: [43147] - icon: 'mdi:wrench-clock' - - - name: "Timed Discharge Start Minute" - class: "" - state_class: "measurement" - uom: "M" - scale: 1 - rule: 1 - registers: [43148] - icon: 'mdi:wrench-clock' - - - name: "Timed Discharge End Hour" - class: "" - state_class: "measurement" - uom: "H" - scale: 1 - rule: 1 - registers: [43149] - icon: 'mdi:wrench-clock' - - - name: "Timed Discharge End Minute" - class: "" - state_class: "measurement" - uom: "M" - scale: 1 - rule: 1 - registers: [43150] - icon: 'mdi:wrench-clock' + - group: InverterStatus + items: + - name: "Inverter Status" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [33095] + icon: "mdi:home-lightning-bolt" + isstr: true + lookup: + - key: 0x0 + value: "Waiting State" + - key: 0x1 + value: "Open Loop Operation" + - key: 0x2 + value: "Soft Start" + - key: 0x3 + value: "On Grid/Generating" + - key: 0x1004 + value: "Grid OverVoltage" + - key: 0x1010 + value: "Grid UnderVoltage" + - key: 0x1012 + value: "Grid OverFrequency" + - key: 0x1013 + value: "Grid UnderFrequency" + - key: 0x1014 + value: "Grid Imp too large" + - key: 0x1015 + value: "No Grid" + - key: 0x1016 + value: "Grid Imbalance" + - key: 0x1017 + value: "Grid Freq Jitter" + - key: 0x1018 + value: "Grid Overcurrent" + - key: 0x1019 + value: "Grid Tracking Fault" + - key: 0x1020 + value: "DC OverVoltage" + - key: 0x1021 + value: "DC Bus Overvoltage" + - key: 0x1022 + value: "DC Bus Uneven Voltage" + - key: 0x1024 + value: "DC Bus Uneven Voltage2" + - key: 0x1025 + value: "DC A path OverCurrent" + - key: 0x1026 + value: "DC B path OverCurrent" + - key: 0x1027 + value: "DC Input Disturbance" + - key: 0x1030 + value: "Grid Disturbance" + - key: 0x1031 + value: "DSP Initialization Protection" + - key: 0x1032 + value: "Over Temp Protection" + - key: 0x1033 + value: "PV Insulation Fault" + - key: 0x1034 + value: "Leakage Current Protection" + - key: 0x1035 + value: "Relay Detection Protection" + - key: 0x1036 + value: "DSP_B Protection" + - key: 0x1037 + value: "DC Component too Large" + - key: 0x1038 + value: "12v UnderVoltage Protection" + - key: 0x1039 + value: "Under Temperature Protection" + - key: 0x1040 + value: "Arc Self-Test Protection" + - key: 0x1041 + value: "Arc Protection" + - key: 0x1042 + value: "DSP on-chip SRAM exception" + - key: 0x1043 + value: "DSP on-chip FLASH exception" + - key: 0x1044 + value: "DSP on-chip PC pointer is abnormal" + - key: 0x1045 + value: "DSP key register exception" + - key: 0x1046 + value: "Grid disturbance 02" + - key: 0x1047 + value: "Grid current sampling abnormality" + - key: 0x1048 + value: "IGBT overcurrent" + - key: 0x1050 + value: "Network current transient overcurrent" + - key: 0x1051 + value: "Battery overvoltage hardware failure" + - key: 0x1052 + value: "LLC hardware overcurrent" + - key: 0x1053 + value: "Battery overvoltage detection" + - key: 0x1054 + value: "Battery undervoltage detection" + - key: 0x1055 + value: "Battery no connected" + - key: 0x1056 + value: "Bypass overvoltage fault" + - key: 0x1057 + value: "Bypass overload fault" + + - name: "Operating Status" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [33121] + icon: "mdi:home-lightning-bolt" + isstr: true + lookup: + - key: 0x701 + value: "Normal Operation" + - key: 0x702 + value: "Initial Standby" + - key: 0x704 + value: "Control Shutdown" + - key: 0x708 + value: "Downtime" + - key: 0x710 + value: "Standby" + - key: 0x720 + value: "Derating Operation" + - key: 0x740 + value: "Limit Operation" + - key: 0x780 + value: "Bypass Overload" + + - name: "Grid Fault Status" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [33116] + icon: "mdi:alert" + isstr: true + lookup: + - key: 0x0000 + value: "No Fault" + - key: 0x1 + value: "No Grid" + - key: 0x2 + value: "Grid OverVoltage" + - key: 0x4 + value: "Grid UnderVoltage" + - key: 0x8 + value: "Grid OverFrequency" + - key: 0x10 + value: "Grid UnderFrequency" + - key: 0x20 + value: "Grid Imbalance" + - key: 0x40 + value: "Grid Frequncy Jitter" + - key: 0x80 + value: "Grid Impedence too Large" + - key: 0x100 + value: "Grid Tracking Fault" + - key: 0x200 + value: "Meter Comm Failure" + - key: 0x400 + value: "Failsafe" + + - name: "Backup Load Fault Status" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [33117] + icon: "mdi:alert" + isstr: true + lookup: + - key: 0x0 + value: "No Fault" + - key: 0x1 + value: "Bypass OverVoltage Fault" + - key: 0x2 + value: "Bypass Overload Fault" + + - name: "Battery Fault Status" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [33118] + icon: "mdi:alert" + isstr: true + lookup: + - key: 0x0 + value: "No Fault" + - key: 0x1 + value: "Battery Not Connected" + - key: 0x2 + value: "Battery OverVoltage Detection" + - key: 0x4 + value: "Battery UnderVoltage Detection" + + - name: "Fault Status 04 (Device)" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [33119] + icon: "mdi:alert" + isstr: true + lookup: + - key: 0x0000 + value: "No Fault" + - key: 0x1 + value: "DC OverVoltage" + - key: 0x2 + value: "DC Bus OverVoltage" + - key: 0x4 + value: "DC Bus Uneven Voltage" + - key: 0x8 + value: "DC Bus UnderVoltage" + - key: 0x10 + value: "DC Bus2 Uneven Voltage" + - key: 0x20 + value: "DC A path OverCurrent" + - key: 0x40 + value: "DC B path OverCurrent" + - key: 0x80 + value: "DC Input Disturbance" + - key: 0x100 + value: "Grid OverCurrent" + - key: 0x200 + value: "IGBT OverCurrent" + - key: 0x400 + value: "Grid Disturbance 2" + - key: 0x800 + value: "Arc Self-Test Protection" + - key: 0x1000 + value: "Arc Fault Reservation" + - key: 0x2000 + value: "Grid Current Sample Abnormality" + + - name: "Fault Status 05 (Device)" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [33120] + icon: "mdi:alert" + isstr: true + lookup: + - key: 0x0000 + value: "No Fault" + - key: 0x1 + value: "Grid Disturbance" + - key: 0x2 + value: "DC Component Too Large" + - key: 0x4 + value: "Over Temp Protection" + - key: 0x8 + value: "Relay Detection Protection" + - key: 0x10 + value: "Under Temp Protection" + - key: 0x20 + value: "PV Insulation Fault" + - key: 0x40 + value: "12V UnderVoltage Protection" + - key: 0x80 + value: "Leakage Current Protection" + - key: 0x100 + value: "Leakage Current Self-Test" + - key: 0x200 + value: "DSP Initialization Protect" + - key: 0x400 + value: "DSP B Protection" + - key: 0x800 + value: "Battery Overvoltage H/W Failure" + - key: 0x1000 + value: "LLC Hardware OverCurrent" + - key: 0x2000 + value: "Network Side Transient OverCurrent" + - key: 0x4000 + value: "CAN Communication Failed" + - key: 0x8000 + value: "DSP Communication Failed" + + - name: "Inverter Temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 0.1 + rule: 2 + registers: [33093] + icon: "mdi:thermometer" + + # Sensors below are outside of modbus request ranges. + # If enabling, ensure to amend the request start register. + # + # - name: "Inverter ID" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 5 + # registers: [33004,33005,33006,33007,33008,33009,33010,33011,33012,33013,33014,33015,33016,33017,33018,33019] + # isstr: true + + # - name: "Product Model" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 6 + # registers: [33000] + # isstr: true + + # - name: "DSP Software Version" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 6 + # registers: [33001] + # isstr: true + + # - name: "LCD Software Version" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 6 + # registers: [33002] + # isstr: true + + # - name: "Protocol Software Version" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 6 + # registers: [33003] + # isstr: true + + - name: "Storage Control Mode" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [33132] + icon: "mdi:battery-clock" + isstr: true + lookup: + - key: 0x21 + value: "Self Use" + - key: 0x22 + value: "Optimized Revenue" + - key: 0x23 + value: "Time of Use" + - key: 0x24 + value: "Off-Grid Storage" + - key: 0x28 + value: "Battery Wake-Up" + - key: 0x60 + value: "Feed-In Priority" + + - group: InverterDC + items: + - name: "PV1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [33049] + icon: "mdi:solar-power" + + - name: "PV2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [33051] + icon: "mdi:solar-power" + + - name: "PV1 Current" + class: "current" + uom: "A" + scale: 0.1 + rule: 1 + registers: [33050] + icon: "mdi:current-dc" + + - name: "PV2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [33052] + icon: "mdi:current-dc" + + - name: "Inverter DC Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 3 + registers: [33058, 33057] + icon: "mdi:solar-power" + + - name: "Inverting/Rectifing Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 10 + rule: 2 + registers: [33157] + icon: "mdi:solar-power" + + - group: InverterAC + items: + - name: "Inverter AC Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 4 + registers: [33152, 33151] + icon: "mdi:solar-power" + + - name: "Inverter Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [33073] + icon: "mdi:transmission-tower" + + - name: "Inverter Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [33076] + icon: "mdi:current-ac" + + - name: "Inverter Active Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 4 + registers: [33080, 33079] + icon: "mdi:transmission-tower" + + # Inverter Reactive Power is defined as a signed 32 bit integer + # across 33082 and 33081, however the field appears to be only + # 20 bits wide i.e. the upper 12 bits are always zero. + # Define only the lower signed 16 bits for moment + - name: "Inverter Reactive Power" + class: "reactive_power" + state_class: "measurement" + uom: "var" + scale: 1 + rule: 4 + registers: [33082] + icon: "mdi:transmission-tower" + + - name: "Inverter Apparent Power" + class: "apparent_power" + state_class: "measurement" + uom: "VA" + scale: 1 + rule: 4 + registers: [33084, 33083] + icon: "mdi:transmission-tower" + + - name: "Inverter Frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [33094] + icon: "mdi:sine-wave" + + - group: Generation + items: + - name: "Daily Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [33035] + icon: "mdi:solar-power" + + - name: "Monthly Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [33032, 33031] + icon: "mdi:solar-power" + + - name: "Yearly Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [33038, 33037] + icon: "mdi:solar-power" + + - name: "Total Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [33030, 33029] + icon: "mdi:solar-power" + + - group: Grid + items: + - name: "Meter Frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [33282] + icon: "mdi:sine-wave" + + - name: "Meter Power Factor" + class: "power_factor" + state_class: "measurement" + uom: "" + scale: 0.01 + rule: 2 + registers: [33281] + icon: "mdi:transmission-tower" + + - name: "Meter Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [33251] + icon: "mdi:transmission-tower" + + - name: "Meter Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.01 + rule: 1 + registers: [33252] + icon: "mdi:current-ac" + + - name: "Meter Active Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 4 + registers: [33258, 33257] + icon: "mdi:transmission-tower" + + - name: "Meter Reactive Power" + class: "reactive_power" + state_class: "measurement" + uom: "var" + scale: 1 + rule: 4 + registers: [33266, 33265] + icon: "mdi:transmission-tower" + + - name: "Meter Apparent Power" + class: "apparent_power" + state_class: "measurement" + uom: "VA" + scale: 1 + rule: 4 + registers: [33274, 33273] + icon: "mdi:transmission-tower" + + - name: "Daily Energy Imported" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [33171] + icon: "mdi:home-import-outline" + + - name: "Total Energy Imported" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [33170, 33169] + icon: "mdi:home-import-outline" + + - name: "Daily Energy Exported" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [33175] + icon: "mdi:home-export-outline" + + - name: "Total Energy Exported" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [33174, 33173] + icon: "mdi:home-export-outline" + + - group: Load + items: + - name: "House Load Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [33147] + icon: "mdi:home-lightning-bolt" + + - name: "Backup Load Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [33148] + icon: "mdi:home-battery" + + - name: "Daily House+Backup Load Consumption" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [33179] + icon: "mdi:lightning-bolt-outline" + + - name: "Total House+Backup Load Consumption" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [33178, 33177] + icon: "mdi:lightning-bolt-outline" + + - group: Battery + items: + - name: "Battery Status" + class: "" + state_class: "measurement" + uom: "" + scale: 1 + rule: 1 + registers: [33135] + isstr: true + lookup: + - key: 0 + value: "Charge" + - key: 1 + value: "Discharge" + icon: "mdi:battery" + + - name: "Battery Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 4 + registers: [33150, 33149] + icon: "mdi:battery-charging" + + - name: "Battery SOC" + class: "battery" + state_class: "measurement" + uom: "%" + scale: 1 + rule: 1 + registers: [33139] + icon: "mdi:battery" + + - name: "Battery SOH" + class: "battery" + state_class: "measurement" + uom: "%" + scale: 1 + rule: 1 + registers: [33140] + icon: "mdi:battery" + + - name: "Battery Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 2 + registers: [33134] + icon: "mdi:current-dc" + + - name: "Battery Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [33133] + icon: "mdi:battery" + + - name: "Today Battery Charge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [33163] + icon: "mdi:battery-plus" + + - name: "Today Battery Discharge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [33167] + icon: "mdi:battery-minus" + + - name: "Total Battery Charge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [33162, 33161] + icon: "mdi:battery-plus" + + - name: "Total Battery Discharge" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [33166, 33165] + icon: "mdi:battery-minus" + + - name: "Battery Charge Current Limit" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [33206] + icon: "mdi:battery-arrow-up" + + - name: "Battery Discharge Current Limit" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [33207] + icon: "mdi:battery-arrow-down" + + - name: "BMS Battery Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 2 + registers: [33142] + icon: "mdi:current-dc" + + - name: "BMS Battery Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.01 + rule: 1 + registers: [33141] + icon: "mdi:battery" + + - name: "BMS Battery Charge Current Limit" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [33143] + icon: "mdi:battery-arrow-up" + + - name: "BMS Battery Discharge Current Limit" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [33144] + icon: "mdi:battery-arrow-down" + + - name: "Backup Mode SOC" + class: "battery" + state_class: "measurement" + uom: "%" + scale: 1 + rule: 1 + registers: [43024] + icon: "mdi:battery" + + - name: "Overdischarge SOC" + class: "battery" + state_class: "measurement" + uom: "%" + scale: 1 + rule: 1 + registers: [43011] + icon: "mdi:battery" + + - group: TimedCharge + items: + - name: "Timed Charge Current" + class: "" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [43141] + icon: "mdi:wrench-clock" + + - name: "Timed Discharge Current" + class: "" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [43142] + icon: "mdi:wrench-clock" + + - name: "Timed Charge Start Hour" + class: "" + state_class: "measurement" + uom: "H" + scale: 1 + rule: 1 + registers: [43143] + icon: "mdi:wrench-clock" + + - name: "Timed Charge Start Minute" + class: "" + state_class: "measurement" + uom: "M" + scale: 1 + rule: 1 + registers: [43144] + icon: "mdi:wrench-clock" + + - name: "Timed Charge End Hour" + class: "" + state_class: "measurement" + uom: "H" + scale: 1 + rule: 1 + registers: [43145] + icon: "mdi:wrench-clock" + + - name: "Timed Charge End Minute" + class: "" + state_class: "measurement" + uom: "M" + scale: 1 + rule: 1 + registers: [43146] + icon: "mdi:wrench-clock" + + - name: "Timed Discharge Start Hour" + class: "" + state_class: "measurement" + uom: "H" + scale: 1 + rule: 1 + registers: [43147] + icon: "mdi:wrench-clock" + + - name: "Timed Discharge Start Minute" + class: "" + state_class: "measurement" + uom: "M" + scale: 1 + rule: 1 + registers: [43148] + icon: "mdi:wrench-clock" + + - name: "Timed Discharge End Hour" + class: "" + state_class: "measurement" + uom: "H" + scale: 1 + rule: 1 + registers: [43149] + icon: "mdi:wrench-clock" + + - name: "Timed Discharge End Minute" + class: "" + state_class: "measurement" + uom: "M" + scale: 1 + rule: 1 + registers: [43150] + icon: "mdi:wrench-clock" diff --git a/custom_components/solarman/inverter_definitions/solis_s6-gr1p.yaml b/custom_components/solarman/inverter_definitions/solis_s6-gr1p.yaml index 580d1f7..62be8c4 100644 --- a/custom_components/solarman/inverter_definitions/solis_s6-gr1p.yaml +++ b/custom_components/solarman/inverter_definitions/solis_s6-gr1p.yaml @@ -1,318 +1,323 @@ +# # Solis S6-GR1P4.6K Configuration # NH-Networks 2023 # + +default: + update_interval: 5 + digits: 6 + requests: - start: 2999 - end: 3024 + end: 3024 mb_functioncode: 0x04 - start: 3035 - end: 3043 + end: 3043 mb_functioncode: 0x04 - start: 3071 - end: 3071 + end: 3071 mb_functioncode: 0x04 parameters: - - group: InverterStatus - items: - - name: "Inverter Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [3043] - icon: 'mdi:home-lightning-bolt' - lookup: - - key: 0x0 - value: "Waiting State" - - key: 0x1 - value: "Open Loop Operation" - - key: 0x2 - value: "Soft Start" - - key: 0x3 - value: "On Grid/Generating" - - key: 0x1004 - value: "Grid OverVoltage" - - key: 0x1010 - value: "Grid UnderVoltage" - - key: 0x1012 - value: "Grid OverFrequency" - - key: 0x1013 - value: "Grid UnderFrequency" - - key: 0x1014 - value: "Grid Imp too large" - - key: 0x1015 - value: "No Grid" - - key: 0x1016 - value: "Grid Imbalance" - - key: 0x1017 - value: "Grid Freq Jitter" - - key: 0x1018 - value: "Grid Overcurrent" - - key: 0x1019 - value: "Grid Tracking Fault" - - key: 0x1020 - value: "DC OverVoltage" - - key: 0x1021 - value: "DC Bus Overvoltage" - - key: 0x1022 - value: "DC Bus Uneven Voltage" - - key: 0x1024 - value: "DC Bus Uneven Voltage2" - - key: 0x1025 - value: "DC A path OverCurrent" - - key: 0x1026 - value: "DC B path OverCurrent" - - key: 0x1027 - value: "DC Input Disturbance" - - key: 0x1030 - value: "Grid Disturbance" - - key: 0x1031 - value: "DSP Initialization Protection " - - key: 0x1032 - value: "Over Temp Protection" - - key: 0x1033 - value: "PV Insulation Fault" - - key: 0x1034 - value: "Leakage Current Protection" - - key: 0x1035 - value: "Relay Detection Protection" - - key: 0x1036 - value: "DSP_B Protection" - - key: 0x1037 - value: "DC Component too Large" - - key: 0x1038 - value: "12v UnderVoltage Protection" - - key: 0x1039 - value: "Under Temperature Protection" - - key: 0x1040 - value: "Arc Self-Test Protection" - - key: 0x1041 - value: "Arc Protection" - - key: 0x1042 - value: "DSP on-chip SRAM exception" - - key: 0x1043 - value: "DSP on-chip FLASH exception" - - key: 0x1044 - value: "DSP on-chip PC pointer is abnormal" - - key: 0x1045 - value: "DSP key register exception" - - key: 0x1046 - value: "Grid disturbance 02" - - key: 0x1047 - value: "Grid current sampling abnormality" - - key: 0x1048 - value: "IGBT overcurrent" - - key: 0x1050 - value: "Network current transient overcurrent" - - key: 0x1051 - value: "Battery overvoltage hardware failure" - - key: 0x1052 - value: "LLC hardware overcurrent" - - key: 0x1053 - value: "Battery overvoltage detection" - - key: 0x1054 - value: "Battery undervoltage detection" - - key: 0x1055 - value: "Battery no connected" - - key: 0x1056 - value: "Bypass overvoltage fault" - - key: 0x1057 - value: "Bypass overload fault" + - group: InverterStatus + items: + - name: "Inverter Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [3043] + icon: "mdi:home-lightning-bolt" + lookup: + - key: 0x0 + value: "Waiting State" + - key: 0x1 + value: "Open Loop Operation" + - key: 0x2 + value: "Soft Start" + - key: 0x3 + value: "On Grid/Generating" + - key: 0x1004 + value: "Grid OverVoltage" + - key: 0x1010 + value: "Grid UnderVoltage" + - key: 0x1012 + value: "Grid OverFrequency" + - key: 0x1013 + value: "Grid UnderFrequency" + - key: 0x1014 + value: "Grid Imp too large" + - key: 0x1015 + value: "No Grid" + - key: 0x1016 + value: "Grid Imbalance" + - key: 0x1017 + value: "Grid Freq Jitter" + - key: 0x1018 + value: "Grid Overcurrent" + - key: 0x1019 + value: "Grid Tracking Fault" + - key: 0x1020 + value: "DC OverVoltage" + - key: 0x1021 + value: "DC Bus Overvoltage" + - key: 0x1022 + value: "DC Bus Uneven Voltage" + - key: 0x1024 + value: "DC Bus Uneven Voltage2" + - key: 0x1025 + value: "DC A path OverCurrent" + - key: 0x1026 + value: "DC B path OverCurrent" + - key: 0x1027 + value: "DC Input Disturbance" + - key: 0x1030 + value: "Grid Disturbance" + - key: 0x1031 + value: "DSP Initialization Protection " + - key: 0x1032 + value: "Over Temp Protection" + - key: 0x1033 + value: "PV Insulation Fault" + - key: 0x1034 + value: "Leakage Current Protection" + - key: 0x1035 + value: "Relay Detection Protection" + - key: 0x1036 + value: "DSP_B Protection" + - key: 0x1037 + value: "DC Component too Large" + - key: 0x1038 + value: "12v UnderVoltage Protection" + - key: 0x1039 + value: "Under Temperature Protection" + - key: 0x1040 + value: "Arc Self-Test Protection" + - key: 0x1041 + value: "Arc Protection" + - key: 0x1042 + value: "DSP on-chip SRAM exception" + - key: 0x1043 + value: "DSP on-chip FLASH exception" + - key: 0x1044 + value: "DSP on-chip PC pointer is abnormal" + - key: 0x1045 + value: "DSP key register exception" + - key: 0x1046 + value: "Grid disturbance 02" + - key: 0x1047 + value: "Grid current sampling abnormality" + - key: 0x1048 + value: "IGBT overcurrent" + - key: 0x1050 + value: "Network current transient overcurrent" + - key: 0x1051 + value: "Battery overvoltage hardware failure" + - key: 0x1052 + value: "LLC hardware overcurrent" + - key: 0x1053 + value: "Battery overvoltage detection" + - key: 0x1054 + value: "Battery undervoltage detection" + - key: 0x1055 + value: "Battery no connected" + - key: 0x1056 + value: "Bypass overvoltage fault" + - key: 0x1057 + value: "Bypass overload fault" - - name: "Operating Status" - class: "" - state_class: "" - uom: "" - scale: 1 - rule: 1 - registers: [3071] - icon: 'mdi:home-lightning-bolt' - lookup: - - key: 0x1 - value: "Normal Operation" - - key: 0x2 - value: "Initial Standby" - - key: 0x4 - value: "Control Shutdown" - - key: 0x8 - value: "Downtime" - - key: 0x10 - value: "Standby" - - key: 0x20 - value: "Derating Operation" - - key: 0x40 - value: "Limit Operation" - - key: 0x80 - value: "Bypass Overload" + - name: "Operating Status" + class: "" + state_class: "" + uom: "" + scale: 1 + rule: 1 + registers: [3071] + icon: "mdi:home-lightning-bolt" + lookup: + - key: 0x1 + value: "Normal Operation" + - key: 0x2 + value: "Initial Standby" + - key: 0x4 + value: "Control Shutdown" + - key: 0x8 + value: "Downtime" + - key: 0x10 + value: "Standby" + - key: 0x20 + value: "Derating Operation" + - key: 0x40 + value: "Limit Operation" + - key: 0x80 + value: "Bypass Overload" - - name: "Inverter Temperature" - class: "temperature" - state_class: "measurement" - uom: "°C" - scale: 0.1 - rule: 2 - registers: [3041] - icon: 'mdi:thermometer' - -# Sensors below are outside of modbus request ranges. -# If enabling, ensure to amend the request start register. -# - name: "Inverter ID" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 5 -# registers: [33004,33005,33006,33007,33008,33009,33010,33011,33012,33013,33014,33015,33016,33017,33018,33019] -# isstr: true + - name: "Inverter Temperature" + class: "temperature" + state_class: "measurement" + uom: "°C" + scale: 0.1 + rule: 2 + registers: [3041] + icon: "mdi:thermometer" -# - name: "Product Model" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 6 -# registers: [2999] -# isstr: true + # Sensors below are outside of modbus request ranges. + # If enabling, ensure to amend the request start register. + # - name: "Inverter ID" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 5 + # registers: [33004,33005,33006,33007,33008,33009,33010,33011,33012,33013,33014,33015,33016,33017,33018,33019] + # isstr: true -# - name: "DSP Software Version" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 6 -# registers: [3000] -# isstr: true + # - name: "Product Model" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 6 + # registers: [2999] + # isstr: true -# - name: "LCD Software Version" -# class: "" -# state_class: "" -# uom: "" -# scale: 1 -# rule: 6 -# registers: [3001] -# isstr: true + # - name: "DSP Software Version" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 6 + # registers: [3000] + # isstr: true - - group: InverterDC - items: - - name: "PV1 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3021] - icon: 'mdi:solar-power' + # - name: "LCD Software Version" + # class: "" + # state_class: "" + # uom: "" + # scale: 1 + # rule: 6 + # registers: [3001] + # isstr: true - - name: "PV2 Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3023] - icon: 'mdi:solar-power' + - group: InverterDC + items: + - name: "PV1 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3021] + icon: "mdi:solar-power" - - name: "PV1 Current" - class: "current" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3022] - icon: 'mdi:current-dc' + - name: "PV2 Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3023] + icon: "mdi:solar-power" - - name: "PV2 Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3024] - icon: 'mdi:current-dc' + - name: "PV1 Current" + class: "current" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3022] + icon: "mdi:current-dc" - - name: "Total DC Power" - class: "power" - state_class: "measurement" - uom: "kW" - scale: 0.001 - rule: 3 - registers: [3007, 3006] - icon: 'mdi:solar-power' + - name: "PV2 Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3024] + icon: "mdi:current-dc" - - group: InverterAC - items: - - name: "Inverter AC Power" - class: "power" - state_class: "measurement" - uom: "W" - scale: 1 - rule: 1 - registers: [3005, 3004] - icon: 'mdi:solar-power' + - name: "Total DC Power" + class: "power" + state_class: "measurement" + uom: "kW" + scale: 0.001 + rule: 3 + registers: [3007, 3006] + icon: "mdi:solar-power" - - name: "Inverter Voltage" - class: "voltage" - state_class: "measurement" - uom: "V" - scale: 0.1 - rule: 1 - registers: [3035] - icon: 'mdi:transmission-tower' + - group: InverterAC + items: + - name: "Inverter AC Power" + class: "power" + state_class: "measurement" + uom: "W" + scale: 1 + rule: 1 + registers: [3005, 3004] + icon: "mdi:solar-power" - - name: "Inverter Current" - class: "current" - state_class: "measurement" - uom: "A" - scale: 0.1 - rule: 1 - registers: [3038] - icon: 'mdi:current-ac' + - name: "Inverter Voltage" + class: "voltage" + state_class: "measurement" + uom: "V" + scale: 0.1 + rule: 1 + registers: [3035] + icon: "mdi:transmission-tower" - - name: "Inverter Frequency" - class: "frequency" - state_class: "measurement" - uom: "Hz" - scale: 0.01 - rule: 1 - registers: [3042] - icon: 'mdi:sine-wave' + - name: "Inverter Current" + class: "current" + state_class: "measurement" + uom: "A" + scale: 0.1 + rule: 1 + registers: [3038] + icon: "mdi:current-ac" - - group: Generation - items: - - name: "Daily Generation" - class: "energy" - state_class: "measurement" - uom: "kWh" - scale: 0.1 - rule: 1 - registers: [3014] - icon: 'mdi:solar-power' + - name: "Inverter Frequency" + class: "frequency" + state_class: "measurement" + uom: "Hz" + scale: 0.01 + rule: 1 + registers: [3042] + icon: "mdi:sine-wave" - - name: "Monthly Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3011, 3010] - icon: 'mdi:solar-power' + - group: Generation + items: + - name: "Daily Generation" + class: "energy" + state_class: "measurement" + uom: "kWh" + scale: 0.1 + rule: 1 + registers: [3014] + icon: "mdi:solar-power" - - name: "Yearly Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3017, 3016] - icon: 'mdi:solar-power' + - name: "Monthly Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3011, 3010] + icon: "mdi:solar-power" - - name: "Total Generation" - class: "energy" - state_class: "total_increasing" - uom: "kWh" - scale: 1 - rule: 3 - registers: [3009, 3008] - icon: 'mdi:solar-power' + - name: "Yearly Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3017, 3016] + icon: "mdi:solar-power" + - name: "Total Generation" + class: "energy" + state_class: "total_increasing" + uom: "kWh" + scale: 1 + rule: 3 + registers: [3009, 3008] + icon: "mdi:solar-power" diff --git a/custom_components/solarman/inverter_definitions/zcs_azzurro-ktl-v3.yaml b/custom_components/solarman/inverter_definitions/zcs_azzurro-ktl-v3.yaml index 3ce74e0..ab7c460 100644 --- a/custom_components/solarman/inverter_definitions/zcs_azzurro-ktl-v3.yaml +++ b/custom_components/solarman/inverter_definitions/zcs_azzurro-ktl-v3.yaml @@ -1,10 +1,11 @@ +# # ZCS Azzurro 3-phase non-hybrid inverters # with LSW-3 WiFi logger with SN 23xxxxxxxx and FW LSW3_15_270A_1.53: # 3PH 3.3KTL-V3 # 3PH 4.4KTL-V3 # 3PH 5.5KTL-V3 # 3PH 6.6KTL-V3 - +# # Not tested, but could probably work: # ZCS Azzurro 3PH 8.8KTL-V3 # ZCS Azzurro 3PH 11KTL-V3 @@ -15,6 +16,11 @@ # SOFAR Solar 8.8KTLX-G3 # SOFAR Solar 11KTLX-G3 # SOFAR Solar 12KTLX-G3 +# + +default: + update_interval: 10 + digits: 6 requests: - start: 0x0400 From 009e08a69c88b160aa9de9da5b7f8d95e7133462 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 17:17:46 +0200 Subject: [PATCH 33/39] feat: Added Program X SOC configuration items feat: Multiple attempts when trying to write into registers --- custom_components/solarman/api.py | 56 ++++++++---- custom_components/solarman/const.py | 3 +- .../inverter_definitions/deye_sg01hp3.yaml | 91 ++++++++++++++++++- .../inverter_definitions/deye_sg04lp3.yaml | 91 ++++++++++++++++++- .../deye_sun-12k-sg04lp3.yaml | 88 +++++++++++++++++- custom_components/solarman/number.py | 17 ++-- custom_components/solarman/switch.py | 1 + 7 files changed, 310 insertions(+), 37 deletions(-) diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index e153a45..c638042 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -221,26 +221,42 @@ async def async_get(self, runtime = 0): async def service_write_holding_register(self, register, value) -> bool: _LOGGER.debug(f"service_write_holding_register: {register}, value: {value}") - try: - await self.async_connect() - response = await self.write_holding_register(register, value) - _LOGGER.debug(f"service_write_holding_register: {register}, response: {response}") - except Exception as e: - _LOGGER.warning(f"service_write_holding_register: {register}, value: {value} failed. [{format_exception(e)}]") - if not self.auto_reconnect: - await self.async_disconnect() - raise - return True + + attempts_left = ACTION_RETRY_ATTEMPTS + while attempts_left > 0: + attempts_left -= 1 + + try: + await self.async_connect() + response = await self.write_holding_register(register, value) + _LOGGER.debug(f"service_write_holding_register: {register}, response: {response}") + return True + except Exception as e: + _LOGGER.warning(f"service_write_holding_register: {register}, value: {value} failed, attempts left: {attempts_left}. [{format_exception(e)}]") + if not self.auto_reconnect: + await self.async_disconnect() + if not attempts_left > 0: + raise + + await asyncio.sleep(TIMINGS_WRITE_EXCEPT_SLEEP) async def service_write_multiple_holding_registers(self, register, values) -> bool: _LOGGER.debug(f"service_write_multiple_holding_registers: {register}, values: {values}") - try: - await self.async_connect() - response = await self.write_multiple_holding_registers(register, values) - _LOGGER.debug(f"service_write_multiple_holding_register: {register}, response: {response}") - except Exception as e: - _LOGGER.warning(f"service_write_multiple_holding_registers: {register}, values: {values} failed. [{format_exception(e)}]") - if not self.auto_reconnect: - await self.async_disconnect() - raise - return True + + attempts_left = ACTION_RETRY_ATTEMPTS + while attempts_left > 0: + attempts_left -= 1 + + try: + await self.async_connect() + response = await self.write_multiple_holding_registers(register, values) + _LOGGER.debug(f"service_write_multiple_holding_register: {register}, response: {response}") + return True + except Exception as e: + _LOGGER.warning(f"service_write_multiple_holding_registers: {register}, values: {values} failed, attempts left: {attempts_left}. [{format_exception(e)}]") + if not self.auto_reconnect: + await self.async_disconnect() + if not attempts_left > 0: + raise + + await asyncio.sleep(TIMINGS_WRITE_EXCEPT_SLEEP) diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index e7fb2bb..bb15011 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -42,9 +42,10 @@ TIMINGS_INTERVAL = 5 TIMINGS_UPDATE_INTERVAL = td(seconds = TIMINGS_INTERVAL) TIMINGS_UPDATE_TIMEOUT = TIMINGS_INTERVAL * 6 -TIMINGS_SOCKET_TIMEOUT = TIMINGS_INTERVAL * 3 - 1 +TIMINGS_SOCKET_TIMEOUT = TIMINGS_INTERVAL * 3 TIMINGS_QUERY_INTERVAL_DEFAULT = 60 TIMINGS_QUERY_EXCEPT_SLEEP = 3 +TIMINGS_WRITE_EXCEPT_SLEEP = 1 REGISTERS_MIN_SPAN_DEFAULT = 25 REGISTERS_DIGITS_DEFAULT = 6 diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 6a00aad..9b3fbd7 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -387,18 +387,101 @@ parameters: - key: "default" value: "On" - - group: Solar Sell + - group: Work Mode items: - - name: "Solar Sell" + - name: Export Surplus update_interval: 30 - class: "" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 - switch: True registers: [0x0091] + - name: Program 1 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A6] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 2 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A7] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 3 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A8] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 4 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A9] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 5 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00AA] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 6 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00AB] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + - group: BMS items: - name: "BMS Charging Voltage" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index 8a95d79..a098e1e 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -393,18 +393,101 @@ parameters: - key: "default" value: "On" - - group: Solar Sell + - group: Work Mode items: - - name: "Solar Sell" + - name: Export Surplus update_interval: 30 - class: "" + class: "switch" state_class: "" uom: "" scale: 1 rule: 1 - switch: True registers: [0x0091] + - name: Program 1 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A6] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 2 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A7] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 3 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A8] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 4 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A9] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 5 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00AA] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 6 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00AB] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + - group: BMS items: - name: "BMS Charged Voltage" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index b2907da..d6ef444 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -395,9 +395,9 @@ parameters: - key: "default" value: "On" - - group: Solar Sell + - group: Work Mode items: - - name: "Solar Sell" + - name: Export Surplus update_interval: 30 class: "switch" state_class: "" @@ -406,6 +406,90 @@ parameters: rule: 1 registers: [0x0091] + - name: Program 1 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A6] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 2 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A7] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 3 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A8] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 4 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00A9] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 5 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00AA] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + + - name: Program 6 SOC + update_interval: 30 + class: "" + state_class: measurement + uom: "%" + scale: 1 + rule: 1 + registers: [0x00AB] + configurable: + range: + min: 0 + max: 100 + icon: mdi:sun-clock + - group: BMS items: - name: "BMS Charged Voltage" diff --git a/custom_components/solarman/number.py b/custom_components/solarman/number.py index 6666c99..8ad2594 100644 --- a/custom_components/solarman/number.py +++ b/custom_components/solarman/number.py @@ -68,12 +68,17 @@ def __init__(self, coordinator, sensor): _LOGGER.warning(f"SolarmanNumberEntity.__init__: Contains more than 1 register!") configurable = sensor["configurable"] - if "min" in configurable: - self._attr_native_min_value = configurable["min"] - if "max" in configurable: - self._attr_native_max_value = configurable["max"] - if "step" in configurable: - self._attr_native_step = configurable["step"] + if configurable: + if "min" in configurable: + self._attr_native_min_value = configurable["min"] + if "max" in configurable: + self._attr_native_max_value = configurable["max"] + if "step" in configurable: + self._attr_native_step = configurable["step"] + elif "range" in sensor: + range = sensor["range"] + self._attr_native_min_value = range["min"] + self._attr_native_max_value = range["max"] @property def native_value(self) -> float: diff --git a/custom_components/solarman/switch.py b/custom_components/solarman/switch.py index b1bcca3..cec6011 100644 --- a/custom_components/solarman/switch.py +++ b/custom_components/solarman/switch.py @@ -4,6 +4,7 @@ import asyncio import voluptuous as vol +from typing import Any from functools import cached_property, partial from homeassistant.config_entries import ConfigEntry From 0549e5435b4ca5bda29d348f750ab0a0a2f8014a Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 19:09:15 +0200 Subject: [PATCH 34/39] chore: readme.md --- readme.md | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/readme.md b/readme.md index 5146764..2939ea7 100644 --- a/readme.md +++ b/readme.md @@ -1,10 +1,15 @@ # ⚡ Solarman Stick Logger integration -[![Stable](https://img.shields.io/github/release/davidrapan/ha-solarman.svg)](https://github.com/davidrapan/ha-solarman/releases/latest) -[![GitHub Activity](https://img.shields.io/github/commit-activity/y/davidrapan/ha-solarman.svg?label=commits)](https://github.com/davidrapan/ha-solarman/commits/main) -[![License](https://img.shields.io/github/license/davidrapan/ha-solarman.svg)](LICENSE) -[![HACS Supported](https://img.shields.io/badge/HACS-Supported-green.svg)](https://github.com/custom-components/hacs) -[![Discussions](https://img.shields.io/badge/community-discussions-brightgreen.svg)](https://github.com/davidrapan/ha-solarman/discussions) +[![Stable](https://img.shields.io/github/release/davidrapan/ha-solarman)](https://github.com/davidrapan/ha-solarman/releases/latest) +[![GitHub Activity](https://img.shields.io/github/commit-activity/y/davidrapan/ha-solarman?label=commits)](https://github.com/davidrapan/ha-solarman/commits/main) +[![License](https://img.shields.io/github/license/davidrapan/ha-solarman)](LICENSE) +[![HACS Supported](https://img.shields.io/badge/HACS-Supported-green)](https://github.com/custom-components/hacs) +[![Discussions](https://img.shields.io/badge/community-discussions-brightgreen)](https://github.com/davidrapan/ha-solarman/discussions) +[![Wiki](https://img.shields.io/badge/wiki-8A2BE2)](https://github.com/davidrapan/ha-solarman/wiki) + +#### Signpost +- [Automations](https://github.com/davidrapan/ha-solarman/wiki/Automations) +- [Sensor renaming](https://github.com/davidrapan/ha-solarman/wiki/Naming-Scheme-%E2%80%90-sensor-renaming) > [!NOTE] > If you are curious about what's planned next look into [🪧 Milestones](https://github.com/davidrapan/ha-solarman/milestones) @@ -18,6 +23,7 @@ > This integration builds on and is heavily inspired by [@StephanJoubert](https://github.com/StephanJoubert/home_assistant_solarman) (but W/ decent amount of changes): > - Using asynchronous part of [@jmccrohan](https://github.com/jmccrohan/pysolarmanv5) + small adjustments to the inner workings of the library itself > - Fetching is implemented through DataUpdateCoordinator + incorporates many more up to date features of HA +> - Supports configuration of inverter parameters (Battery, Work Mode, ...) > - Improved stability (no more disconnects and missing values) > - Discovery and not just for configuration but also as part of initialization (i.e. adapts to changed IP) > - New Inverter profiles features **See 'deye_sg04lp3.yaml' for examples*: @@ -97,4 +103,4 @@ Maybe it will be useful for some, but since the stability of the polling improve - Find newly added Solarman, open it and then click on the DOWNLOAD button ### 🔧 Manually -- Copy the contents of 'custom_components/solarman' directory into the Home Assistant with exactly the same hirearchy withing the '/config' directory \ No newline at end of file +- Copy the contents of 'custom_components/solarman' directory into the Home Assistant with exactly the same hirearchy within the '/config' directory \ No newline at end of file From 709df972c5efffebab722c200b4b230cfad0b0b6 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 22:13:43 +0200 Subject: [PATCH 35/39] refactor: Added Grid prefix for Export Surplus --- .../solarman/inverter_definitions/deye_sg01hp3.yaml | 9 +++++++-- .../solarman/inverter_definitions/deye_sg04lp3.yaml | 9 +++++++-- .../inverter_definitions/deye_sun-12k-sg04lp3.yaml | 10 ++++++++-- custom_components/solarman/sensor.py | 6 ++++++ 4 files changed, 28 insertions(+), 6 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 9b3fbd7..6aa5a4f 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -207,7 +207,7 @@ parameters: step: 0.1 icon: "mdi:battery" - - name: "Zero Export power" + - name: "Grid Zero Export power" class: "power" state_class: "measurement" uom: "W" @@ -389,7 +389,8 @@ parameters: - group: Work Mode items: - - name: Export Surplus + - name: Grid Export Surplus + alt: Solar Sell update_interval: 30 class: "switch" state_class: "" @@ -1363,6 +1364,7 @@ parameters: # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" + desciption: Combined power of all three phases realtime: class: "measurement" state_class: "measurement" @@ -1610,6 +1612,7 @@ parameters: # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" + desciption: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1679,6 +1682,7 @@ parameters: # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "SmartLoad Power" + desciption: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1691,6 +1695,7 @@ parameters: items: # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" + desciption: Combined power of all inputs realtime: class: "power" state_class: "measurement" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index a098e1e..c8412bb 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -213,7 +213,7 @@ parameters: step: 0.1 icon: "mdi:battery" - - name: "Zero Export power" + - name: "Grid Zero Export power" class: "power" state_class: "measurement" uom: "W" @@ -395,7 +395,8 @@ parameters: - group: Work Mode items: - - name: Export Surplus + - name: Grid Export Surplus + alt: Solar Sell update_interval: 30 class: "switch" state_class: "" @@ -1369,6 +1370,7 @@ parameters: # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" + desciption: Combined power of all three phases realtime: class: "measurement" state_class: "measurement" @@ -1611,6 +1613,7 @@ parameters: # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" + desciption: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1680,6 +1683,7 @@ parameters: # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "SmartLoad Power" + desciption: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1692,6 +1696,7 @@ parameters: items: # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" + desciption: Combined power of all inputs realtime: class: "power" state_class: "measurement" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index d6ef444..7288d6f 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -215,7 +215,7 @@ parameters: step: 0.1 icon: "mdi:battery" - - name: "Zero Export power" + - name: "Grid Zero Export power" class: "power" state_class: "measurement" uom: "W" @@ -397,7 +397,8 @@ parameters: - group: Work Mode items: - - name: Export Surplus + - name: Grid Export Surplus + alt: Solar Sell update_interval: 30 class: "switch" state_class: "" @@ -1381,6 +1382,7 @@ parameters: # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" + desciption: Combined power of all three phases realtime: class: "measurement" state_class: "measurement" @@ -1392,6 +1394,7 @@ parameters: # Grid - The inverted power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power ∇" + desciption: Combined power of all three phases entity_id: "grid_power_inverted" realtime: class: "measurement" @@ -1636,6 +1639,7 @@ parameters: # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" + desciption: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1705,6 +1709,7 @@ parameters: # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "SmartLoad Power" + desciption: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1717,6 +1722,7 @@ parameters: items: # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" + desciption: Combined power of all inputs realtime: class: "power" state_class: "measurement" diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 4d9c9e3..9d80810 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -112,6 +112,12 @@ def __init__(self, coordinator, sensor, battery_nominal_voltage, battery_life_cy if "unit_of_measurement" in sensor and (unit_of_measurement := sensor["unit_of_measurement"]): self._attr_unit_of_measurement = unit_of_measurement + if "alt" in sensor and (alt := sensor["alt"]): + self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "Alt Name": alt } + + if "description" in sensor and (description := sensor["description"]): + self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "description": description } + if "options" in sensor and (options := sensor["options"]): self._attr_options = options self._attr_extra_state_attributes = self._attr_extra_state_attributes | { "options": options } From 049713adf0c276b646b0b8f0d98175333a87fe92 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Thu, 18 Jul 2024 23:53:45 +0200 Subject: [PATCH 36/39] fix: Inverter profiles typo --- .../solarman/inverter_definitions/deye_sg01hp3.yaml | 8 ++++---- .../solarman/inverter_definitions/deye_sg04lp3.yaml | 8 ++++---- .../inverter_definitions/deye_sun-12k-sg04lp3.yaml | 10 +++++----- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 6aa5a4f..0f1efab 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -1364,7 +1364,7 @@ parameters: # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "measurement" state_class: "measurement" @@ -1612,7 +1612,7 @@ parameters: # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1682,7 +1682,7 @@ parameters: # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "SmartLoad Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1695,7 +1695,7 @@ parameters: items: # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" - desciption: Combined power of all inputs + description: Combined power of all inputs realtime: class: "power" state_class: "measurement" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index c8412bb..b51f356 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -1370,7 +1370,7 @@ parameters: # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "measurement" state_class: "measurement" @@ -1613,7 +1613,7 @@ parameters: # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1683,7 +1683,7 @@ parameters: # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "SmartLoad Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1696,7 +1696,7 @@ parameters: items: # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" - desciption: Combined power of all inputs + description: Combined power of all inputs realtime: class: "power" state_class: "measurement" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index 7288d6f..ab0ba33 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -1382,7 +1382,7 @@ parameters: # Grid - The power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "measurement" state_class: "measurement" @@ -1394,7 +1394,7 @@ parameters: # Grid - The inverted power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Grid Power ∇" - desciption: Combined power of all three phases + description: Combined power of all three phases entity_id: "grid_power_inverted" realtime: class: "measurement" @@ -1639,7 +1639,7 @@ parameters: # Load - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "Load Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1709,7 +1709,7 @@ parameters: # SmartLoad/Generator - The Power is S16bit (low 16 bits) + S16bit (high 16 bits) - name: "SmartLoad Power" - desciption: Combined power of all three phases + description: Combined power of all three phases realtime: class: "power" state_class: "measurement" @@ -1722,7 +1722,7 @@ parameters: items: # PV - The combined power of Input 1 & 2 & 3 & 4 (L:1W, H:10W) - name: "PV Power" - desciption: Combined power of all inputs + description: Combined power of all inputs realtime: class: "power" state_class: "measurement" From 7f44389fc0ca4d602231f550cd9aa78a5c87b928 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Fri, 19 Jul 2024 00:07:52 +0200 Subject: [PATCH 37/39] chore: Added some sensor descriptions fix: Battery state to enum --- .../solarman/inverter_definitions/deye_sg01hp3.yaml | 11 +++++++++-- .../solarman/inverter_definitions/deye_sg04lp3.yaml | 11 +++++++++-- .../inverter_definitions/deye_sun-12k-sg04lp3.yaml | 10 +++++++++- 3 files changed, 27 insertions(+), 5 deletions(-) diff --git a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml index 0f1efab..e6b92e0 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg01hp3.yaml @@ -735,6 +735,7 @@ parameters: icon: "mdi:battery-minus" - name: "Today Battery Life Cycles" + description: Calculates today's battery life cycles based on today's charged amount class: "" state_class: "total_increasing" uom: "" @@ -744,6 +745,7 @@ parameters: icon: "mdi:battery-sync" - name: "Total Battery Life Cycles" + description: Calculates total battery life cycles based on total charged amount class: "" state_class: "total_increasing" uom: "" @@ -805,6 +807,7 @@ parameters: registers: [0x020F, 0x0210] - name: "Today Losses" + description: Includes today's consumption of the inverter device itself as well AC/DC conversion losses class: "energy" state_class: "total_increasing" uom: "kWh" @@ -829,6 +832,7 @@ parameters: registers: [0x0202] - name: "Total Losses" + description: Includes total consumption of the inverter device itself as well AC/DC conversion losses class: "energy" state_class: "total_increasing" uom: "kWh" @@ -1106,6 +1110,7 @@ parameters: # Battery - The state of health - name: "Battery SOH" + description: Calculates state of health based on total charged amount class: "" state_class: "measurement" uom: "%" @@ -1116,12 +1121,13 @@ parameters: # Battery - The state of battery - name: "Battery State" - class: "" + description: Determines battery state from battery power by +-50 W + class: "enum" state_class: "" uom: "" scale: 1 rule: 0 - digits: 2 + options: ["charging", "standby", "discharging"] icon: "mdi:battery" # Battery - The current of battery 1 is S16bit (low 16 bits) @@ -1472,6 +1478,7 @@ parameters: # Inverter - Includes consumption of the inverter device itself as well AC/DC conversion losses - name: "Power losses" + description: Includes consumption of the inverter device itself as well AC/DC conversion losses class: "power" state_class: "measurement" uom: "W" diff --git a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml index b51f356..16370da 100644 --- a/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sg04lp3.yaml @@ -741,6 +741,7 @@ parameters: icon: "mdi:battery-minus" - name: "Daily Battery Life Cycles" + description: Calculates today's battery life cycles based on today's charged amount class: "" state_class: "total_increasing" uom: "" @@ -750,6 +751,7 @@ parameters: icon: "mdi:battery-sync" - name: "Total Battery Life Cycles" + description: Calculates total battery life cycles based on total charged amount class: "" state_class: "total_increasing" uom: "" @@ -811,6 +813,7 @@ parameters: registers: [0x020F, 0x0210] - name: "Daily Losses" + description: Includes today's consumption of the inverter device itself as well AC/DC conversion losses class: "energy" state_class: "total_increasing" uom: "kWh" @@ -835,6 +838,7 @@ parameters: registers: [0x0202] - name: "Total Losses" + description: Includes total consumption of the inverter device itself as well AC/DC conversion losses class: "energy" state_class: "total_increasing" uom: "kWh" @@ -1112,6 +1116,7 @@ parameters: # Battery - The state of health - name: "Battery SOH" + description: Calculates state of health based on total charged amount class: "" state_class: "measurement" uom: "%" @@ -1122,12 +1127,13 @@ parameters: # Battery - The state of battery - name: "Battery State" - class: "" + description: Determines battery state from battery power by +-50 W + class: "enum" state_class: "" uom: "" scale: 1 rule: 0 - digits: 2 + options: ["charging", "standby", "discharging"] icon: "mdi:battery" # Battery - The current of battery 1 is S16bit (low 16 bits) @@ -1478,6 +1484,7 @@ parameters: # Inverter - Includes consumption of the inverter device itself as well AC/DC conversion losses - name: "Power losses" + description: Includes consumption of the inverter device itself as well AC/DC conversion losses class: "power" state_class: "measurement" uom: "W" diff --git a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml index ab0ba33..8481815 100644 --- a/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml +++ b/custom_components/solarman/inverter_definitions/deye_sun-12k-sg04lp3.yaml @@ -743,6 +743,7 @@ parameters: icon: "mdi:battery-minus" - name: "Today Battery Life Cycles" + description: Calculates today's battery life cycles based on today's charged amount class: "" state_class: "total_increasing" uom: "" @@ -752,6 +753,7 @@ parameters: icon: "mdi:battery-sync" - name: "Total Battery Life Cycles" + description: Calculates total battery life cycles based on total charged amount class: "" state_class: "total_increasing" uom: "" @@ -813,6 +815,7 @@ parameters: registers: [0x020F, 0x0210] - name: "Today Losses" + description: Includes today's consumption of the inverter device itself as well AC/DC conversion losses class: "energy" state_class: "total_increasing" uom: "kWh" @@ -837,6 +840,7 @@ parameters: registers: [0x0202] - name: "Total Losses" + description: Includes total consumption of the inverter device itself as well AC/DC conversion losses class: "energy" state_class: "total_increasing" uom: "kWh" @@ -1125,6 +1129,7 @@ parameters: # Battery - The state of health - name: "Battery SOH" + description: Calculates state of health based on total charged amount class: "" state_class: "measurement" uom: "%" @@ -1135,11 +1140,13 @@ parameters: # Battery - The state of battery - name: "Battery State" - class: "" + description: Determines battery state from battery power by +-50 W + class: "enum" state_class: "" uom: "" scale: 1 rule: 0 + options: ["charging", "standby", "discharging"] icon: "mdi:battery" # Battery - The current of battery 1 is S16bit (low 16 bits) @@ -1504,6 +1511,7 @@ parameters: # Inverter - Includes consumption of the inverter device itself as well AC/DC conversion losses - name: "Power losses" + description: Includes consumption of the inverter device itself as well AC/DC conversion losses class: "power" state_class: "measurement" uom: "W" From 78bf0b6750f4fa1f6d8577cd097a85f4696a23b5 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Fri, 19 Jul 2024 00:35:35 +0200 Subject: [PATCH 38/39] chore: readme.md --- readme.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/readme.md b/readme.md index 2939ea7..e9b68b7 100644 --- a/readme.md +++ b/readme.md @@ -1,4 +1,4 @@ -# ⚡ Solarman Stick Logger integration +# ⚡ Solarman Stick Logger [![Stable](https://img.shields.io/github/release/davidrapan/ha-solarman)](https://github.com/davidrapan/ha-solarman/releases/latest) [![GitHub Activity](https://img.shields.io/github/commit-activity/y/davidrapan/ha-solarman?label=commits)](https://github.com/davidrapan/ha-solarman/commits/main) @@ -9,6 +9,7 @@ #### Signpost - [Automations](https://github.com/davidrapan/ha-solarman/wiki/Automations) +- [Custom sensors](https://github.com/davidrapan/ha-solarman/wiki/Custom-sensors) - [Sensor renaming](https://github.com/davidrapan/ha-solarman/wiki/Naming-Scheme-%E2%80%90-sensor-renaming) > [!NOTE] From 1f6f61210336df4522ae1383cff85297aca613f1 Mon Sep 17 00:00:00 2001 From: David Rapan Date: Fri, 19 Jul 2024 01:33:52 +0200 Subject: [PATCH 39/39] feat: Silence Host is Unreachable --- custom_components/solarman/api.py | 7 +++---- custom_components/solarman/const.py | 8 ++++---- custom_components/solarman/parser.py | 6 +++--- custom_components/solarman/sensor.py | 2 +- 4 files changed, 11 insertions(+), 12 deletions(-) diff --git a/custom_components/solarman/api.py b/custom_components/solarman/api.py index c638042..8d7804d 100644 --- a/custom_components/solarman/api.py +++ b/custom_components/solarman/api.py @@ -72,9 +72,8 @@ async def _send_receive_v5_frame(self, data_logging_stick_frame): raise except OSError as e: if e.errno == errno.EHOSTUNREACH: - self.log.debug("[%s] EHOSTUNREACH error: %s", self.serial, e) - self.log.debug("[%s] Send/Receive error: %s", self.serial, e) - raise TimeoutError() + raise TimeoutError from e + raise except Exception as e: self.log.exception("[%s] Send/Receive error: %s", self.serial, e) raise @@ -194,7 +193,7 @@ async def async_get(self, runtime = 0): except (V5FrameError, TimeoutError, Exception) as e: result = 0 - if not isinstance(e, TimeoutError) or not attempts_left >= 1 or _LOGGER.isEnabledFor(logging.DEBUG): + if ((not isinstance(e, TimeoutError) or not attempts_left >= 1) and not (not isinstance(e, TimeoutError) or (e.__cause__ and isinstance(e.__cause__, OSError) and e.__cause__.errno == errno.EHOSTUNREACH))) or _LOGGER.isEnabledFor(logging.DEBUG): _LOGGER.warning(f"Querying ({start} - {end}) failed. #{runtime} [{format_exception(e)}]") await asyncio.sleep(TIMINGS_QUERY_EXCEPT_SLEEP) diff --git a/custom_components/solarman/const.py b/custom_components/solarman/const.py index bb15011..35b241c 100644 --- a/custom_components/solarman/const.py +++ b/custom_components/solarman/const.py @@ -35,6 +35,10 @@ DEFAULT_BATTERY_NOMINAL_VOLTAGE = 48 DEFAULT_BATTERY_LIFE_CYCLE_RATING = 6000 +DEFAULT_DIGITS = 6 +DEFAULT_REGISTERS_UPDATE_INTERVAL = 60 +DEFAULT_REGISTERS_MIN_SPAN = 25 + AUTO_RECONNECT = True ACTION_RETRY_ATTEMPTS = 5 @@ -43,13 +47,9 @@ TIMINGS_UPDATE_INTERVAL = td(seconds = TIMINGS_INTERVAL) TIMINGS_UPDATE_TIMEOUT = TIMINGS_INTERVAL * 6 TIMINGS_SOCKET_TIMEOUT = TIMINGS_INTERVAL * 3 -TIMINGS_QUERY_INTERVAL_DEFAULT = 60 TIMINGS_QUERY_EXCEPT_SLEEP = 3 TIMINGS_WRITE_EXCEPT_SLEEP = 1 -REGISTERS_MIN_SPAN_DEFAULT = 25 -REGISTERS_DIGITS_DEFAULT = 6 - REQUEST_CODE = "code" REQUEST_CODE_ALT = "mb_functioncode" REQUEST_START = "start" diff --git a/custom_components/solarman/parser.py b/custom_components/solarman/parser.py index fadab8f..5738746 100644 --- a/custom_components/solarman/parser.py +++ b/custom_components/solarman/parser.py @@ -12,9 +12,9 @@ class ParameterParser: def __init__(self, parameter_definition): self._lookups = parameter_definition - self._update_interval = TIMINGS_QUERY_INTERVAL_DEFAULT - self._min_span = REGISTERS_MIN_SPAN_DEFAULT - self._digits = REGISTERS_DIGITS_DEFAULT + self._update_interval = DEFAULT_REGISTERS_UPDATE_INTERVAL + self._min_span = DEFAULT_REGISTERS_MIN_SPAN + self._digits = DEFAULT_DIGITS self._result = {} if "default" in parameter_definition: diff --git a/custom_components/solarman/sensor.py b/custom_components/solarman/sensor.py index 9d80810..6743317 100644 --- a/custom_components/solarman/sensor.py +++ b/custom_components/solarman/sensor.py @@ -92,7 +92,7 @@ def __init__(self, coordinator, sensor, battery_nominal_voltage, battery_life_cy if "state_class" in sensor and sensor["state_class"]: self._attr_extra_state_attributes = { "state_class": sensor["state_class"] } - self._digits = sensor["digits"] if "digits" in sensor else REGISTERS_DIGITS_DEFAULT + self._digits = sensor["digits"] if "digits" in sensor else DEFAULT_DIGITS self._attr_entity_category = (None)