ESP32 Modbus / RS-485 Gateway for Energy Meters & Heat Pumps (MAX485 → Home Assistant)

A huge amount of serious home energy hardware speaks Modbus RTU over RS-485:

  • DIN-rail energy meters (e.g. SDM120, SDM630, DDSU666, etc.)
  • Heat pumps, boilers, inverters, BMS controllers
  • Industrial sensors and controllers

With one ESP32 and a cheap MAX485 (RS-485) transceiver, you can build a gateway that:

  • Polls Modbus registers (voltage, current, power, kWh, temperatures, alarms)
  • Publishes the values into Home Assistant
  • Works fully local, no cloud

This guide covers:

  • Wiring an ESP32 to RS-485 (MAX485)
  • Modbus basics (address, baud rate, registers)
  • ESPHome Modbus configuration (recommended)
  • MQTT/Arduino alternative (optional)
  • Practical tips for SDM120/SDM630 and heat pump integrations

1. Modbus RTU & RS-485 in 2 minutes

  • RS-485 = physical layer (differential wires A/B, long distance, noise resistant)
  • Modbus RTU = protocol running over RS-485
  • One master (ESP32 gateway) polls one or more slaves (meter / heat pump)
  • Slaves have:
    • Address (1…247)
    • Baud rate (commonly 9600)
    • Parity/stop bits (often 8N1 or 8E1)
  • Data lives in registers:
    • Input registers (read-only)
    • Holding registers (read/write)
  • Values are often:
    • 16-bit or 32-bit
    • Scaled (e.g. “2305” means 230.5 V)
    • Sometimes floats (IEEE 754)

2. Hardware Required

  • ESP32 DevKit
  • MAX485 module (or equivalent RS-485 TTL transceiver)
  • RS-485 cable to meter / heat pump (twisted pair recommended)
  • Optional: 120 Ω termination resistor (only at bus ends)
  • Power supply for ESP32 (5 V USB is fine)

Important note about voltage levels:

  • MAX485 modules typically run from 5 V (some are 3.3 V tolerant, many are not)
  • The ESP32 UART pins are 3.3 V
  • In practice, many MAX485 boards work with ESP32 without issues, but for “proper” engineering:
    • Use a 3.3 V compatible transceiver (e.g. SP3485, MAX3485) or
    • Ensure logic-level compatibility

If you want the safest choice: buy a MAX3485 / SP3485 “3.3 V RS485” module.


3. Wiring ESP32 ↔ RS-485 (MAX485)

MAX485 module pins typically:

  • VCC, GND
  • RO (Receiver Output)
  • DI (Driver Input)
  • RE (Receiver Enable) – active LOW
  • DE (Driver Enable) – active HIGH
  • A, B (RS-485 differential pair)

3.1 Recommended ESP32 Wiring (Half-Duplex)

Use one UART (example GPIO16/17) + one direction control GPIO:

ESP32                 MAX485
-----                 ------
5V   ---------------- VCC
GND  ---------------- GND

GPIO17 (TX) --------- DI
GPIO16 (RX) --------- RO

GPIO4  -------------  DE and RE (tied together)
                      (DE=HIGH transmit, RE=LOW receive)

RS-485 A ------------ A
RS-485 B ------------ B

Direction control:

  • Many libraries (and ESPHome) support a “flow control pin” to toggle transmit/receive.
  • Often you connect:
    • DE and RE together
    • Drive them with a single GPIO

If your module labels RE as RE/ or ~RE, remember it’s inverted (active low).


4. RS-485 Bus Tips (Avoid Pain)

  • Use a twisted pair for A/B
  • Keep GND reference if possible (some devices need it)
  • Termination:
    • Only needed at long distances / high speed
    • If used, place 120 Ω across A/B at the two ends of the bus
  • Bias resistors:
    • Some buses need pull-up/pull-down biasing (often built into equipment)
  • If values are garbage:
    • A/B swapped is common → just swap them and retry

METHOD 1 — ESPHome Modbus Gateway (Recommended)

ESPHome can talk Modbus RTU and expose sensors directly into Home Assistant.

5. ESPHome Base Config + UART

esphome:
  name: esp32-modbus-gateway
  platform: ESP32
  board: esp32dev

wifi:
  ssid: "YOUR_WIFI"
  password: "YOUR_PASSWORD"

logger:
api:
ota:

uart:
  id: modbus_uart
  tx_pin: 17
  rx_pin: 16
  baud_rate: 9600
  stop_bits: 1

If your device uses parity (common on some meters), add:

  parity: EVEN

6. Add Modbus Layer + Controller

modbus:
  id: modbus1
  uart_id: modbus_uart
  flow_control_pin: 4   # DE/RE control pin

Now define a controller per slave address:

modbus_controller:
  - id: sdm120
    address: 1
    modbus_id: modbus1
    setup_priority: -10
    update_interval: 5s

