44import math
55from datetime import datetime
66
7- from pymodbus .client import ModbusTcpClient # type: ignore
7+ from pymodbus .client import ModbusTcpClient , AsyncModbusTcpClient # type: ignore
88from pymodbus .constants import DeviceInformation # type: ignore
99from pymodbus .pdu import ExceptionResponse # type: ignore
1010from pymodbus .client .mixin import ModbusClientMixin # type: ignore
@@ -192,8 +192,7 @@ class TypeOfGateway(enum.Enum):
192192class SchneiderModbus :
193193 def __init__ (self , host , type_of_gateway : TypeOfGateway , port = 502 , timeout = 5 ):
194194 _LOGGER .info (f"Connecting Modbus TCP to { host } :{ port } " )
195- self .client = ModbusTcpClient (host = host , port = port , timeout = timeout )
196- self .client .connect ()
195+ self .client = AsyncModbusTcpClient (host = host , port = port , timeout = timeout )
197196 self .type_of_gateway = type_of_gateway
198197 self .synthetic_slave_id = None
199198
@@ -231,15 +230,15 @@ async def hardware_version(self) -> str | None:
231230 else :
232231 return await self .__read_string (0x0050 , 6 , GATEWAY_SLAVE_ID )
233232
234- def serial_number (self ) -> str | None :
233+ async def serial_number (self ) -> str | None :
235234 """[S/N]: PP YY WW [D [nnnn]]
236235 • PP: Plant
237236 • YY: Year in decimal notation [05...99]
238237 • WW: Week in decimal notation [1...53]
239238 • D: Day of the week in decimal notation [1...7]
240239 • nnnn: Sequence of numbers [0001...10.00-0–1]
241240 """
242- return self .__sync_read_string (0x0064 , 6 , GATEWAY_SLAVE_ID )
241+ return await self .__read_string (0x0064 , 6 , GATEWAY_SLAVE_ID )
243242
244243 async def firmware_version (self ) -> str | None :
245244 """valid for firmware version 001.008.007 and later."""
@@ -716,9 +715,9 @@ async def tag_hardware_revision(self, tag_index: int) -> str | None:
716715 """Hardware revision"""
717716 return await self .__read_string (0x796A , 6 , tag_index )
718717
719- def tag_serial_number (self , tag_index : int ) -> str | None :
718+ async def tag_serial_number (self , tag_index : int ) -> str | None :
720719 """Serial number"""
721- return self .__sync_read_string (0x7970 , 10 , tag_index )
720+ return await self .__read_string (0x7970 , 10 , tag_index )
722721
723722 async def tag_product_range (self , tag_index : int ) -> str | None :
724723 """Product range"""
@@ -915,35 +914,50 @@ def round_to_significant_digits(number: float, significant_digits: int):
915914 def __write (self , address : int , registers : list [int ], slave_id : int ):
916915 self .client .write_registers (address , registers , device_id = slave_id )
917916
918- def __read (self , address : int , count : int , slave_id : int ):
919- response = self .client .read_holding_registers (
920- address = address , count = count , device_id = slave_id
921- )
922- if response .isError ():
923- raise ConnectionError (str (response ))
924- return response .registers
925-
926- async def __async_read (self , address : int , count : int , slave_id : int ) -> list [int ]:
927- loop = asyncio .get_event_loop ()
917+ async def __async_read (
918+ self , address : int , count : int , slave_id : int
919+ ) -> list [int ] | None :
928920 try :
929- return await asyncio .wait_for (
930- loop .run_in_executor (None , self .__read , address , count , slave_id ),
921+ if not self .client .connected :
922+ await self .client .connect ()
923+
924+ result = await asyncio .wait_for (
925+ self .client .read_holding_registers (
926+ address = address , count = count , device_id = slave_id
927+ ),
931928 timeout = 5.0 ,
932929 )
930+ if result .isError ():
931+ _LOGGER .debug (
932+ f"Modbus error reading { address } from slave ID { slave_id } "
933+ )
934+ return None
935+ return result .registers
936+
933937 except asyncio .TimeoutError :
934- _LOGGER .debug (f"Timeout when fetching address { address } from slave ID { slave_id } " )
938+ _LOGGER .debug (
939+ f"Timeout when fetching address { address } from slave ID { slave_id } "
940+ )
941+ return None
935942
936943 async def __async_write (
937944 self , address : int , registers : list [int ], slave_id : int
938945 ) -> None :
939- loop = asyncio .get_event_loop ()
940946 try :
941- await asyncio .wait_for (
942- loop .run_in_executor (None , self .__write , address , registers , slave_id ),
947+ if not self .client .connected :
948+ await self .client .connect ()
949+
950+ result = await asyncio .wait_for (
951+ self .client .write_registers (address , registers , device_id = slave_id ),
943952 timeout = 5.0 ,
944953 )
954+ if result .isError ():
955+ _LOGGER .debug (f"Modbus error writing { address } to slave ID { slave_id } " )
956+ return None
945957 except asyncio .TimeoutError :
946- _LOGGER .debug (f"Timeout when writing to address { address } from slave ID { slave_id } " )
958+ _LOGGER .debug (
959+ f"Timeout when writing to address { address } to slave ID { slave_id } "
960+ )
947961
948962 async def __identify (self , _ : int ):
949963 # data = self.client.read_device_information(read_code=DeviceInformation.REGULAR, device_id=0xFF)
@@ -959,16 +973,7 @@ async def __identify(self, _: int):
959973
960974 async def __read_string (self , address : int , count : int , slave_id : int ) -> str | None :
961975 registers = await self .__async_read (address , count , slave_id )
962- return self .client .convert_from_registers (
963- registers , ModbusClientMixin .DATATYPE .STRING
964- )
965-
966- def __sync_read_string (self , address : int , count : int , slave_id : int ) -> str | None :
967- registers = self .__read (address , count , slave_id )
968- return self .client .convert_from_registers (
969- registers , ModbusClientMixin .DATATYPE .STRING
970- )
971-
976+ return self .client .convert_from_registers (registers , ModbusClientMixin .DATATYPE .STRING )
972977
973978 async def __write_string (self , address : int , slave_id : int , string : str ):
974979 registers = self .client .convert_to_registers (
@@ -1001,14 +1006,14 @@ async def __write_int_16(self, address: int, slave_id: int, value: int):
10011006 await self .__async_write (address , registers , slave_id )
10021007
10031008 async def __read_int_32 (self , address : int , slave_id : int ) -> int | None :
1004- registers = self .__read (address , 2 , slave_id )
1009+ registers = await self .__async_read (address , 2 , slave_id )
10051010 result = self .client .convert_from_registers (
10061011 registers , ModbusClientMixin .DATATYPE .UINT32
10071012 )
10081013 return result if result != 0x8000_0000 else None
10091014
10101015 async def __read_int_64 (self , address : int , slave_id : int ) -> int | None :
1011- registers = self .__read (address , 4 , slave_id )
1016+ registers = await self .__async_read (address , 4 , slave_id )
10121017 result = self .client .convert_from_registers (
10131018 registers , ModbusClientMixin .DATATYPE .UINT64
10141019 )
0 commit comments