121 lines
3.1 KiB
Python
Executable File
121 lines
3.1 KiB
Python
Executable File
#!/usr/bin/env python3
|
|
import argparse
|
|
import struct
|
|
from pymodbus.client import ModbusTcpClient
|
|
|
|
|
|
def call_with_unit(fn, unit, **kwargs):
|
|
"""
|
|
Compatible con varias versiones de pymodbus:
|
|
- pymodbus 3.x usa device_id
|
|
- versiones anteriores pueden usar slave o unit
|
|
"""
|
|
last_error = None
|
|
|
|
for key in ("device_id", "slave", "unit"):
|
|
try:
|
|
return fn(**kwargs, **{key: unit})
|
|
except TypeError as e:
|
|
last_error = e
|
|
|
|
raise last_error
|
|
|
|
|
|
def f32_abcd(reg_hi, reg_lo):
|
|
raw = reg_hi.to_bytes(2, "big") + reg_lo.to_bytes(2, "big")
|
|
return struct.unpack(">f", raw)[0]
|
|
|
|
|
|
def print_holding(client, unit, start, count):
|
|
print(f"\n=== HOLDING REGISTERS start={start}, count={count}, unit={unit} ===")
|
|
|
|
try:
|
|
rr = call_with_unit(
|
|
client.read_holding_registers,
|
|
unit,
|
|
address=start,
|
|
count=count
|
|
)
|
|
except Exception as e:
|
|
print("EXCEPTION:", repr(e))
|
|
return
|
|
|
|
if rr.isError():
|
|
print("MODBUS ERROR:", rr)
|
|
return
|
|
|
|
regs = rr.registers
|
|
|
|
for i, value in enumerate(regs):
|
|
print(f"{start + i}: {value}")
|
|
|
|
print("\nFloat ABCD por parejas:")
|
|
for i in range(0, len(regs) - 1, 2):
|
|
try:
|
|
value = f32_abcd(regs[i], regs[i + 1])
|
|
print(f"{start + i}/{start + i + 1}: {value:.6f}")
|
|
except Exception as e:
|
|
print(f"{start + i}/{start + i + 1}: ERROR {e}")
|
|
|
|
|
|
def print_bits(client, unit, kind, start, count):
|
|
print(f"\n=== {kind.upper()} start={start}, count={count}, unit={unit} ===")
|
|
|
|
fn = client.read_discrete_inputs if kind == "discrete" else client.read_coils
|
|
|
|
try:
|
|
rr = call_with_unit(
|
|
fn,
|
|
unit,
|
|
address=start,
|
|
count=count
|
|
)
|
|
except Exception as e:
|
|
print("EXCEPTION:", repr(e))
|
|
return
|
|
|
|
if rr.isError():
|
|
print("MODBUS ERROR:", rr)
|
|
return
|
|
|
|
bits = rr.bits[:count]
|
|
|
|
for i, value in enumerate(bits):
|
|
print(f"{start + i}: {int(value)}")
|
|
|
|
|
|
def main():
|
|
parser = argparse.ArgumentParser()
|
|
parser.add_argument("--host", required=True)
|
|
parser.add_argument("--port", type=int, default=502)
|
|
parser.add_argument("--unit", type=int, default=1)
|
|
args = parser.parse_args()
|
|
|
|
client = ModbusTcpClient(args.host, port=args.port, timeout=3)
|
|
|
|
if not client.connect():
|
|
print(f"ERROR: no conecta con {args.host}:{args.port}")
|
|
return
|
|
|
|
print(f"OK: conectado a {args.host}:{args.port}")
|
|
|
|
try:
|
|
# El WISE muestra Mapping Address(4X) 1001.
|
|
# Probamos base cero y base uno.
|
|
print_holding(client, args.unit, 1000, 20)
|
|
print_holding(client, args.unit, 1001, 20)
|
|
|
|
# Intentos típicos para DI por Modbus/TCP.
|
|
# Luego afinamos según Bit Status del WISE.
|
|
print_bits(client, args.unit, "discrete", 0, 16)
|
|
print_bits(client, args.unit, "discrete", 1, 16)
|
|
print_bits(client, args.unit, "coils", 0, 16)
|
|
print_bits(client, args.unit, "coils", 1, 16)
|
|
|
|
finally:
|
|
client.close()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|