MQTT Application Overview

The WIZio-SEN MQTT application initializes the board hardware, configures the WIZnet Ethernet interface, connects to the MQTT broker, subscribes to the 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)

The device therefore checks peripherals and incoming MQTT messages approximately every 100 ms, excluding processing and network time.


Network and Broker Configuration

The Ethernet interface is initialized by setup.py using the WIZnet network interface with these pins:

Signal

Pin

SPI bus

SPI(2)

SPI baud rate

8,000,000

CS

PB12

RST

PD9

PWR / enable

PE15

The supplied config.py enables DHCP:

DHCP = True

If DHCP is disabled or fails, the fallback static configuration in setup.py is:

Field

Default value

IP address

192.168.1.2

Subnet mask

255.255.255.0

Gateway

192.168.1.1

DNS

192.168.1.1

MQTT broker settings are loaded from mqtt.json:

{
    "host": "10.0.1.238",
    "username": null,
    "password": null,
    "port": 1883
}

To create mqtt.json, copy mqtt.default.json and enter the broker address and authentication settings for your network.

If a value is missing, device_mqtt.py uses these fallbacks:

Field

Fallback value

Host

127.0.0.1

Username

None

Password

None

Port

1883

The MQTT client ID is generated from the WIZnet chip MAC address. If umqtt.simple is unavailable, the application attempts to install it into /flash using mip after the network is connected.


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

network_config/set

JSON

Changes the Ethernet configuration.

digital_output/+/set

JSON

Changes one relay output.

analog_output/+/set

JSON

Handler exists, but no analog-output channels are configured by default.

uart/write

UTF-8 data

Sends data through the RS485/UART interface.

eeprom/write

UTF-8 data

Writes data to EEPROM at index 0.

eeprom/read/request

JSON

Requests EEPROM data from an index.

eeprom/wipe

Text

Wipes EEPROM when the payload is exactly True.

Published state and response topics

Topic

Payload

Description

network_config/state

JSON

Current Ethernet configuration.

digital_input/INx/state

JSON

Current digital input value for IN1 or IN2.

digital_output/RYx/state

JSON

Resulting relay output value for RY1 or RY2.

analog_input/state

JSON

Analog values and input modes for AI0 and AI1.

serial_mode

JSON

Reports RS485 for the supplied configuration.

uart/read

UTF-8 data

Data received from the RS485/UART interface.

eeprom/read/response

Raw bytes

EEPROM data returned after a read request.

loadcell/weight

Text number

Averaged load-cell weight in kilograms.

temp/k1

Text number

Optional K-type channel 1 temperature in degrees Celsius.

temp/k2

Text number

Optional K-type channel 2 temperature in degrees Celsius.

Topics are registered with the add_topic() decorator. The current wildcard dispatcher gives the captured pin to handlers for digital_output/+/set and analog_output/+/set:

@client.add_topic("digital_output/+/set")
def handle_digital_output(pin, msg):
    pass

For normal topics, the handler receives only the payload:

@client.add_topic("uart/write")
def write_to_uart(msg):
    pass

Initial State and Retained Messages

After connecting, the device publishes:

  • Current network configuration.

  • Both digital input states.

  • Both relay output states.

  • The analog input state.

  • Initial analog-output states if analog-output channels are configured.

  • The selected serial mode.

The general publish() helper uses retain=True, so state messages published through that helper are retained by the broker. This includes topics such as:

network_config/state
digital_input/IN1/state
digital_output/RY1/state
analog_input/state
serial_mode
loadcell/weight
temp/k1
temp/k2

UART receive data is published directly through umqtt.simple and is not explicitly retained. Command topics should normally not be retained because a retained command may be delivered again when the device reconnects.


Network Configuration Topics

Read the current network state

The device publishes its current Ethernet configuration to:

network_config/state

Example payload:

{
    "ip": "192.168.1.50",
    "mask": "255.255.255.0",
    "gateway": "192.168.1.1",
    "dns": "192.168.1.1",
    "dhcp": false
}

Change the network configuration

Publish to:

network_config/set

Use DHCP:

{
    "dhcp": true
}

Use a static address:

{
    "dhcp": false,
    "ip": "192.168.1.50",
    "mask": "255.255.255.0",
    "gateway": "192.168.1.1",
    "dns": "192.168.1.1"
}

The handler validates each IPv4 address, disconnects MQTT, reinitializes the WIZnet interface, sets the restart flag, and reconnects using the new network settings.


Digital I/O Topics

The supplied device configuration supports:

Type

Names

Digital inputs

IN1, IN2

Relay outputs

RY1, RY2

Set a relay output

Topic pattern:

digital_output/<pin>/set

Example:

digital_output/RY1/set

Payload:

{
    "value": 1
}

Use 0 to turn the relay off. If value is missing, the handler uses 0. The resulting state is published to:

digital_output/RY1/state

Monitor digital inputs

Digital inputs are published to:

