modbus_tcp_async.py 2.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. class AsyncModbusTCPMeter(ModbusTCPMeter):
  2. def __init__(self, *args, **kwargs):
  3. super().__init__(*args, **kwargs)
  4. self.reader = self.writer = None
  5. async def _connect(self):
  6. self.reader, self.writer = await asyncio.open_connection(host=self.port, port=self.tcp_port)
  7. async def read(self, regnames=None):
  8. if regnames is None:
  9. registers = self.REGS
  10. return await self._read_multiple(registers)
  11. if isinstance(regnames, str):
  12. registers = [register for register in self.REGS if register['name'] == regnames]
  13. if len(registers) == 0:
  14. return "Register not found on device."
  15. return await self._read_single(registers[0])
  16. if isinstance(regnames, Iterable):
  17. registers = [register for register in self.REGS if register['name'] in regnames]
  18. return await self._read_multiple(registers)
  19. async def _read_single(self, register):
  20. num_regs = register['length']
  21. message = self._modbus_message(register['start'], num_regs)
  22. if self.writer is None:
  23. await self._connect()
  24. self.writer.write(message)
  25. await self.writer.drain()
  26. data = await self.reader.readexactly(9 + 2 * num_regs)
  27. return self._convert_value(data[9:], signed=register['signed'], decimals=register['decimals'], isFloat=register['isFloat']|False)
  28. async def _read_multiple(self, registers):
  29. registers.sort(key=lambda reg: reg['start'])
  30. results = {}
  31. for reg_range in self._split_ranges(registers):
  32. # Prepare the request
  33. first_reg = min([register['start'] for register in reg_range])
  34. num_regs = max([register['start'] + register['length'] for register in reg_range]) - first_reg
  35. if self.writer is None:
  36. await self._connect()
  37. self.writer.write(self._modbus_message(first_reg, num_regs))
  38. await self.writer.drain()
  39. # Receive the response
  40. data = await self.reader.readexactly(9 + 2 * num_regs)
  41. results.update(self._interpret_result(data[9:], reg_range))
  42. return results