'''
Create a Modbus TCP server (slave) which can be requested for data or set with
specific values by a host device.
'''
# system packages
import time
import network
# import modbus server classes
from tcp import ModbusTCP
# ===============================================
# connect to a network
station = network.WLAN(network.STA_IF)
if station.active() and station.isconnected():
station.disconnect()
time.sleep(1)
station.active(False)
time.sleep(1)
station.active(True)
# station.connect('SSID', 'PASSWORD')
station.connect('Wokwi-GUEST', '')
time.sleep(1)
while True:
print('Waiting for WiFi connection...')
if station.isconnected():
print('Connected to WiFi.')
print(station.ifconfig())
break
time.sleep(2)
# ===============================================
# TCP Slave setup
tcp_port = 502
local_ip = station.ifconfig()[0]
# ModbusTCP can get TCP requests from a client device to provide/set data
server = ModbusTCP()
# check whether server has been bound to an IP and port
is_bound = server.get_bound_status()
if not is_bound:
server.bind(local_ip=local_ip, local_port=tcp_port)
letras = ["A", "B", "C", "D", "E"]
max_len = 5 # max length of any register sub-group
# define register values as a dictionary
registers = {
"COILS": {
0: {
"register": 0,
"val": [0, 0, 0],
"key": ["PM", "PP", "PA"]
},
max_len: {
"register": max_len,
"val": [0],
"key": ["Set Receta"]
}
},
"HREGS": {
0: {
"register": 0,
"val": [2, 3, 4, 5],
"key": [f"Receta Tipo {letra}" for letra in letras]
},
max_len: {
"register": max_len,
"val": [4, 3, 2, 1],
"key": [f"Receta Numero {letra}" for letra in letras]
}
},
"ISTS": {
0: {
"register": 0,
"val": [0, 0],
"key": ["Marcha", "Emerge"]
},
max_len: {
"register": max_len,
"val": [0, 0, 0, 0, 0],
"key": [f"Reed {letra}+" for letra in letras]
},
2*max_len: {
"register": 2*max_len,
"val": [1, 1, 1, 1, 1],
"key": [f"Reed {letra}-" for letra in letras]
},
3*max_len: {
"register": 3*max_len,
"val": [1, 0, 0],
"key": [f"LED {num}" for num in range(1, 4)]
},
4*max_len: {
"register": 4*max_len,
"val": [0, 0, 0, 0, 0],
"key": [f"Cilindro {letra}+" for letra in letras],
},
5*max_len: {
"register": 5*max_len,
"val": [0, 0, 0, 0],
"key": [f"LED {letra}" for letra in letras[1:]]
}
},
"IREGS": {
0: {
"register": 0,
"val": [255],
"key": ["Tipo A"]
},
max_len: {
"register": max_len,
"val": [2, 2, 4, 4],
"key": [f"Receta Tipo {letra}" for letra in letras[1:]]
},
2*max_len: {
"register": 2*max_len,
"val": [1, 3, 3, 1],
"key": [f"Receta Numero {letra}" for letra in letras[1:]]
},
3*max_len: {
"register": 3*max_len,
"val": [0, 0, 0, 0],
"key": [f"Display {letra}" for letra in letras[1:]]
}
}
}
modifiable_registers = {reg_type: registers[reg_type] for reg_type in ["COILS", "HREGS"]}
print('Setting up registers ...')
# use the defined values of each register type provided by registers
server.setup_registers(registers)
print('Register setup done')
print('Serving as TCP server on {}:{}'.format(local_ip, tcp_port))
# global variables:
reg_dict = server._register_dict
# Iterar sobre un diccionario e imprimir clave y valor en cada línea
def print_dict(data):
for key, value in data.items():
print(key)
for inner_key, inner_value in value.items():
print(f" {inner_key}: {inner_value}")
# show registers
def show_actual_regs():
actual_regs = {}
for reg_type, regs in registers.items():
a_r = {}
for addr, r_d in reg_dict[reg_type].items():
init_addr = max_len * (addr // max_len)
index = addr - init_addr
val = r_d["val"]
key = regs[init_addr]["key"][index]
if not a_r:
actual_regs[reg_type] = a_r
a_r[key] = val
print()
print("> Actual REGISTERS >")
print_dict(actual_regs)
# show modified registers
def show_mod_regs():
mod_regs = {}
for reg_type, regs in modifiable_registers.items():
m_r = {}
for addr, r_d in reg_dict[reg_type].items():
init_addr = max_len * (addr // max_len)
index = addr - init_addr
val = r_d["val"]
group = regs[init_addr]
if group["val"][index] != val:
group["val"][index] = val
key = group["key"][index]
if not m_r:
mod_regs[reg_type] = m_r
m_r[key] = val
if mod_regs:
print()
print(f"> Modified REGISTERS >")
print_dict(mod_regs)
# mostrar los valores de los registros según sus "claves"
show_actual_regs()
# modificar algunos registros (emular un cliente)
reg_dict["COILS"][0]["val"] = 1
reg_dict["HREGS"][7]["val"] = 1
reg_dict["HREGS"][8]["val"] = 2
while True:
try:
server.process()
show_mod_regs()
except KeyboardInterrupt:
print('KeyboardInterrupt, stopping TCP server...')
break
except Exception as e:
print('Exception during execution: {}'.format(e))
print("Finished providing/accepting data as server")