forked from brainelectronics/micropython-modbus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add single char wait time after flush to avoid RTU control pin timing…
… issue, see brainelectronics#68 and brainelectronics#72
- Loading branch information
1 parent
8bf8a3f
commit 8e8ed49
Showing
10 changed files
with
489 additions
and
13 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Build image | ||
# $ docker build -t micropython-client-rtu -f Dockerfile.client_rtu . | ||
# | ||
# Run image | ||
# $ docker run -it --rm --name micropython-client-rtu micropython-client-rtu | ||
|
||
FROM micropython/unix:v1.18 | ||
|
||
# use "volumes" in docker-compose file to remove need of rebuilding | ||
# COPY ./ /home | ||
# COPY umodbus /root/.micropython/lib/umodbus | ||
|
||
CMD [ "micropython-dev", "-m", "heizung_rtu_dezentral" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
# Build image | ||
# $ docker build -t micropython-host-rtu -f Dockerfile.host_rtu . | ||
# | ||
# Run image | ||
# $ docker run -it --rm --name micropython-host-rtu micropython-host-rtu | ||
|
||
FROM micropython/unix:v1.18 | ||
|
||
# use "volumes" in docker-compose file to remove need of rebuilding | ||
# COPY ./ /home | ||
# COPY umodbus /root/.micropython/lib/umodbus | ||
|
||
CMD [ "micropython-dev", "-m", "heizung_rtu_zentral" ] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
--- | ||
|
||
# | ||
# build all non-image containers | ||
# $ docker-compose build | ||
# can be combined into one command to also start it afterwards | ||
# $ docker-compose up --build | ||
# | ||
|
||
version: "3.8" | ||
|
||
services: | ||
micropython-dezentral: | ||
build: | ||
context: . | ||
dockerfile: heizung-Dockerfile.dezentral_rtu | ||
container_name: micropython-dezentral | ||
volumes: | ||
- ./:/home | ||
- ./umodbus:/root/.micropython/lib/umodbus | ||
- ./fakes:/usr/lib/micropython | ||
- ./tests/ulogging.py:/root/.micropython/lib/ulogging.py | ||
expose: | ||
- "65433" | ||
ports: | ||
# reach "micropython-dezentral" at 172.25.0.2:65433, see networks | ||
- "65433:65433" | ||
networks: | ||
serial_bridge: | ||
# fix IPv4 address to be known and in the MicroPython scripts | ||
# https://docs.docker.com/compose/compose-file/#ipv4_address | ||
ipv4_address: 172.25.0.2 | ||
|
||
micropython-zentral: | ||
build: | ||
context: . | ||
dockerfile: heizung-Dockerfile.zentral_rtu | ||
container_name: micropython-zentral | ||
volumes: | ||
- ./:/home | ||
- ./umodbus:/root/.micropython/lib/umodbus | ||
- ./fakes:/usr/lib/micropython | ||
- ./tests/ulogging.py:/root/.micropython/lib/ulogging.py | ||
depends_on: | ||
- micropython-dezentral | ||
networks: | ||
serial_bridge: | ||
# fix IPv4 address to be known and in the MicroPython scripts | ||
# https://docs.docker.com/compose/compose-file/#ipv4_address | ||
ipv4_address: 172.25.0.3 | ||
|
||
networks: | ||
serial_bridge: | ||
# use "external: true" if the network already exists | ||
# check available networks with "docker network ls" | ||
# external: true | ||
driver: bridge | ||
# https://docs.docker.com/compose/compose-file/#ipam | ||
ipam: | ||
config: | ||
- subnet: 172.25.0.0/16 | ||
gateway: 172.25.0.1 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,149 @@ | ||
#!/usr/bin/env python3 | ||
# -*- coding: UTF-8 -*- | ||
|
||
""" | ||
Main script | ||
Do your stuff here, this file is similar to the loop() function on Arduino | ||
Create a Modbus RTU client (slave) which can be requested for data or set with | ||
specific values by a host device. | ||
The RTU communication pins can be choosen freely (check MicroPython device/ | ||
port specific limitations). | ||
The register definitions of the client as well as its connection settings like | ||
bus address and UART communication speed can be defined by the user. | ||
""" | ||
|
||
# import modbus client classes | ||
from umodbus.serial import ModbusRTU | ||
|
||
IS_DOCKER_MICROPYTHON = False | ||
try: | ||
import machine | ||
machine.reset_cause() | ||
except ImportError: | ||
raise Exception('Unable to import machine, are all fakes available?') | ||
except AttributeError: | ||
# machine fake class has no "reset_cause" function | ||
IS_DOCKER_MICROPYTHON = True | ||
import json | ||
|
||
|
||
# =============================================== | ||
# RTU Slave setup | ||
# act as client, provide Modbus data via RTU to a host device | ||
# ModbusRTU can get serial requests from a host device to provide/set data | ||
# check MicroPython UART documentation | ||
# https://docs.micropython.org/en/latest/library/machine.UART.html | ||
# for Device/Port specific setup | ||
# | ||
# RP2 needs "rtu_pins = (Pin(4), Pin(5))" whereas ESP32 can use any pin | ||
# the following example is for an ESP32. | ||
# For further details check the latest MicroPython Modbus RTU documentation | ||
# example https://micropython-modbus.readthedocs.io/en/latest/EXAMPLES.html#rtu | ||
rtu_pins = (25, 26) # (TX, RX) | ||
slave_addr = 10 # address on bus as client | ||
baudrate = 9600 | ||
uart_id = 1 | ||
|
||
from machine import Pin | ||
import os | ||
from umodbus import version | ||
|
||
print('Using pins {} with UART ID {}'.format(rtu_pins, uart_id)) | ||
|
||
client = ModbusRTU( | ||
addr=slave_addr, # address on bus | ||
pins=rtu_pins, # given as tuple (TX, RX) | ||
baudrate=baudrate, # optional, default 9600 | ||
# data_bits=8, # optional, default 8 | ||
# stop_bits=1, # optional, default 1 | ||
# parity=None, # optional, default None | ||
# ctrl_pin=12, # optional, control DE/RE | ||
uart_id=uart_id # optional, default 1, see port specific docs | ||
) | ||
|
||
if IS_DOCKER_MICROPYTHON: | ||
# works only with fake machine UART | ||
assert client._itf._uart._is_server is True | ||
|
||
|
||
def reset_data_registers_cb(reg_type, address, val): | ||
# usage of global isn't great, but okay for an example | ||
global client | ||
global register_definitions | ||
|
||
print('Resetting register data to default values ...') | ||
client.setup_registers(registers=register_definitions) | ||
print('Default values restored') | ||
|
||
|
||
# common slave register setup, to be used with the Master example above | ||
register_definitions = { | ||
"COILS": { | ||
"RESET_REGISTER_DATA_COIL": { | ||
"register": 42, | ||
"len": 1, | ||
"val": 0 | ||
}, | ||
"EXAMPLE_COIL": { | ||
"register": 123, | ||
"len": 1, | ||
"val": 1 | ||
} | ||
}, | ||
"HREGS": { | ||
"EXAMPLE_HREG": { | ||
"register": 93, | ||
"len": 1, | ||
"val": 19 | ||
} | ||
}, | ||
"ISTS": { | ||
"EXAMPLE_ISTS": { | ||
"register": 67, | ||
"len": 1, | ||
"val": 0 | ||
} | ||
}, | ||
"IREGS": { | ||
"EXAMPLE_IREG": { | ||
"register": 10, | ||
"len": 1, | ||
"val": 60001 | ||
} | ||
} | ||
} | ||
|
||
# alternatively the register definitions can also be loaded from a JSON file | ||
# this is always done if Docker is used for testing purpose in order to keep | ||
# the client registers in sync with the test registers | ||
if IS_DOCKER_MICROPYTHON: | ||
with open('registers/example.json', 'r') as file: | ||
register_definitions = json.load(file) | ||
|
||
# reset all registers back to their default value with a callback | ||
register_definitions['COILS']['RESET_REGISTER_DATA_COIL']['on_set_cb'] = \ | ||
reset_data_registers_cb | ||
|
||
print('Setting up registers ...') | ||
# use the defined values of each register type provided by register_definitions | ||
client.setup_registers(registers=register_definitions) | ||
# alternatively use dummy default values (True for bool regs, 999 otherwise) | ||
# client.setup_registers(registers=register_definitions, use_default_vals=True) | ||
print('Register setup done') | ||
|
||
print('Serving as RTU client on address {} at {} baud'. | ||
format(slave_addr, baudrate)) | ||
|
||
while True: | ||
try: | ||
result = client.process() | ||
except KeyboardInterrupt: | ||
print('KeyboardInterrupt, stopping RTU client...') | ||
break | ||
except Exception as e: | ||
print('Exception during execution: {}'.format(e)) | ||
|
||
print("Finished providing/accepting data as client") |
Oops, something went wrong.