Hello,
I am looking for a Modbus TCP server library, because I would like to connect the
ESP32 POE board as a Modbus server to a Siemens PLC.
I was able to find examples for Arduino MKR WiFi 1010 via Ethernet shield (W5500)
and for Arduino NanoV3 via Ethernet shield (ENC28J60). Both work fine. But I was
not able to find an example/tutorial for the ESP32 working as a Modbus TCP server
via the hardwired Ethernet interface (LAN8710A chip).
I got the "ESP32_PoE_Ethernet_SD_Card_Arduino" example running. Even with a fixed
IP adress. But I am stuck on this Modbus TCP topic. Any help is appreciated.
Thanks
Hello,
Were you successful in finding a solution? I am looking for the same.
Hi! I'm trying exactly the same. I was able to actually connect to the Modbus server on the ESP32 POE using this:
#include <Arduino.h>
#include "ModbusServerWiFi.h"
char ssid[] = "YOUR_SSID";
char pass[] = "YOUR_PW";
// Set up a Modbus server
ModbusServerWiFi MBserver;
IPAddress lIP; // assigned local IP
const uint8_t MY_SERVER(1);
uint16_t memo[128]; // Test server memory
// Worker function for serverID=1, function code 0x03 or 0x04
ModbusMessage FC03(ModbusMessage request) {
uint16_t addr = 0; // Start address to read
uint16_t wrds = 0; // Number of words to read
ModbusMessage response;
// Get addr and words from data array. Values are MSB-first, get() will convert to binary
request.get(2, addr);
request.get(4, wrds);
// address valid?
if (!addr || addr > 128) {
// No. Return error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
return response;
}
// Modbus address is 1..n, memory address 0..n-1
addr--;
// Number of words valid?
if (!wrds || (addr + wrds) > 127) {
// No. Return error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
return response;
}
// Prepare response
response.add(request.getServerID(), request.getFunctionCode(), (uint8_t)(wrds * 2));
// Loop over all words to be sent
for (uint16_t i = 0; i < wrds; i++) {
// Add word MSB-first to response buffer
response.add(memo[addr + i]);
}
// Return the data response
return response;
}
void setup() {
// Init Serial
Serial.begin(115200);
while (!Serial) {}
Serial.println("__ OK __");
// Register the worker function with the Modbus server
MBserver.registerWorker(MY_SERVER, READ_HOLD_REGISTER, &FC03);
// Register the worker function again for another FC
MBserver.registerWorker(MY_SERVER, READ_INPUT_REGISTER, &FC03);
// Connect to WiFi
WiFi.begin(ssid, pass);
delay(200);
while (WiFi.status() != WL_CONNECTED) {
Serial.print('.');
delay(1000);
}
// print local IP address:
lIP = WiFi.localIP();
Serial.printf("My IP address: %u.%u.%u.%u\n", lIP[0], lIP[1], lIP[2], lIP[3]);
// Initialize server memory with consecutive values
for (uint16_t i = 0; i < 128; ++i) {
memo[i] = (i * 2) << 8 | ((i * 2) + 1);
}
// Start the Modbus TCP server:
// Port number 502, maximum of 4 clients in parallel, 10 seconds timeout
MBserver.start(502, 4, 10000);
}
void loop() {
static uint32_t statusTime = millis();
const uint32_t statusInterval(10000);
// We will be idling around here - all is done in subtasks :D
if (millis() - statusTime > statusInterval) {
Serial.printf("%d clients running.\n", MBserver.activeClients());
statusTime = millis();
}
delay(100);
}
I can connect to it from my laptop (via Python pyModbusTCP.client). However, I'm not sure how to proceed as from here. Ultimately I want the ESP32 POE to react on something on the GPIO pins and send a modbus signal to another modbus Server based on that.
I did make an attempt to do it via ethernet, which connects, receives an IP address, but now I cannot reach the modbus server on the ESP32 POE.
#include <Arduino.h>
#include "ModbusServerEthernet.h"
#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT
#define ETH_PHY_POWER 12
#include <ETH.h>
// Set up a Modbus server
ModbusServerEthernet MBserver;
// Create server
uint16_t memo[32]; // Test server memory: 32 words
// Server function to handle FC 0x03 and 0x04
ModbusMessage FC03(ModbusMessage request)
{
Serial.println(request);
ModbusMessage response; // The Modbus message we are going to give back
uint16_t addr = 0; // Start address
uint16_t words = 0; // # of words requested
request.get(2, addr); // read address from request
request.get(4, words); // read # of words from request
// Address overflow?
if ((addr + words) > 20)
{
// Yes - send respective error response
response.setError(request.getServerID(), request.getFunctionCode(), ILLEGAL_DATA_ADDRESS);
}
// Set up response
response.add(request.getServerID(), request.getFunctionCode(), (uint8_t)(words * 2));
// Request for FC 0x03?
if (request.getFunctionCode() == READ_HOLD_REGISTER)
{
// Yes. Complete response
for (uint8_t i = 0; i < words; ++i)
{
// send increasing data values
response.add((uint16_t)(memo[addr + i]));
}
}
else
{
// No, this is for FC 0x04. Response is random
for (uint8_t i = 0; i < words; ++i)
{
// send increasing data values
response.add((uint16_t)random(1, 65535));
}
}
// Send response back
return response;
}
static bool eth_connected = false;
void WiFiEvent(WiFiEvent_t event)
{
switch (event) {
case SYSTEM_EVENT_ETH_START:
Serial.println("ETH Started");
//set eth hostname here
ETH.setHostname("esp32-ethernet");
break;
case SYSTEM_EVENT_ETH_CONNECTED:
Serial.println("ETH Connected");
break;
case SYSTEM_EVENT_ETH_GOT_IP:
Serial.print("ETH MAC: ");
Serial.print(ETH.macAddress());
Serial.print(", IPv4: ");
Serial.print(ETH.localIP());
if (ETH.fullDuplex()) {
Serial.print(", FULL_DUPLEX");
}
Serial.print(", ");
Serial.print(ETH.linkSpeed());
Serial.println("Mbps");
eth_connected = true;
break;
case SYSTEM_EVENT_ETH_DISCONNECTED:
Serial.println("ETH Disconnected");
eth_connected = false;
break;
case SYSTEM_EVENT_ETH_STOP:
Serial.println("ETH Stopped");
eth_connected = false;
break;
default:
break;
}
}
void setup() {
// Init Serial
Serial.begin(115200);
while (!Serial) {}
Serial.println("__ OK __");
WiFi.onEvent(WiFiEvent);
ETH.begin();
// Set up test memory
for (uint16_t i = 0; i < 32; ++i)
{
memo[i] = 100 + i;
}
// Now set up the server for some function codes
MBserver.registerWorker(1, READ_HOLD_REGISTER, &FC03); // FC=03 for serverID=1
MBserver.registerWorker(1, READ_INPUT_REGISTER, &FC03); // FC=04 for serverID=1
MBserver.registerWorker(2, READ_HOLD_REGISTER, &FC03); // FC=03 for serverID=2
// Start the server
MBserver.start(502, 2, 20000);
}
void loop() {
static uint32_t statusTime = millis();
const uint32_t statusInterval(10000);
// We will be idling around here - all is done in subtasks :D
if (millis() - statusTime > statusInterval) {
Serial.printf("%d clients running.\n", MBserver.activeClients());
statusTime = millis();
}
delay(100);
}
Maybe we can help each other here? ;)
Hello together,
i wanted to ask if anybody got a sucessful working Modbus Server with the Olimex via ethernet?
I just want to send an receive some simple in- and outputs from my IoBroker Master.
Greetings
Patrick