From bb426748f94f0970d977237c06c6da2111738321 Mon Sep 17 00:00:00 2001 From: Mark Vandersteen Date: Sun, 29 May 2022 13:26:54 +1000 Subject: [PATCH] Fix to inverter_model and addition of async_scan --- README.md | 10 +++---- setup.cfg | 2 +- sungrowinverter/SungrowInverter.py | 41 ++++++++++++++++++++++++----- sungrowinverter/configs/hybrid.py | 6 +++-- sungrowinverter/configs/inverter.py | 1 - test.py | 4 +-- 6 files changed, 47 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index 351db84..910f9f6 100644 --- a/README.md +++ b/README.md @@ -87,7 +87,7 @@ timeout: tcp connection is timed out and fails after this long ### Methods -Available methods and how to use +Available methods `client.inverter_model()` Returns a object of sungrowinverter.common.SungrowInverterModel with details of model, serial, nominal output power (kWh) @@ -97,7 +97,7 @@ Available methods and how to use #### All inverters - `model:` provides device model (ie. SH5K - as found in current models supported above) + `model:` Provides device model (ie. SH5K - as found in current models supported above) `device_code:` Sungrow device code found at register 5000 (refer docs for actual codes if needed) @@ -109,13 +109,13 @@ Available methods and how to use `mppt_input:` The number of mppt inputs the inverter supports, refer notes below. - `data:` provides a dictionary of data of all registers queried (key = register name, value = register value) refer to the https://github.com/mvandersteen/SungrowInverter/tree/main/sungrowinverter/configs for details on what registers are exposed. + `data:` Provides a dictionary of data of all registers queried (key = register name, value = register value) refer to the https://github.com/mvandersteen/SungrowInverter/tree/main/sungrowinverter/configs for details on what registers are exposed. #### Hybrid (storage) inverters only - `battery_type:` , this will show the configured details for the inverter + `battery_type:` Show the battery type configured for the inverter - `battery_capacity :` hybrid inverters only, this will show the configured details for the inverter + `battery_energy_capacity:` hybrid only, this will show the capacity of the battery configured for the inverter ## Note diff --git a/setup.cfg b/setup.cfg index 4886870..e2c79db 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,6 +1,6 @@ [metadata] name = SungrowInverter -version = 0.1.8 +version = 0.1.9 author = Mark Vandersteen author_email = mark@vandersteen.me description = A client to allow access to a Sungrow inverter modbus parameters (read only). diff --git a/sungrowinverter/SungrowInverter.py b/sungrowinverter/SungrowInverter.py index 8cca859..ab89615 100755 --- a/sungrowinverter/SungrowInverter.py +++ b/sungrowinverter/SungrowInverter.py @@ -9,7 +9,7 @@ Refer configs/hybrid.py and configs/string.py for inverters that are supported. """ -__version__ = "0.1.8" +__version__ = "0.1.9" from SungrowModbusTcpClient import SungrowModbusTcpClient @@ -246,11 +246,13 @@ async def inverter_model(self) -> SungrowInverterModel: self.data["battery_energy_capacity"] = self.battery_energy_capacity logging.info("Storage device attached to inverter: [Model: %s, Capacity: %s kWh]", self.battery_type, self.battery_energy_capacity) - return inverter_model - else: - logging.error("CONNECTION ERROR: Could not connect to inverter @ Host: %s, Port: %s", self._modbusclient.host, self._modbusclient.port) - logging.error("UPSUPPORT INVERTER: Supported inverter device_type_code [%s] is not supported", self.data["device_type_code"]) + return inverter_model + + else: + logging.error("UPSUPPORT INVERTER: Supported inverter device_type_code [%s] is not supported", self.data["device_type_code"]) + else: + logging.error("DEVICE CODE NOT FOUND: A device code could not be obtained from the inverter") else: logging.error("CONNECTION ERROR: Could not connect to inverter @ Host: %s, Port: %s", self._modbusclient.host, self._modbusclient.port) else: @@ -313,4 +315,31 @@ async def async_update(self): else: logging.error("CONNECTION ERROR: Could not connect to inverter to read modbus registers") - return False \ No newline at end of file + return False + + + # Core monitoring loop + async def async_scan(self, register_type, start_register, register_count, step_by = 20): + """Connect to the inverter and scan for register locations""" + + connected = self._modbusclient.connect() + + if connected: + for start in range(start_register, start_register + register_count, step_by): + try: + if register_type == "read": + response = self._modbusclient.read_input_registers(int(start - 1), count=step_by, unit=self._slave) + elif register_type == "holding": + response = self._modbusclient.read_holding_registers(int(start - 1), count=step_by, unit=self._slave) + + if hasattr(response, 'registers'): + logging.info("[start_register: %s, register_count: %s] contents: %s", int(start_register) , register_count, response.registers) + else: + logging.info("[start_register: %s, register_count: %s] nothing returned", int(start_register) , register_count) + + except Exception: + logging.info("Exception thrown") + + self._modbusclient.close() + return True + return False \ No newline at end of file diff --git a/sungrowinverter/configs/hybrid.py b/sungrowinverter/configs/hybrid.py index 252eae8..9f1831f 100644 --- a/sungrowinverter/configs/hybrid.py +++ b/sungrowinverter/configs/hybrid.py @@ -143,6 +143,8 @@ HYBRID_CALCULATED_REGISTERS: tuple[CalcRegister, ...] = ( CalcRegister("daily_export_energy", "self.data['daily_export_from_pv'] + self.data['daily_export_from_battery']", unit_of_measure=KILO_WATT_HOUR), - CalcRegister("total_export_energy", "self.data['total_export_from_pv'] + self.data['total_export_from_battery']", unit_of_measure=KILO_WATT_HOUR), - CalcRegister("inverter_efficiency", "int((self.data['daily_energy_yield'] / self.data['daily_pv_generation']) * 100)", unit_of_measure=PERCENTAGE, description="Energy yield from the days pv generation"), + CalcRegister("total_export_energy", "self.data['total_export_from_pv'] + self.data['total_export_from_battery']", unit_of_measure=KILO_WATT_HOUR), + CalcRegister("daily_batery_charge", "self.data['daily_battery_charge_from_pv'] + self.data['daily_charge_from_grid']", unit_of_measure=KILO_WATT_HOUR), + CalcRegister("total_batery_charge", "self.data['total_battery_charge_from_pv'] + self.data['total_charge_from_grid']", unit_of_measure=KILO_WATT_HOUR), + CalcRegister("inverter_efficiency", "int((self.data['daily_energy_yield'] / self.data['daily_pv_generation']) * 100)", unit_of_measure=PERCENTAGE, description="Energy yield from the days pv generation") ) \ No newline at end of file diff --git a/sungrowinverter/configs/inverter.py b/sungrowinverter/configs/inverter.py index aa9c4cd..3fc1b74 100644 --- a/sungrowinverter/configs/inverter.py +++ b/sungrowinverter/configs/inverter.py @@ -5,7 +5,6 @@ SungrowInverterModel, KILO_WATT, VOLTAGE, - AMPERE, AMP_HOUR, BATTERY_TYPES, ) diff --git a/test.py b/test.py index c463801..cef4c68 100644 --- a/test.py +++ b/test.py @@ -3,7 +3,7 @@ from sungrowinverter import SungrowInverter -logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.ERROR) +logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.INFO) #logging.basicConfig(format='%(levelname)s:%(message)s', level=logging.DEBUG) # Change IP Address (192.168.4.2) to suit your inverter @@ -14,7 +14,7 @@ result = loop.run_until_complete(client.async_update()) #Get a list data returned from the inverter. -if result != False: +if result: print(client.data) else: print("Could not connect to inverter") \ No newline at end of file