Arduino-based Modbus TCP slave device for remote relay control from a SCADA system.
The device receives relay commands over Modbus TCP, runs the relay for a configurable time interval, reports the current relay state and remaining time back to SCADA, and stores the configured relay time in EEPROM so it survives power loss.
- Modbus TCP slave for SCADA integration.
- Relay control through Modbus coils.
- Relay timer enable/disable through a separate Modbus coil.
- Configurable relay runtime through a holding register.
- Relay state, timer enable state, and remaining timer value exposed through input registers.
- EEPROM storage for the relay runtime and timer enable settings.
- Non-blocking relay timer based on
millis(). - Ethernet link watchdog for W5100/W5500 recovery after cable disconnect/reconnect.
- Optional hardware reset line for the W5100 Ethernet module.
- Uses the
ModbusTCP_RUlibrary.
This project is built on top of my Arduino Modbus TCP library:
The firmware uses this library to expose coils, input registers, holding registers, and write callbacks for SCADA-side control.
Tested target hardware:
- Arduino-compatible controller.
- W5100 or W5500 Ethernet module/shield.
- Relay module.
- SCADA or Modbus Poll client on the same TCP/IP network.
Default pin assignment:
| Signal | Arduino pin | Notes |
|---|---|---|
| Relay output | 2 |
Active LOW relay module logic |
| W5100 reset | 3 |
Drives Ethernet module reset line |
| Ethernet CS | 10 |
Set with Ethernet.init(10) |
Default firmware network settings:
byte mac[] = {0x02, 0x47, 0xA1, 0x10, 0x00, 0x04};
IPAddress ip(192, 168, 0, 178);
IPAddress gateway(192, 168, 0, 1);
IPAddress subnet(255, 255, 255, 0);Modbus TCP port: 502.
Change these values in the sketch before uploading if your network uses a different subnet or the MAC address conflicts with another device.
See docs/modbus-map.md for the full register map and Modbus Poll examples.
Short version:
| Type | Address | Function | Description |
|---|---|---|---|
| Coil | 0 |
FC01, FC05, FC15 |
Relay command: 0 = OFF, 1 = ON |
| Coil | 1 |
FC01, FC05, FC15 |
Relay timer enable: 0 = disabled, 1 = enabled |
| Input Register | 0 |
FC04 |
Actual relay state: 0 = OFF, 1 = ON |
| Input Register | 1 |
FC04 |
Remaining relay time in seconds |
| Input Register | 2 |
FC04 |
Relay timer enabled state: 0 = disabled, 1 = enabled |
| Holding Register | 0 |
FC03, FC06, FC16 |
Relay runtime in seconds |
Default relay runtime: 300 seconds.
Allowed relay runtime range: 1 to 3600 seconds.
The Arduino sketch is located in:
firmware/ScadaRelayTimer/ScadaRelayTimer.ino
Required libraries:
SPIEthernetEEPROMModbusTCP_RU
- SCADA writes
1toCoil 0. - The Arduino turns the relay on.
- If
Coil 1is ON, the relay timer starts. - SCADA reads the relay state and remaining time from input registers.
- When the timer is enabled and expires, the relay turns off automatically.
- SCADA can write a new runtime value to
Holding Register 0. - The new runtime value and timer enable state are saved to EEPROM.
Turn the relay on or off:
Function: 05 Write Single Coil
Address: 0
Value: ON / OFF
Enable or disable the relay timer:
Function: 05 Write Single Coil
Address: 1
Value: ON / OFF
Read relay state and remaining time:
Function: 04 Read Input Registers
Address: 0
Quantity: 3
Read configured relay runtime:
Function: 03 Read Holding Registers
Address: 0
Quantity: 1
Write a new relay runtime:
Function: 06 Write Single Register
Address: 0
Value: 120
Writing 120 makes the relay run for 120 seconds. The value is saved in EEPROM and remains after power cycling.
Rapid SCADA screenshots showing the device configuration and relay control test.
This project was created as a modernization of an existing relay control device. The old MgsModbus dependency was removed and replaced with ModbusTCP_RU.
This repository currently includes an MIT license draft. Review and change it before publishing if you prefer a different license.




