Skip to content

Commit c85d351

Browse files
authored
unify modbus sleeps (currently used by solaredge and huawei) (openWB#1446)
* unify modbus sleeps (currently used by solaredge and huawei) * use reconnect delay * review * flake8
1 parent e6c5dc8 commit c85d351

File tree

7 files changed

+68
-28
lines changed

7 files changed

+68
-28
lines changed

packages/modules/common/evse.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def activate_precise_current(self) -> None:
7373
else:
7474
with ModifyLoglevelContext(log, logging.DEBUG):
7575
log.debug("Bit zur Angabe der Ströme in 0,1A-Schritten wird gesetzt.")
76-
self.client.delegate.write_registers(2005, value ^ self.PRECISE_CURRENT_BIT, unit=self.id)
76+
self.client.write_registers(2005, value ^ self.PRECISE_CURRENT_BIT, unit=self.id)
7777
# Zeit zum Verarbeiten geben
7878
time.sleep(1)
7979

@@ -83,10 +83,10 @@ def deactivate_precise_current(self) -> None:
8383
if value & self.PRECISE_CURRENT_BIT:
8484
with ModifyLoglevelContext(log, logging.DEBUG):
8585
log.debug("Bit zur Angabe der Ströme in 0,1A-Schritten wird zurueckgesetzt.")
86-
self.client.delegate.write_registers(2005, value ^ self.PRECISE_CURRENT_BIT, unit=self.id)
86+
self.client.write_registers(2005, value ^ self.PRECISE_CURRENT_BIT, unit=self.id)
8787
else:
8888
return
8989

9090
def set_current(self, current: int) -> None:
9191
time.sleep(0.1)
92-
self.client.delegate.write_registers(1000, current, unit=self.id)
92+
self.client.write_registers(1000, current, unit=self.id)

packages/modules/common/modbus.py

Lines changed: 50 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@
77
import logging
88
import struct
99
from enum import Enum
10-
from typing import Callable, Iterable, Union, overload, List
10+
import time
11+
from typing import Any, Callable, Iterable, Optional, Union, overload, List
1112

1213
import pymodbus
1314
from pymodbus.client.sync import ModbusTcpClient, ModbusSerialClient
@@ -46,29 +47,41 @@ def __init__(self, bits: int, decoding_method: str):
4647

4748

4849
class ModbusClient:
49-
def __init__(self, delegate: Union[ModbusSerialClient, ModbusTcpClient], address: str, port: int = 502):
50-
self.delegate = delegate
50+
def __init__(self,
51+
delegate: Union[ModbusSerialClient, ModbusTcpClient],
52+
address: str, port: int = 502,
53+
sleep_after_connect: Optional[int] = 0):
54+
self._delegate = delegate
5155
self.address = address
5256
self.port = port
57+
self.sleep_after_connect = sleep_after_connect
5358

5459
def __enter__(self):
5560
try:
56-
self.delegate.__enter__()
61+
self._delegate.__enter__()
62+
time.sleep(self.sleep_after_connect)
5763
except pymodbus.exceptions.ConnectionException as e:
5864
e.args += (NO_CONNECTION.format(self.address, self.port),)
5965
raise e
6066
return self
6167

6268
def __exit__(self, exc_type, exc_value, exc_traceback):
63-
self.delegate.__exit__(exc_type, exc_value, exc_traceback)
69+
self._delegate.__exit__(exc_type, exc_value, exc_traceback)
6470

65-
def close_connection(self) -> None:
71+
def connect(self) -> None:
72+
self._delegate.connect()
73+
time.sleep(self.sleep_after_connect)
74+
75+
def close(self) -> None:
6676
try:
6777
log.debug("Close Modbus TCP connection")
68-
self.delegate.close()
78+
self._delegate.close()
6979
except Exception as e:
7080
raise Exception(__name__+" "+str(type(e))+" " + str(e)) from e
7181

82+
def is_socket_open(self) -> bool:
83+
return self._delegate.is_socket_open()
84+
7285
def __read_registers(self, read_register_method: Callable,
7386
address: int,
7487
types: Union[Iterable[ModbusDataType], ModbusDataType],
@@ -118,7 +131,7 @@ def read_holding_registers(self, address: int,
118131
wordorder: Endian = Endian.Big,
119132
**kwargs):
120133
return self.__read_registers(
121-
self.delegate.read_holding_registers, address, types, byteorder, wordorder, **kwargs
134+
self._delegate.read_holding_registers, address, types, byteorder, wordorder, **kwargs
122135
)
123136

124137
@overload
@@ -137,7 +150,12 @@ def read_input_registers(self, address: int,
137150
byteorder: Endian = Endian.Big,
138151
wordorder: Endian = Endian.Big,
139152
**kwargs):
140-
return self.__read_registers(self.delegate.read_input_registers, address, types, byteorder, wordorder, **kwargs)
153+
return self.__read_registers(self._delegate.read_input_registers,
154+
address,
155+
types,
156+
byteorder,
157+
wordorder,
158+
**kwargs)
141159

142160
@overload
143161
def read_coils(self, address: int, types: Iterable[ModbusDataType], byteorder: Endian = Endian.Big,
@@ -151,7 +169,7 @@ def read_coils(self, address: int, count: int, **kwargs) -> bool:
151169

152170
def read_coils(self, address: int, count: int, **kwargs):
153171
try:
154-
response = self.delegate.read_coils(address, count, **kwargs)
172+
response = self._delegate.read_coils(address, count, **kwargs)
155173
if response.isError():
156174
raise Exception(__name__+" "+str(response))
157175
return response.bits[0] if count == 1 else response.bits[:count]
@@ -162,18 +180,35 @@ def read_coils(self, address: int, count: int, **kwargs):
162180
e.args += (NO_VALUES.format(self.address, self.port),)
163181
raise e
164182

183+
def write_registers(self, address: int, value: Any, types: ModbusDataType):
184+
self._delegate.write_registers(address, value, types)
185+
165186

166187
class ModbusTcpClient_(ModbusClient):
167-
def __init__(self, address: str, port: int = 502):
188+
def __init__(self,
189+
address: str,
190+
port: int = 502,
191+
sleep_after_connect: Optional[int] = None,
192+
**kwargs):
168193
parsed_url = parse_url(address)
169194
host = parsed_url.host
170195
if parsed_url.port is not None:
171196
port = parsed_url.port
172-
super().__init__(ModbusTcpClient(host, port), address, port)
197+
super().__init__(ModbusTcpClient(host, port, **kwargs), address, port, sleep_after_connect)
173198

174199

175200
class ModbusSerialClient_(ModbusClient):
176-
def __init__(self, port: int):
177-
super().__init__(ModbusSerialClient(method="rtu", port=port, baudrate=9600, stopbits=1, bytesize=8, timeout=1),
201+
def __init__(self,
202+
port: int,
203+
sleep_after_connect: Optional[int] = None,
204+
**kwargs):
205+
super().__init__(ModbusSerialClient(method="rtu",
206+
port=port,
207+
baudrate=9600,
208+
stopbits=1,
209+
bytesize=8,
210+
timeout=1,
211+
**kwargs),
178212
"Serial",
179-
port)
213+
port,
214+
sleep_after_connect)

packages/modules/devices/good_we/device.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -90,7 +90,7 @@ def read_legacy(component_type: str, ip_address: str, id: int, num: Optional[int
9090
log.debug('GoodWe ID: ' + str(id))
9191

9292
dev.update()
93-
dev.client.close_connection()
93+
dev.client.close()
9494

9595

9696
def main(argv: List[str]):

packages/modules/devices/huawei/device.py

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,17 +26,20 @@ def create_inverter_component(component_config: HuaweiInverterSetup):
2626
return HuaweiInverter(device_config.id, component_config)
2727

2828
def update_components(components: Iterable[Union[HuaweiBat, HuaweiCounter, HuaweiInverter]]):
29-
with client as c:
29+
if client.is_socket_open() is False:
30+
client.connect()
31+
try:
3032
modbus_id = device_config.configuration.modbus_id
31-
regs = c.read_holding_registers(32064, [ModbusDataType.INT_32]*5701, unit=modbus_id)
33+
regs = client.read_holding_registers(32064, [ModbusDataType.INT_32]*5701, unit=modbus_id)
3234
counter_currents_reg = regs[5043:5045] # INT 32, 37107-9
3335
counter_power_reg = regs[5049] # INT32, 37113
3436
bat_power_reg = regs[-1] # INT32, 37765
3537
inverter_power_reg = regs[0] # INT32 32064
3638
# Huawei darf nur mit Regelintervall sehr langsam betrieben werden, daher kann hier eine längere Pause
3739
# eingelegt werden. Ob auch eine kürzere ausreichend ist, ist nicht getestet.
3840
time.sleep(5)
39-
bat_soc_reg = c.read_holding_registers(37760, ModbusDataType.INT_16, unit=modbus_id) # Int 16 37760
41+
bat_soc_reg = client.read_holding_registers(
42+
37760, ModbusDataType.INT_16, unit=modbus_id) # Int 16 37760
4043

4144
for component in components:
4245
with SingleComponentUpdateContext(component.fault_state):
@@ -46,11 +49,12 @@ def update_components(components: Iterable[Union[HuaweiBat, HuaweiCounter, Huawe
4649
component.update(counter_currents_reg, counter_power_reg)
4750
elif isinstance(component, HuaweiInverter):
4851
component.update(inverter_power_reg)
52+
except Exception as e:
53+
client.close()
54+
raise e
4955

5056
try:
51-
client = ModbusTcpClient_(device_config.configuration.ip_address, 502)
52-
client.delegate.connect()
53-
time.sleep(7)
57+
client = ModbusTcpClient_(device_config.configuration.ip_address, 502, sleep_after_connect=7)
5458
except Exception:
5559
log.exception("Fehler in create_device")
5660
return ConfigurableDevice(

packages/modules/devices/huawei_smartlogger/device.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ def __init__(self, device_config: Union[Dict, Huawei_Smartlogger]) -> None:
3535
ip_address = self.device_config.configuration.ip_address
3636
self.port = 502
3737
self.client = modbus.ModbusTcpClient_(ip_address, 502)
38-
self.client.delegate.connect()
38+
self.client.connect()
3939
except Exception:
4040
log.exception("Fehler im Modul "+self.device_config.name)
4141

packages/modules/devices/solaredge/device.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,8 @@ def __init__(self, device_config: Union[Dict, Solaredge]) -> None:
4848
try:
4949
self.device_config = dataclass_from_dict(Solaredge, device_config)
5050
self.client = modbus.ModbusTcpClient_(self.device_config.configuration.ip_address,
51-
self.device_config.configuration.port)
51+
self.device_config.configuration.port,
52+
reconnect_delay=reconnect_delay)
5253
self.inverter_counter = 0
5354
self.synergy_units = 1
5455
except Exception:

packages/modules/devices/sungrow/bat.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def __init__(self,
2929
def update(self) -> None:
3030
unit = self.__device_modbus_id
3131
soc = int(self.__tcp_client.read_input_registers(13022, ModbusDataType.INT_16, unit=unit) / 10)
32-
resp = self.__tcp_client.delegate.read_input_registers(13000, 1, unit=unit)
32+
resp = self.__tcp_client._delegate.read_input_registers(13000, 1, unit=unit)
3333
binary = bin(resp.registers[0])[2:].zfill(8)
3434
power = self.__tcp_client.read_input_registers(13021, ModbusDataType.INT_16, unit=unit)
3535
if binary[5] == "1":

0 commit comments

Comments
 (0)