7. Example: SDM120 (Single Phase Meter)

SDM meters have well-known register maps (you’ll match to your manual).
Below is a typical pattern for voltage, current, power, energy (register numbers vary by model/firmware; verify in your SDM120 documentation).

sensor:
  - platform: modbus_controller
    modbus_controller_id: sdm120
    name: "SDM120 Voltage"
    id: sdm120_voltage
    register_type: holding
    address: 0x0000
    unit_of_measurement: "V"
    accuracy_decimals: 1
    value_type: FP32

  - platform: modbus_controller
    modbus_controller_id: sdm120
    name: "SDM120 Current"
    register_type: holding
    address: 0x0006
    unit_of_measurement: "A"
    accuracy_decimals: 2
    value_type: FP32

  - platform: modbus_controller
    modbus_controller_id: sdm120
    name: "SDM120 Active Power"
    register_type: holding
    address: 0x000C
    unit_of_measurement: "W"
    accuracy_decimals: 1
    value_type: FP32

  - platform: modbus_controller
    modbus_controller_id: sdm120
    name: "SDM120 Energy Import"
    register_type: holding
    address: 0x0156
    unit_of_measurement: "kWh"
    accuracy_decimals: 2
    value_type: FP32

Key fields explained:

  • address: is the Modbus register address
  • register_type: holding vs input (depends on device)
  • value_type: FP32 means 32-bit float
  • update_interval: in controller controls polling rate

If your meter uses input registers, change:

register_type: input

8. Example: SDM630 (Three Phase Meter)

You typically read per-phase voltage/current + total power + total energy.

Set controller address (example 2):

modbus_controller:
  - id: sdm630
    address: 2
    modbus_id: modbus1
    update_interval: 5s

Then define sensors similarly:

  • Voltage L1/L2/L3
  • Current L1/L2/L3
  • Total active power
  • Total import/export kWh

(Exact register addresses depend on your SDM630 map.)


9. Example: Heat Pump via Modbus

Heat pumps commonly expose:

  • Flow temperature
  • Return temperature
  • Outdoor temp
  • Compressor frequency
  • Mode (heat/cool/dhw)
  • Alarms

The structure is the same:

  1. Set the correct Modbus address, baud rate, parity
  2. Read registers based on the vendor map
  3. Apply scaling (sometimes ×0.1 or ×0.01)

If a register holds “235” meaning 23.5°C, you use filters:

filters:
  - multiply: 0.1

Example:

sensor:
  - platform: modbus_controller
    modbus_controller_id: heatpump
    name: "Heat Pump Flow Temp"
    register_type: input
    address: 0x0100
    unit_of_measurement: "°C"
    accuracy_decimals: 1
    value_type: U_WORD
    filters:
      - multiply: 0.1

METHOD 2 — Arduino + MQTT Modbus Gateway (Alternative)

If you prefer “raw MQTT”:

  • ESP32 reads Modbus registers with a library like ModbusMaster
  • Builds JSON payload
  • Publishes to MQTT topic like home/modbus/sdm120

Example payload:

{
  "voltage": 230.4,
  "current": 1.82,
  "power": 412.0,
  "energy_kwh": 18.25
}

Home Assistant then uses the same mqtt: sensor: pattern you already use.

This method is flexible but requires more code and careful error handling.


10. Home Assistant Integration Ideas

10.1 Energy Dashboard

If you publish/import kWh correctly, you can feed Home Assistant’s Energy Dashboard (especially if you have solar / battery).

10.2 Alerts

  • Notify if power draw exceeds a threshold
  • Notify if heat pump reports an alarm register
  • Notify if voltage drops below a safe level

10.3 Logging & Stats

Once data is in HA, it becomes part of:

  • history graphs
  • statistics
  • long-term energy monitoring

11. Troubleshooting Checklist (Most Common Failures)

  • A/B swapped: swap them if no response
  • Wrong baud/parity: check device manual (9600 8N1 vs 9600 8E1 is common)
  • Wrong slave address: many meters default to 1, but not always
  • No direction control: ensure DE/RE pin is working if using MAX485
  • Register map mismatch: SDM models differ; confirm addresses and data types
  • Float word order: some devices swap 16-bit words (endianness). ESPHome supports different value_type variants if needed.

Summary

An ESP32 + RS-485 transceiver turns Modbus RTU devices into Home Assistant entities:

  • Works for DIN energy meters like SDM120/SDM630 and many heat pumps
  • ESPHome is the easiest path: UART + modbus + modbus_controller + sensors
  • Once values are in HA, you can build dashboards, automations, and energy insights

The key is matching:

  • slave address
  • baud/parity
  • register map + data type + scaling

Get those right and Modbus becomes one of the most powerful “serious hardware” integrations you can add to Home Assistant.

Share your love

Leave a Reply

Your email address will not be published. Required fields are marked *