Skip to content

A Modbus RTU (RS-485) to MQTT Gateway (based on ESP32)

License

Notifications You must be signed in to change notification settings

gmasse/esp-modbus-mqtt

Folders and files

NameName
Last commit message
Last commit date

Latest commit

3b40d27 · May 7, 2024

History

23 Commits
May 7, 2024
Mar 12, 2020
Oct 1, 2023
Mar 6, 2020
Mar 5, 2020
Mar 12, 2020
Mar 12, 2020
Mar 5, 2020
Mar 5, 2020
Mar 12, 2020
Mar 5, 2020
Mar 7, 2020
May 7, 2024
May 7, 2024

Repository files navigation

esp-modbus-mqtt: A Modbus RTU (RS-485) to MQTT Gateway (based on ESP32)

CI workflow

Circuit

Auto-switching UART-to-RS485 converter:


                   VCC ---------------+
                                      |
                              +-------x-------+
        (PIN27)    RXD <------| RX            |
                              |      UART    B|----------<> B
        (PIN26)    TXD ------>| TX    TO      |
ESP32                         |     RS-485    |     RS485 bus side
                              |               |
                              |              A|----------<> A
                              |               |
                              +-------x-------+
                                      |
                                     GND

Manual switching UART-to-RS485 converter:

                   VCC ---------------+
                                      |
                              +-------x-------+
        (PIN27)    RXD <------| R             |
                              |      UART    B|----------<> B
        (PIN26)    TXD ------>| D     TO      |
ESP32                         |     RS-485    |     RS485 bus side
        (PIN25)    RTS --+--->| DE            |
                         |    |              A|----------<> A
                         +----| /RE           |
                              +-------x-------+
                                      |
                                     GND

NB: ESP32 pins are configurable at compilation time.

Modbus

Device acts as Modbus Master, regurlaly polling a list of registers from a Modbus Slave.

List of Modbus parameters (in platformio.ini file):

  • modbus_rxd: RX/R pin number (default: 27)
  • modbus_txd: TX/D pin number (default: 26)
  • modbus_rts: DE/RE pin number (default: 25). If you don't need RTS, use NOT_A_PIN value.
  • modbus_baudrate (default: 9600)
  • modbus_unit: Modbus Slave ID (default: 10);
  • modbus_retries: if a Modbus request fails, number of retries before passing to the next register (default: 2)
  • modbus_scanrate: the device will attempt to poll the slave every XX seconds (default: 30)

Registers list is defined by the array registers[] in src/modbus_registers.h. A very simple example would be:

const modbus_register_t registers[] = {
    { 123, MODBUS_TYPE_HOLDING, REGISTER_TYPE_U16, "value_123" },
    { 124, MODBUS_TYPE_HOLDING, REGISTER_TYPE_U16, "value_124" }
};

Where:

  • 123 and 124 are register address to read,
  • MODBUS_TYPE_HOLDING is the Modbus object type to read,
  • REGISTER_TYPE_U16 is the expected format of the returned value,
  • value_123 and value_124 are the name in the JSON MQTT message

Supported Modbus objects:

  • HOLDING type is supported and has been tested
  • INPUT, COIL, DISCRETE and COUNT has not been tested but should work

Supported returned Value:

  • REGISTER_TYPE_U16: unsigned 16-bit integer
  • REGISTER_TYPE_BITFIELD: a sequence of 16 (or less) single bits; the first item maps the least significant bit
  • REGISTER_TYPE_DIEMATIC_ONE_DECIMAL: a specific De-Dietrich signed decimal implementation
  • REGISTER_TYPE_DEBUG: hexadecimal value only visible in INFO logs (not sent in MQTT message)
  • other types are not supported (TODO src/modbus_base.cpp:readModbusRegisterToJson)

MQTT

MQTT parameters are passed through environment variables:

  • PIO_MQTT_HOST_IP: MQTT broker IPv4
  • PIO_MQTT_PORT: MQTT broker port
  • PIO_MQTT_TOPIC: root prefix of the published topic

With PIO_MQTT_TOPIC=MyTopic, based on the register list example above, the published MQTT message will be:

Topic: MyTopic/ESP-MM-ABCDEF012345/data
Message: {"value_123":0,"value_124":65536}

Where ABCDEF012345 is the ESP unique Chip ID.

Compilation

git clone https://github.com/gmasse/esp-modbus-mqtt.git
cd esp-modbus-mqtt
python3 -m venv venv
source venv/bin/activate
pip install -U platformio
hash -r
cp platformio.ini.dist platformio.ini
(edit platformio.ini if needed)
export PIO_FIRMWARE_URL="http://domain.com/firmware.bin"
export PIO_MQTT_HOST_IP=11.22.33.44
export PIO_MQTT_PORT=1883
export PIO_MQTT_TOPIC=mytopic
platformio run

Built firmware will be at .pio/build/fm-devkit/firmware.bin You can upload to ESP with: platformio run upload

TODO

FAQ

Passing environment variables via VS Code

Edit .vscode/settings.json and add the following lines:

  "terminal.integrated.env.osx": {
    "PIO_FIRMWARE_URL": "https://url/firmware.bin",
    "PIO_MQTT_HOST_IP": "11.22.33.44",
    "PIO_MQTT_PORT": "1883",
    "PIO_MQTT_TOPIC": "mytopic"
  },

Flashing firmware

cp .plateformio/packages/framework-arduinoespressif32/tools/sdk/bin/bootloader_dio_40m.bin .
cp .platformio/packages/framework-arduinoespressif32/tools/partitions/default.bin .

esptool.py --chip esp32 --port /dev/ttyUSB1 --baud 460800 \
 --before default_reset --after hard_reset write_flash -z \
 --flash_mode dio --flash_freq 40m --flash_size detect \
 0x1000 bootloader_dio_40m.bin 0x8000 default.bin 0x10000 firmware.bin