Skip to content

Commit

Permalink
Add Modbus TCP
Browse files Browse the repository at this point in the history
OpenDTU is extended by a Modbus server. The Modbus server serves TCP at port 502.
At Modbus ID 1 the server mimicks the Modbus registers in the original DTUPro.
At Modbus ID 125 the server serves a SunSpec compatible pseudo inverter that
provides the OpenDTU aggregated data from all registered inverters.

The OpenDTU Modbus sources were imspired by : https://github.com/ArekKubacki/OpenDTU.
See tbnobody#582 for the orignal pull request.

The Modbus library used for Modbus communication is: https://github.com/eModbus/eModbus.
Documentation for the library is here: https://emodbus.github.io/.
The library was choosen to achieve a lower memory footprint.

fixes tbnobody#582

Signed-off-by: Bobby Noelte <b0661n0e17e@gmail.com>
  • Loading branch information
b0661 committed Apr 9, 2024
1 parent 1258865 commit c517f7b
Show file tree
Hide file tree
Showing 13 changed files with 1,010 additions and 0 deletions.
6 changes: 6 additions & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,12 @@ struct CONFIG_T {
double Latitude;
uint8_t SunsetType;
} Ntp;
struct {
bool TCPEnabled;
uint32_t Port;
uint32_t IDDTUPro;
uint32_t IDTotal;
} Modbus;

struct {
bool Enabled;
Expand Down
24 changes: 24 additions & 0 deletions include/ModbusDtu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <TaskSchedulerDeclarations.h>

// eModbus
#include "ModbusServerTCPasync.h"

class ModbusDtuClass {
public:
ModbusDtuClass();
void init(Scheduler& scheduler);

private:
void loop();

Task _loopTask;
};

ModbusMessage OpenDTUTotal(ModbusMessage request);
ModbusMessage DTUPro(ModbusMessage request);

extern ModbusDtuClass ModbusDtu;
extern ModbusServerTCPasync ModbusTCPServer;
17 changes: 17 additions & 0 deletions include/ModbusSettings.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

class ModbusSettingsClass {
public:
ModbusSettingsClass();
void init();

void performConfig();

private:
void startTCP();

void stopTCP();
};

extern ModbusSettingsClass ModbusSettings;
2 changes: 2 additions & 0 deletions include/WebApi.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
#include "WebApi_inverter.h"
#include "WebApi_limit.h"
#include "WebApi_maintenance.h"
#include "WebApi_modbus.h"
#include "WebApi_mqtt.h"
#include "WebApi_network.h"
#include "WebApi_ntp.h"
Expand Down Expand Up @@ -50,6 +51,7 @@ class WebApiClass {
WebApiInverterClass _webApiInverter;
WebApiLimitClass _webApiLimit;
WebApiMaintenanceClass _webApiMaintenance;
WebApiModbusClass _webApiModbus;
WebApiMqttClass _webApiMqtt;
WebApiNetworkClass _webApiNetwork;
WebApiNtpClass _webApiNtp;
Expand Down
15 changes: 15 additions & 0 deletions include/WebApi_modbus.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once

#include <ESPAsyncWebServer.h>
#include <TaskSchedulerDeclarations.h>

class WebApiModbusClass {
public:
void init(AsyncWebServer& server, Scheduler& scheduler);

private:
void onModbusStatus(AsyncWebServerRequest* request);
void onModbusAdminGet(AsyncWebServerRequest* request);
void onModbusAdminPost(AsyncWebServerRequest* request);
};
5 changes: 5 additions & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,11 @@
#define NTP_LATITUDE 51.1657f
#define NTP_SUNSETTYPE 1U

#define MODBUS_TCP_ENABLED false
#define MODBUS_PORT 502
#define MODBUS_ID_DTUPRO 1
#define MODBUS_ID_TOTAL 125

#define MQTT_ENABLED false
#define MQTT_HOST ""
#define MQTT_PORT 1883U
Expand Down
7 changes: 7 additions & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -35,10 +35,17 @@ build_flags =
build_unflags =
-std=gnu++11

; Ignore dependencies of eModbus as they are fulfilled by other library variants
lib_ignore =
AsyncTCP
ESPAsyncTCP
custom-Ethernet

lib_deps =
mathieucarbou/ESP Async WebServer @ 2.8.1
bblanchon/ArduinoJson @ ^6.21.5
https://github.com/bertmelis/espMqttClient.git#v1.6.0
https://github.com/eModbus/eModbus.git
nrf24/RF24 @ ^1.4.8
olikraus/U8g2 @ ^2.35.15
buelowp/sunset @ ^1.1.7
Expand Down
12 changes: 12 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ bool ConfigurationClass::write()
ntp["longitude"] = config.Ntp.Longitude;
ntp["sunsettype"] = config.Ntp.SunsetType;

JsonObject modbus = doc.createNestedObject("modbus");
modbus["tcp_enabled"] = config.Modbus.TCPEnabled;
modbus["port"] = config.Modbus.Port;
modbus["id_dtupro"] = config.Modbus.IDDTUPro;
modbus["id_total"] = config.Modbus.IDTotal;

JsonObject mqtt = doc.createNestedObject("mqtt");
mqtt["enabled"] = config.Mqtt.Enabled;
mqtt["hostname"] = config.Mqtt.Hostname;
Expand Down Expand Up @@ -227,6 +233,12 @@ bool ConfigurationClass::read()
config.Ntp.Longitude = ntp["longitude"] | NTP_LONGITUDE;
config.Ntp.SunsetType = ntp["sunsettype"] | NTP_SUNSETTYPE;

JsonObject modbus = doc["modbus"];
config.Modbus.TCPEnabled = modbus["tcp_enabled"] | MODBUS_TCP_ENABLED;
config.Modbus.Port = modbus["port"] | MODBUS_PORT;
config.Modbus.IDDTUPro = modbus["id_dtupro"] | MODBUS_ID_DTUPRO;
config.Modbus.IDTotal = modbus["id_total"] | MODBUS_ID_TOTAL;

JsonObject mqtt = doc["mqtt"];
config.Mqtt.Enabled = mqtt["enabled"] | MQTT_ENABLED;
strlcpy(config.Mqtt.Hostname, mqtt["hostname"] | MQTT_HOST, sizeof(config.Mqtt.Hostname));
Expand Down
Loading

0 comments on commit c517f7b

Please sign in to comment.