56 lines
1.9 KiB
Python
56 lines
1.9 KiB
Python
"""pymodbus-based helpers for the ZLAC8015D V4 RS485 (Modbus RTU) protocol.
|
|
|
|
Register reference (from "ZLAC8015D V4 Series RS485 Communication" manual):
|
|
0x2001 RS485 Custom Drive Node Number (RW/S, range 1-127, default 1)
|
|
0x2002 RS485 custom communication baud rate (RW/S)
|
|
0x2010 Save all RW attribute parameters to EEPROM (write 1 to save)
|
|
|
|
Requires: pip install pymodbus pyserial
|
|
"""
|
|
from pymodbus.client import ModbusSerialClient
|
|
|
|
REG_NODE_ID = 0x2001
|
|
REG_SAVE_EEPROM = 0x2010
|
|
|
|
# pymodbus renamed the "slave id" keyword across major versions
|
|
# (unit -> slave -> device_id). Try each so this works regardless of
|
|
# which pymodbus version is installed (e.g. on the Ubuntu test box).
|
|
_ID_KWARGS = ("device_id", "slave", "unit")
|
|
|
|
|
|
def _call(fn, *args, node_id, **kwargs):
|
|
last_err = None
|
|
for kw in _ID_KWARGS:
|
|
try:
|
|
return fn(*args, **{kw: node_id}, **kwargs)
|
|
except TypeError as exc:
|
|
last_err = exc
|
|
continue
|
|
raise TypeError(f"pymodbus client does not accept any of {_ID_KWARGS}: {last_err}")
|
|
|
|
|
|
def make_client(port: str, baud: int = 115200, timeout: float = 0.3) -> ModbusSerialClient:
|
|
return ModbusSerialClient(
|
|
port,
|
|
baudrate=baud,
|
|
bytesize=8,
|
|
parity="N",
|
|
stopbits=1,
|
|
timeout=timeout,
|
|
)
|
|
|
|
|
|
def read_register(client: ModbusSerialClient, node_id: int, address: int, count: int = 1):
|
|
"""Return list of register values, or None on error/no response."""
|
|
result = _call(client.read_holding_registers, address, node_id=node_id, count=count)
|
|
if result is None or result.isError():
|
|
return None
|
|
return result.registers
|
|
|
|
|
|
def write_register(client: ModbusSerialClient, node_id: int, address: int, value: int) -> bool:
|
|
result = _call(client.write_register, address, value, node_id=node_id)
|
|
if result is None or result.isError():
|
|
return False
|
|
return True
|