Documentación de la carpeta client_modbusTCP
Esta carpeta contiene el cliente Modbus TCP encargado de leer datos de un servidor Modbus (por ejemplo, un recloser simulado) y almacenar los datos en una base de datos InfluxDB. El flujo principal es: consulta periódica de registros analógicos y eventos, y almacenamiento en InfluxDB.
Estructura de archivos
client_modbusTCP/
├── client.py
├── requirements.txt
1. client.py
Este es el script principal del cliente Modbus TCP. Se conecta a un servidor Modbus, lee registros analógicos y eventos, y almacena los resultados en InfluxDB.
¿Qué hace cada sección? - Configura la conexión a Modbus TCP y a InfluxDB. - Define los registros analógicos y eventos a consultar. - Lee periódicamente los valores y detecta cambios de eventos. - Guarda los datos en InfluxDB, incluyendo los eventos como texto. - Permite la finalización segura con Ctrl+C.
Contenido del archivo:
from pymodbus.client import ModbusTcpClient
from influxdb_client import InfluxDBClient, Point
from influxdb_client.client.write_api import SYNCHRONOUS
import time
MODBUS_HOST = "127.0.0.1"
MODBUS_PORT = 5020
INFLUXDB_URL = "http://localhost:8086"
INFLUXDB_TOKEN = "9b87FS8_-PvJYOYfVlU5-7MF6Oes9jhgFWitRcZp7-efOsaI3tMLoshBGdAQM_m-akDeE7fd1IoRNl8-aOzQwg=="
INFLUXDB_ORG = "Fila3"
INFLUXDB_BUCKET = "Fila3"
input_registers = [
("Ia", 0), ("Ib", 1), ("Ic", 2),
("Ua", 4), ("Ub", 5), ("Uc", 6),
("Ur", 7), ("Us", 8), ("Ut", 9),
("Uab", 10), ("Ubc", 11), ("Uca", 12),
("Urs", 13), ("Ust", 14), ("Utr", 15),
("KVA_A", 16), ("KVA_B", 17), ("KVA_C", 18),
("KW_A", 19), ("KW_B", 20), ("KW_C", 21),
("KVAr_A", 22), ("KVAr_B", 23), ("KVAr_C", 24),
("KVA_total", 25), ("KVAr_total", 26), ("KW_total", 27),
("Freq_abc", 60), ("Freq_rst", 61),
("FP_total", 67), ("FP_A", 68), ("FP_B", 69), ("FP_C", 70),
]
# Mapeo de direcciones booleanas a nombres técnicos
discrete_inputs = {
3: "AR initiated",
43: "Open (EF1+)",
50: "Open (UF)",
55: "Open (Local)",
59: "Alarm",
63: "Malfunction",
75: "Closed (AR)",
100: "Excessive Too",
105: "Excessive Tcc",
106: "SIM Module Fault",
}
# Mapeo de direcciones a descripciones legibles
descripciones_eventos = {
3: "Se inició un ciclo de reconexión automática",
43: "Apertura por falla a tierra positiva",
50: "Apertura por baja frecuencia",
55: "Apertura manual o por panel",
59: "Alarma de protección activa",
63: "Error general detectado en el recloser",
75: "Cerrado por acción de reconexión automática (AR)",
100: "Tiempo de apertura excedido",
105: "Tiempo de cierre excedido",
106: "Falla en el módulo SIM",
}
def guardar_en_influxdb(write_api, analogos, eventos):
point = Point("mediciones_recloser")
# Campos analógicos
for nombre, valor in analogos.items():
if nombre.startswith("Freq") or nombre.startswith("FP"):
valor = valor / 100.0
point.field(nombre, valor)
# Campo eventos como string
if eventos:
eventos_str = ", ".join(eventos)
point.field("eventos", eventos_str)
write_api.write(bucket=INFLUXDB_BUCKET, record=point)
def main():
client = ModbusTcpClient(MODBUS_HOST, port=MODBUS_PORT)
influx_client = InfluxDBClient(url=INFLUXDB_URL, token=INFLUXDB_TOKEN, org=INFLUXDB_ORG)
write_api = influx_client.write_api(write_options=SYNCHRONOUS)
if not client.connect():
print("No se pudo conectar al servidor Modbus.")
return
estados_anteriores = {offset: None for offset in discrete_inputs}
try:
while True:
analogos = {}
eventos = []
print("\n--- Consulta de registros ---")
# Lectura de registros analógicos
for nombre, offset in input_registers:
result = client.read_input_registers(offset, count=1)
if result.isError():
print(f"[ERROR] {nombre} (30000+{offset}): {result}")
else:
valor = result.registers[0]
analogos[nombre] = valor
print(f"{nombre} = {valor}")
# Lectura de eventos
for offset, nombre_tecnico in discrete_inputs.items():
result = client.read_discrete_inputs(offset, count=1)
if result.isError():
print(f"[ERROR] {nombre_tecnico} (10000+{offset}): {result}")
else:
estado = result.bits[0]
estado_anterior = estados_anteriores[offset]
if estado_anterior is None:
estados_anteriores[offset] = estado
elif estado != estado_anterior:
descripcion = descripciones_eventos.get(offset, nombre_tecnico)
eventos.append(descripcion)
estados_anteriores[offset] = estado
print(f"{nombre_tecnico} = {'ON' if estado else 'OFF'}")
guardar_en_influxdb(write_api, analogos, eventos)
if eventos:
print(f"Eventos detectados y guardados: {', '.join(eventos)}")
else:
print("No hubo eventos nuevos.")
time.sleep(15)
except KeyboardInterrupt:
print("Finalizando cliente Modbus.")
finally:
client.close()
influx_client.close()
if __name__ == "__main__":
main()
2. requirements.txt
Este archivo lista las dependencias de Python necesarias para ejecutar el cliente.
Contenido del archivo:
pymodbus
influxdb-client==1.38.0
Comandos útiles
Instalar dependencias:
pip install -r requirements.txt
Ejecutar el cliente:
python client.py