digital_input/<pin>/state

Example payload:

{
    "value": 1
}

The device publishes a new input message only when the physical input value changes. The MQTT layer publishes the physical pin value without inverting active-low inputs.


Analog Input Topics

The supplied device configuration supports two analog inputs:

Input

Mode

Unit

AI0

Current

mA

AI1

Current

mA

The mode values are:

Value

Meaning

0

Voltage mode

1

Current mode

All analog inputs are published together on:

analog_input/state

Example payload:

{
    "AI0": {
        "value": 12.3,
        "mode": 1
    },
    "AI1": {
        "value": 11.8,
        "mode": 1
    }
}

The application collects ten readings before publishing an average. Current-mode readings are calculated with:

current_ma = (voltage / 120) * 1000

Voltage-mode readings are calculated with:

input_voltage = (voltage * 14.7) / 4.7

Reported values are limited to 20 mA in current mode and 10 V in voltage mode.

The MQTT handler includes analog_output/+/set, but MAX_AO is 0 in device.py, so the supplied WIZio-SEN application has no analog-output channels by default.


Serial UART Topics

device.py initializes UART4 from config.py. The supplied config.py contains:

Field

Value

Baud rate

9600

Data bits

8

Parity

None

Stop bits

1

The selected interface is reported during startup on:

serial_mode

Example payload:

{
    "Mode": "RS485"
}

Send UART data

Publish UTF-8 data to:

uart/write

Example:

hello from MQTT

Receive UART data

Data received from UART4 is published to:

uart/read

The device reads available bytes during each polling cycle and decodes them as UTF-8 with replacement characters when necessary.


EEPROM Topics

The onboard EEPROM uses software I2C:

Signal

Pin

SCL

PB6

SDA

PB7

The EEPROM driver is initialized when the expected EEPROM addresses are detected. Each read and write is limited to 1000 bytes.

Write data

Publish UTF-8 data to:

eeprom/write

Example:

board-name=WIZio-SEN

The supplied handler writes at index 0.

Read data

Publish a JSON request to:

eeprom/read/request

Payload:

{
    "index": 0
}

If index is missing, the handler uses 0. The result is published as raw bytes to:

eeprom/read/response

Wipe data

Publish to:

eeprom/wipe

Required payload:

True

The comparison is case-sensitive.

Warning

Wiping the EEPROM removes its stored contents and normally cannot be undone.


Load-Cell Topic

Load-cell support is enabled by the supplied configuration:

LOADCELL_CAPACITY_KG = 10.0
LOADCELL_RATED_OUTPUT = 2.0

The application expects a 10 kg, 2 mV/V load cell with 10 V excitation. Update these values in config.py for a different sensor.

The device averages load-cell readings and publishes the result in kilograms to:

loadcell/weight

Thermocouple Topics

The runtime contains non-blocking CS1237/CS1238 support for two K-type channels. When the temperature settings are defined in config.py, the device publishes readings to:

temp/k1
temp/k2

The readings are published in degrees Celsius after cold-junction compensation.

The supplied config.py does not define CELSIUS_MIN, CELSIUS_MAX, or CELSIUS_PGA, so thermocouple support is disabled in the supplied configuration.


Runtime, Restart, and Error Behavior

When the network configuration changes, the application:

  1. Disconnects from MQTT.

  2. Reinitializes Ethernet.

  3. Sets client.restart = True.

  4. Exits the current MQTT loop.

  5. Starts the MQTT runtime again.

Common behavior:

Situation

Behavior

MQTT connection fails

The MQTT run raises a connection error and disconnects.

Unknown topic is received

The message is ignored.

Invalid JSON command payload

The handler returns without applying the command.

Invalid relay pin

The device reports an error and returns -1.

EEPROM is unavailable

EEPROM operations cannot complete.

Runtime exception

The error is printed, MQTT disconnects, and the application exits.

KeyboardInterrupt

MQTT disconnects and the application exits.

Debug output is controlled by:

DEBUG = True

Set it to False to disable dprint() output.


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 dispatch, polling intervals, automatic state publication, or retained-message behavior.

Use device.py when changing the underlying GPIO, ADC, UART, I2C, EEPROM, load-cell, or thermocouple behavior.

The main files have these responsibilities:

  • mqtt_app.py defines subscribed command topics and their handlers.

  • device_mqtt.py manages the MQTT connection, subscriptions, polling, and published state topics.

  • device.py provides the WIZio-SEN hardware functions.

  • setup.py initializes the WIZnet Ethernet interface.

  • mqtt.json stores the broker connection settings.

  • main.py starts the MQTT application.


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}'

Monitor digital input states:

mosquitto_sub -h 10.0.1.238 \
  -t "digital_input/+/state" -v

Monitor analog inputs:

mosquitto_sub -h 10.0.1.238 \
  -t "analog_input/state" -v

Send RS485 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 WIZio-SEN"

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}'