MQTT Application Overview
The WIZ-RTU MQTT application initializes the board hardware, configures the WIZnet Ethernet interface, connects to the MQTT broker, subscribes to registered command topics, publishes the initial device state, and then starts its polling loop.
Board boots
|
v
Initialize hardware and Ethernet
|
v
Load mqtt.json
|
v
Connect to MQTT broker
|
v
Subscribe to command topics
|
v
Publish initial states
|
v
Poll hardware and process MQTT messages
The MQTT loop performs:
self.poll()
self.check_msg()
time.sleep_ms(100)
This means the device checks peripherals and incoming MQTT messages approximately every 100 ms, excluding processing and network time.
Network and Broker Configuration
The Ethernet interface uses network.WIZNET5K with the following default pins:
Signal |
Pin |
|---|---|
SPI bus |
|
SPI baud rate |
|
CS |
|
RST |
|
PWR / enable |
|
The device first attempts to use DHCP. If DHCP fails, it falls back to:
Field |
Default value |
|---|---|
IP address |
|
Subnet mask |
|
Gateway |
|
DNS |
|
MQTT broker settings are loaded from mqtt.json:
{
"host": "10.0.1.238",
"username": null,
"password": null,
"port": 1883
}
To create mqtt.json, simply rename the file mqtt.default.json to mqtt.json and enter your MQTT broker’s corresponding configurations.
Note
Here you should input your broker’s IP address and other information.
If you use your personal PC as the broker, run ipconfig to get your PC IP under the local network and enter the IP to mqtt.json.
If a value is missing, the following defaults are used:
Field |
Fallback value |
|---|---|
Host |
|
Username |
|
Password |
|
Port |
|
The MQTT client ID is generated from the board MAC address.
If umqtt.simple is unavailable, the application attempts to install it into /flash using mip.
Note
In newer firmware builds, umqtt should already be frozen into the firmware, so an online installation should normally not be required.
MQTT Topic Summary
The application uses command topics for requests received by the device and state or response topics for data published by the device.
Subscribed command topics
Topic |
Payload |
Description |
|---|---|---|
|
JSON |
Changes the Ethernet configuration. |
|
JSON |
Changes one digital output. |
|
JSON |
Changes one analog output voltage. |
|
UTF-8 data |
Sends data through UART3. |
|
UTF-8 data |
Writes data to EEPROM. |
|
JSON |
Requests EEPROM data from an index. |
|
Text |
Wipes EEPROM when the payload is exactly |
Published state and response topics
Topic |
Payload |
Description |
|---|---|---|
|
JSON |
Current Ethernet configuration. |
|
JSON |
Current digital input pin value. |
|
JSON |
Resulting digital output value. |
|
JSON |
Averaged analog input values and modes. |
|
JSON |
Requested analog output voltage. |
|
UART data |
Data received from UART3. |
|
Raw bytes |
EEPROM data returned after a read request. |
Topics are registered with the add_topic() decorator:
@client.add_topic("uart/write")
def write_to_uart(msg):
pass
For normal topics, the handler receives the payload:
def handler(msg):
pass
For the current digital-output and analog-output wildcard topics, the handler receives the captured pin and the payload:
def handler(pin, msg):
pass
For example, a message sent to:
digital_output/RY1/set
is matched against:
digital_output/+/set
and calls:
handler(b"RY1", msg)
Note
The current wildcard dispatcher only handles topic families beginning with digital_output or analog_output.
Initial State and Retained Messages
After connecting, the device publishes:
Current network configuration.
All eight digital input states.
All eight digital output states.
All four analog input values and modes.
Initial analog output states.
This allows an MQTT dashboard to display the current device state immediately after subscribing.
The general publish() helper uses:
retain=True
Therefore, state messages published through this helper are retained by the broker.
This includes:
network_config/state
digital_input/IN1/state
digital_output/RY1/state
analog_input/state
analog_output/AO0/state
The following topics are published directly and are not explicitly retained by the application:
uart/read
eeprom/read/response
Command topics should normally not be retained because a retained command could be delivered again when the device reconnects.
Network Configuration Topics
Read the current network state
The device publishes its network configuration to:
network_config/state
Example payload:
{
"ip": "10.0.1.109",
"mask": "255.255.255.0",
"gateway": "10.0.1.254",
"dns": "8.8.8.8",
"dhcp": true
}
Change the network configuration
Publish to:
network_config/set
Use DHCP:
{
"dhcp": true
}
Use a static IP address:
{
"dhcp": false,
"ip": "10.0.1.109",
"subnet_mask": "255.255.255.0",
"default_gateway": "10.0.1.254",
"dns": "8.8.8.8"
}
After receiving the request, the application disconnects MQTT, reinitializes Ethernet, sets the restart flag, and starts the MQTT runtime again with the new configuration.
Warning
The current MQTT handler does not call validate_ipv4() before applying a static configuration. Ensure all submitted IPv4 values are valid.
Digital I/O Topics
The program supports:
Type |
Names |
|---|---|
Digital inputs |
|
Digital outputs |
|
Set a digital output
Topic pattern:
digital_output/<pin>/set
Example:
digital_output/RY1/set
Payload:
{
"value": 1
}
If value is missing, the handler uses 0.
The resulting pin state is published to:
digital_output/RY1/state
Example response:
{
"value": 1
}
Monitor digital inputs
Digital inputs are published to:
digital_input/<pin>/state
Example:
digital_input/IN1/state
Payload:
{
"value": 1
}
The device publishes a new message only when the physical input value changes.
Note
The payload contains the physical pin value. The MQTT layer does not invert active-low inputs.
Analog I/O Topics
The program supports:
Type |
Names |
|---|---|
Analog inputs |
|
Analog outputs |
|
Default analog input modes:
Input |
Mode |
Unit |
|---|---|---|
|
Current |
mA |
|
Current |
mA |
|
Voltage |
V |
|
Voltage |
V |
Mode values:
Value |
Meaning |
|---|---|
|
Voltage mode |
|
Current mode |
Monitor analog inputs
All channels are published together on:
analog_input/state
Example payload:
{
"AI0": {
"value": 12.3,
"mode": 1
},
"AI1": {
"value": 11.8,
"mode": 1
},
"AI2": {
"value": 2.5,
"mode": 0
},
"AI3": {
"value": 3.1,
"mode": 0
}
}
Each channel collects ten readings before publishing an average. With the default loop delay, analog data is normally published about once per second.
Reported values are limited to:
Mode |
Maximum reported value |
|---|---|
Voltage mode |
|
Current mode |
|
The conversion formulas are:
# Current mode
current_ma = (voltage / 120) * 1000
# Voltage mode
input_voltage = (voltage * 14.7) / 4.7
Set an analog output
Topic pattern:
analog_output/<pin>/set
Example:
analog_output/AO0/set
Payload:
{
"voltage": 5.0
}
If voltage is missing, the handler uses 0.
The requested value is published to:
analog_output/AO0/state
The DAC uses 12-bit values from 0 to 4095.
Calibration values:
Output |
Minimum measured voltage |
Maximum measured voltage |
|---|---|---|
|
|
|
|
|
|
Requested voltages outside the supported range are clamped to the DAC limits.
Serial UART Topics
UART communication uses UART(3).
Fallback settings:
Field |
Fallback value |
|---|---|
Baud rate |
|
Data bits |
|
Parity |
|
Stop bits |
|
Send UART data
Publish UTF-8 data to:
uart/write
Example:
hello from MQTT
Receive UART data
UART data is published to:
uart/read
The device checks UART during every polling cycle, reads all available bytes, and decodes them as UTF-8 with replacement characters.
EEPROM Topics
The EEPROM uses software I2C:
Signal |
Pin |
|---|---|
SCL |
|
SDA |
|
The EEPROM is considered connected only when the I2C scan contains every address from 0x50 to 0x57.
Limits:
Operation |
Maximum size |
|---|---|
Write |
|
Read |
|
Write data
Publish UTF-8 data to:
eeprom/write
Example:
hello from WIZ-RTU
The default write index is 0.
Read data
First, request a read from eeprom by publishing to:
eeprom/read/request
Payload:
{
"index": 0
}
If index is missing, the handler uses 0.
THen, the eeprom read result will be published as raw bytes to:
eeprom/read/response
Wipe data
Publish to:
eeprom/wipe
Required payload:
True
The comparison is case-sensitive.
Warning
Wiping EEPROM removes its stored contents and normally cannot be undone.
Runtime, Restart, and Error Behavior
When the network configuration changes, the application:
Disconnects from MQTT.
Reinitializes Ethernet.
Sets
client.restart = True.Exits the current MQTT loop.
Starts the MQTT runtime again.
Common error behavior:
Situation |
Behavior |
|---|---|
MQTT connection fails |
|
Unknown topic is received |
The message is ignored. |
Invalid JSON command payload |
The handler returns without applying the command. |
Invalid output name |
The device prints an error and returns |
EEPROM is unavailable |
EEPROM operations fail their assertion check. |
Runtime exception |
The error is printed, MQTT disconnects, and the application exits. |
|
MQTT disconnects and the application exits without printing a normal runtime error. |
Debug output is controlled by:
DEBUG = False
Set it to True to enable dprint() messages.
Customizing the MQTT Application
Edit mqtt_app.py to add, remove, or change subscribed command topics and their handlers.
Example:
@client.add_topic("custom/topic")
def handle_custom_topic(msg):
print("Received:", msg)
Use device_mqtt.py only when changing lower-level behavior such as:
MQTT connection handling.
Subscription and dispatch logic.
Polling intervals.
Automatic state publication.
Retained-message behavior.
Use device.py only when changing the underlying GPIO, ADC, DAC, UART, I2C, or EEPROM behavior.
Example Usage With Mosquitto
Replace 10.0.1.238 with your broker address.
Monitor all topics:
mosquitto_sub -h 10.0.1.238 -t "#" -v
Turn on RY1:
mosquitto_pub -h 10.0.1.238 \
-t "digital_output/RY1/set" \
-m '{"value":1}'
Set AO0 to 5.0 V:
mosquitto_pub -h 10.0.1.238 \
-t "analog_output/AO0/set" \
-m '{"voltage":5.0}'
Monitor analog inputs:
mosquitto_sub -h 10.0.1.238 \
-t "analog_input/state" -v
Send UART data:
mosquitto_pub -h 10.0.1.238 \
-t "uart/write" \
-m "hello"
Write EEPROM data:
mosquitto_pub -h 10.0.1.238 \
-t "eeprom/write" \
-m "hello from WIZ-RTU"
Request EEPROM data:
mosquitto_pub -h 10.0.1.238 \
-t "eeprom/read/request" \
-m '{"index":0}'
Request DHCP:
mosquitto_pub -h 10.0.1.238 \
-t "network_config/set" \
-m '{"dhcp":true}'