Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add Modbus Sunspec compatibility to opendtu-onbattery #1150

Open
wants to merge 67 commits into
base: development
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
4084b4d
Add Modbus
ArekKubacki Feb 13, 2023
cc98831
Added Modbus
ArekKubacki Feb 13, 2023
ddb0325
Merge remote-tracking branch 'origin/master'
ArekKubacki Feb 13, 2023
802601a
Checking that the measurement does not exceed the max Power
ArekKubacki Feb 15, 2023
0777a9c
Modbus BugFix
ArekKubacki Feb 15, 2023
53b9690
Modbus BugFix
ArekKubacki Feb 15, 2023
e13348c
Added WatchDog to Modbus
ArekKubacki Mar 8, 2023
32b9750
Update from master
ArekKubacki Mar 8, 2023
3277e71
Merge branch 'master' into master
ArekKubacki Mar 8, 2023
1b8b56f
Revert "Merge branch 'master' into v1"
ArekKubacki May 30, 2023
314b285
Merge branch 'tbnobody-master'
ArekKubacki May 30, 2023
6ec026b
Edit platformio.ini
ArekKubacki May 30, 2023
5077d03
Fixed Temperature, Frequency etc.
ArekKubacki Jun 2, 2023
8d52334
Merge remote-tracking branch 'origin/master'
ArekKubacki Jun 2, 2023
a3b2457
Modbus fixed
ArekKubacki Jun 2, 2023
54e1641
Fixed Temp, Freq, AC
ArekKubacki Jun 2, 2023
2d9c942
Merge remote-tracking branch 'origin/master'
ArekKubacki Jun 2, 2023
45c9984
Merge
ArekKubacki Jun 2, 2023
adeed86
Merge
ArekKubacki Jun 5, 2023
0fb144f
Modbus Added
ArekKubacki Jun 5, 2023
6765ab6
ModbusDtu h file fixed
ArekKubacki Jun 5, 2023
f7678a0
Fixed Modbus Library
ArekKubacki Jun 5, 2023
acdd4ed
simulating a Fronius Smart Meter with openDTU. currently only feeding…
Jun 10, 2023
5684efa
if only one inverter is connected, use its measurement data.
Jun 12, 2023
909e53b
Merge pull request #1 from tbnobody/master
AloisKlingler Jun 28, 2023
634f962
adding totals as webapi live
Jun 28, 2023
e551d8d
Merge branch 'master' of https://github.com/AloisKlingler/OpenDTU-Fro…
Jun 28, 2023
7a09c3d
Merge pull request #2 from tbnobody/master
AloisKlingler Jun 29, 2023
e6ec4e4
disable wifi powersave mode
Jul 6, 2023
a4e8644
Merge pull request #3 from tbnobody/master
AloisKlingler Aug 8, 2023
6bc9acb
single phase inverters: use variable to fill them to phase 1 to smart…
Aug 8, 2023
99100b7
fixing still empty values on HMS inverters
Aug 9, 2023
423b33e
Merge pull request #4 from tbnobody/master
AloisKlingler Aug 9, 2023
9ebfd82
next try to avoid sending 0-values to modbus-register.
Aug 20, 2023
2f1bb0d
missed some changes in last commit
Aug 20, 2023
c2a06bb
Merge pull request #5 from tbnobody/master
AloisKlingler Sep 7, 2023
226e106
Merge pull request #6 from tbnobody/master
AloisKlingler Sep 12, 2023
cc19c16
Merge pull request #7 from tbnobody/master
AloisKlingler Sep 14, 2023
1aaa4c2
no more additional smartmeter data to increase reliability
Sep 14, 2023
afd6cc4
Merge pull request #8 from tbnobody/master
AloisKlingler Sep 20, 2023
10f5320
Merge pull request #9 from tbnobody/master
AloisKlingler Oct 11, 2023
7465e28
Merge pull request #10 from tbnobody/master
AloisKlingler Nov 20, 2023
b95041e
init variable on starting
Nov 20, 2023
1f77c38
adding configuration element in settings -> network settings to enabl…
Nov 20, 2023
9932a06
Revert "adding configuration element in settings -> network settings …
Jul 31, 2024
66bd4db
Revert "init variable on starting"
Jul 31, 2024
373ff32
Revert "no more additional smartmeter data to increase reliability"
Jul 31, 2024
a2e1c0d
Revert "missed some changes in last commit"
Jul 31, 2024
6c13883
Merge branch 'master' of https://github.com/tbnobody/OpenDTU into tbn…
Jul 31, 2024
735ab0c
Merge branch 'tbnobody-master'
Jul 31, 2024
510e7ca
resolve mergeconflicts v24.6.29
Jul 31, 2024
4888113
fix cpplint failing checks
Jul 31, 2024
4b82f64
migrate Modbus to TaskScheduler
Aug 1, 2024
ef9612e
fix wrong taskname for modbustask
Aug 1, 2024
38aac57
v24.8.1-0.2.2 based on v24.8.1
Aug 1, 2024
ef6e845
Merge branch 'master' of https://github.com/tbnobody/OpenDTU
Aug 1, 2024
e341b96
bring back detailled smartmeter data if only one hoymiles inverter is…
Aug 2, 2024
fcfe327
wrong modbus register leaded to wrong Reactive Power in smartmeter data
Aug 2, 2024
e5fe5b9
Update settings.json
AloisKlingler Aug 4, 2024
03e6e79
Update settings.json
AloisKlingler Aug 4, 2024
c2c4e03
Update settings.json
AloisKlingler Aug 4, 2024
7a4cf2f
rectify settings.json
Aug 4, 2024
93ab87c
Update main.cpp
AloisKlingler Aug 4, 2024
61b2d98
extract strings to have a better possibility to configure dynamic sun…
Aug 5, 2024
389f982
Merge pull request #15 from tbnobody/master
AloisKlingler Aug 6, 2024
ad04999
from Fronius-Simulation to SunSpec-OpenDTU compatibility.
Aug 6, 2024
7a2ae06
fix delayed starting of modbus server
Aug 6, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions include/Configuration.h
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,16 @@ struct CONFIG_T {
bool Enabled;
} Mdns;

struct {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please also add bool verboseLogging to your struct and use that to enable/disable logging within your Modbus module instead of commenting the logging lines.

bool modbus_tcp_enabled;
bool modbus_delaystart;
char mfrname[32];
char modelname[32];
char options[16];
char version[16];
char serial[16];
} modbus;

struct {
char Server[NTP_MAX_SERVER_STRLEN + 1];
char Timezone[NTP_MAX_TIMEZONE_STRLEN + 1];
Expand Down
25 changes: 25 additions & 0 deletions include/ModbusDtu.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#pragma once

#include <TaskSchedulerDeclarations.h>
#include <cstdint>
#include "Configuration.h"
#include <ModbusIP_ESP8266.h>
#include <Hoymiles.h>

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

private:
void loop();
void setup();
void modbus();
bool _isstarted = false;
float _lasttotal = 0;

Task _loopTask;
Task _modbusTask;
};

extern ModbusDtuClass ModbusDtu;
7 changes: 7 additions & 0 deletions include/defaults.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@

#define MDNS_ENABLED false

#define MODBUS_ENABLED false
#define MODBUS_DELAY_START false
#define MODBUS_MFRNAME "OpenDTU"
#define MODBUS_MODELNAME "OpenDTU-SunSpec"
#define MODBUS_OPTIONS ""
#define MODBUS_VERSION "1.0"

#define NTP_SERVER_OLD "pool.ntp.org"
#define NTP_SERVER "opendtu.pool.ntp.org"
#define NTP_TIMEZONE "CET-1CEST,M3.5.0,M10.5.0/3"
Expand Down
1 change: 1 addition & 0 deletions platformio.ini
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ lib_deps =
nrf24/RF24 @ 1.4.9
olikraus/U8g2 @ 2.35.19
buelowp/sunset @ 1.1.7
https://github.com/emelianov/modbus-esp8266#master
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we point to a specific commit or release-tag instead of a branch?
This might break builds at any point in the future without us knowing whats going on.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

currently not, as there is a change which is most probably needed in master only:
emelianov/modbus-esp8266#292

as soon as there is a 4.1.2 (or whatever) released I think this one could be used.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you specific the commit hash with #a5872af7250e03e9a5cd578366b0c2cdc097fcc9 instead of #master you can make sure that the dependency won't get updated randomly with the next push to master

https://github.com/arkhipenko/TaskScheduler#testing

extra_scripts =
Expand Down
18 changes: 18 additions & 0 deletions src/Configuration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,15 @@ bool ConfigurationClass::write()
JsonObject mdns = doc["mdns"].to<JsonObject>();
mdns["enabled"] = config.Mdns.Enabled;

JsonObject modbus = doc["modbus"].to<JsonObject>();
modbus["modbus_tcp_enabled"] = config.modbus.modbus_tcp_enabled;
modbus["modbus_delaystart"] = config.modbus.modbus_delaystart;
modbus["mfrname"] = config.modbus.mfrname;
modbus["modelname"] = config.modbus.modelname;
modbus["options"] = config.modbus.options;
modbus["version"] = config.modbus.version;
modbus["serial"] = config.modbus.serial;

JsonObject ntp = doc["ntp"].to<JsonObject>();
ntp["server"] = config.Ntp.Server;
ntp["timezone"] = config.Ntp.Timezone;
Expand Down Expand Up @@ -222,6 +231,15 @@ bool ConfigurationClass::read()
JsonObject mdns = doc["mdns"];
config.Mdns.Enabled = mdns["enabled"] | MDNS_ENABLED;

JsonObject modbus = doc["modbus"];
config.modbus.modbus_tcp_enabled = modbus["modbus_tcp_enabled"] | MODBUS_ENABLED;
config.modbus.modbus_delaystart = modbus["modbus_delaystart"] | MODBUS_DELAY_START;
strlcpy(config.modbus.mfrname, modbus["mfrname"] | MODBUS_MFRNAME, sizeof(config.modbus.mfrname));
strlcpy(config.modbus.modelname, modbus["modelname"] | MODBUS_MODELNAME, sizeof(config.modbus.modelname));
strlcpy(config.modbus.options, modbus["options"] | MODBUS_OPTIONS, sizeof(config.modbus.options));
strlcpy(config.modbus.version, modbus["version"] | MODBUS_VERSION, sizeof(config.modbus.version));
strlcpy(config.modbus.serial, modbus["serial"] | "", sizeof(config.modbus.serial));

JsonObject ntp = doc["ntp"];
strlcpy(config.Ntp.Server, ntp["server"] | NTP_SERVER, sizeof(config.Ntp.Server));
strlcpy(config.Ntp.Timezone, ntp["timezone"] | NTP_TIMEZONE, sizeof(config.Ntp.Timezone));
Expand Down
230 changes: 230 additions & 0 deletions src/ModbusDtu.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
#include "ModbusDtu.h"
#include "Datastore.h"
#include "MessageOutput.h"

ModbusIP mb;

ModbusDtuClass ModbusDtu;

ModbusDtuClass::ModbusDtuClass()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't it make more sense if we call it ModbusSunspec or SunspecModbus to explain what this is actually doing?

Do you have any documentation about the protocol that youa re implementing here?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this implementation is (maybe only partially) modbus-sunspec compatibility to simulate a sunspec energy-meter.

as far as I could google, this should match to "sunspec meter" registers in float mode.
I could not check if it is the complete protocol or only partial.
at least, if I check against fronius documentation, it is complete.

: _loopTask(Configuration.get().Dtu.PollInterval * TASK_SECOND, TASK_FOREVER, std::bind(&ModbusDtuClass::loop, this))
, _modbusTask(TASK_IMMEDIATE, TASK_FOREVER, std::bind(&ModbusDtuClass::modbus, this))
{
}

void ModbusDtuClass::init(Scheduler& scheduler)
{
scheduler.addTask(_loopTask);
_loopTask.enable();
scheduler.addTask(_modbusTask);
}

void ModbusDtuClass::modbus()
{
mb.task();
}

void ModbusDtuClass::setup()
{
if ((Configuration.get().Dtu.Serial) < 0x100000000000 || (Configuration.get().Dtu.Serial) > 0x199999999999) {
MessageOutput.printf("Modbus: need a DTU Serial between 100000000000 and 199999999999 (currently configured: %llx)\r\n", Configuration.get().Dtu.Serial);
_isstarted = false;
return;
}
mb.server();
mb.addHreg(0x9c40, 21365); //40000 Sunspec Id start
mb.addHreg(0x9c41, 28243); //40001 Sunspec Id end
mb.addHreg(0x9c42, 1); //40002 SunSpec_DID
mb.addHreg(0x9c43, 65); //40003 SunSpec_Length
const char *mfrname = Configuration.get().modbus.mfrname; //Manufacturer Name max. 32 chars
for (uint8_t i = 0; i < 32; i += 2) {
uint16_t value = 0;
if (strlen(mfrname) > i) value = (mfrname[i] << 8) | (i + 1 < strlen(mfrname) ? mfrname[i + 1] : 0);
mb.addHreg(0x9c44 + (i / 2), value); //40004 - 40019 Manufacturer name
// MessageOutput.printf("Vendor: write %d to register %d\r\n", value, (0x9c44 + (i / 2)));
}
const char *modelname = Configuration.get().modbus.modelname;
for (uint8_t i = 0; i < 32; i += 2) {
uint16_t value = 0;
if (strlen(modelname) > i) value = (modelname[i] << 8) | (i + 1 < strlen(modelname) ? modelname[i + 1] : 0);
mb.addHreg(0x9c54 + (i / 2), value); //40020 - 40035 Device Model Name
// MessageOutput.printf("Modelname: write %d to register %d\r\n", value, (0x9c54 + (i / 2)));
}
const char *options = Configuration.get().modbus.options;
for (uint8_t i = 0; i < 16; i += 2) {
uint16_t value = 0;
if (strlen(options) > i) value = (options[i] << 8) | (i + 1 < strlen(options) ? options[i + 1] : 0);
mb.addHreg(0x9c64 + (i / 2), value); //40036 - 40043 Options
// MessageOutput.printf("Options: write %d to register %d\r\n", value, (0x9c64 + (i / 2)));
}
const char *version = Configuration.get().modbus.version;
for (uint8_t i = 0; i < 16; i += 2) {
uint16_t value = 0;
if (strlen(version) > i) value = (version[i] << 8) | (i + 1 < strlen(version) ? version[i + 1] : 0);
mb.addHreg(0x9c6c + (i / 2), value); //40044 - 40051 Version
// MessageOutput.printf("Version: write %d to register %d\r\n", value, (0x9c6c + (i / 2)));
}
const char *serialconfig = Configuration.get().modbus.serial;
if (!strlen(serialconfig)) {
char serial[24];
uint16_t *hexbytes = reinterpret_cast<uint16_t *>(serial);
snprintf(serial,sizeof(serial),"%llx",(Configuration.get().Dtu.Serial));
MessageOutput.printf("Modbus: init uses DTU Serial: %llx\r\n", Configuration.get().Dtu.Serial);
MessageOutput.printf("Modbus: writing to init modbus registers %d %d %d %d %d %d\r\n", ntohs(hexbytes[0]), ntohs(hexbytes[1]), ntohs(hexbytes[2]), ntohs(hexbytes[3]), ntohs(hexbytes[4]), ntohs(hexbytes[5]));
for (uint8_t i = 0; i < 6; i++) {
mb.addHreg(0x9c74 + i, ntohs(hexbytes[i])); //40052 Serial Number start
}
mb.addHreg(0x9c7a, 0, 10); //40067 Serial Number end
} else {
for (uint8_t i = 0; i < 32; i += 2) {
uint16_t value = 0;
if (strlen(serialconfig) > i) value = (serialconfig[i] << 8) | (i + 1 < strlen(serialconfig) ? serialconfig[i + 1] : 0);
mb.addHreg(0x9c74 + (i / 2), value); //40052 - 40067 Serial Number
// MessageOutput.printf("Modbus: write %d to register %d\r\n", value, (0x9c74 + (i / 2)));
}
}
mb.addHreg(0x9c84, 202); //40068 DeviceAddress Modbus TCP Address: 202
mb.addHreg(0x9c85, 213); //40069 SunSpec_DID
mb.addHreg(0x9c86, 124); //40070 SunSpec_Length
mb.addHreg(0x9c87, 0, 123);//40071 - 40194 smartmeter data
mb.addHreg(0x9d03, 65535); //40195 end block identifier
mb.addHreg(0x9d04, 0); //40196
_isstarted = true;
}

void ModbusDtuClass::loop()
{
_loopTask.setInterval(Configuration.get().Dtu.PollInterval * TASK_SECOND);

if (!(Configuration.get().modbus.modbus_tcp_enabled)) return;

if (!Hoymiles.isAllRadioIdle()) {
_loopTask.forceNextIteration();
return;
}

if (!_isstarted) {
if (!(Configuration.get().modbus.modbus_delaystart) || (Datastore.getIsAllEnabledReachable() && Datastore.getTotalAcYieldTotalEnabled() != 0)) {
MessageOutput.printf("Modbus: starting server ... \r\n");
ModbusDtu.setup();
_modbusTask.enable();
} else {
MessageOutput.printf("Modbus: not initializing yet! (Total Yield = 0 or not all configured inverters reachable)\r\n");
return;
}
}

if (!(Datastore.getIsAllEnabledReachable()) || !(Datastore.getTotalAcYieldTotalEnabled() != 0) || (!_isstarted) || !(Configuration.get().modbus.modbus_delaystart)) {
MessageOutput.printf("Modbus: not updating registers! (Total Yield = 0 or not all configured inverters reachable)\r\n");
return;
} else {
float value;
uint16_t *hexbytes = reinterpret_cast<uint16_t *>(&value);
value = (Datastore.getTotalAcPowerEnabled()*-1);
// MessageOutput.printf("Modbus: write %.2f to 40097 and 40098\r\n", value);
mb.Hreg(0x9ca1, hexbytes[1]);
mb.Hreg(0x9ca2, hexbytes[0]);
value = (Datastore.getTotalAcYieldTotalEnabled()*1000);
if (value > _lasttotal) {
_lasttotal = value;
// MessageOutput.printf("Modbus: write %.2f to 40129 and 40130\r\n", value);
mb.Hreg(0x9cc1, hexbytes[1]);
mb.Hreg(0x9cc2, hexbytes[0]);
}

if (Hoymiles.getNumInverters() == 1) {
// MessageOutput.printf("Modbus: Start additional SM Information\r\n");
auto inv = Hoymiles.getInverterByPos(0);
if (inv != nullptr) {
for (auto& t : inv->Statistics()->getChannelTypes()) {
if (t == TYPE_DC) {
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC));
mb.Hreg(0x9c87, hexbytes[1]);
mb.Hreg(0x9c88, hexbytes[0]);
value = ((inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_1) != 0 ? inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_1) : inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC)));
mb.Hreg(0x9c89, hexbytes[1]);
mb.Hreg(0x9c8a, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_2));
mb.Hreg(0x9c8b, hexbytes[1]);
mb.Hreg(0x9c8c, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_3));
mb.Hreg(0x9c8d, hexbytes[1]);
mb.Hreg(0x9c8e, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_1N));
mb.Hreg(0x9c8f, hexbytes[1]);
mb.Hreg(0x9c90, hexbytes[0]);
value = ((inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_1N) != 0 ? inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_1N) : inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC)));
mb.Hreg(0x9c91, hexbytes[1]);
mb.Hreg(0x9c92, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_2N));
mb.Hreg(0x9c93, hexbytes[1]);
mb.Hreg(0x9c94, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_3N));
mb.Hreg(0x9c95, hexbytes[1]);
mb.Hreg(0x9c96, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC));
mb.Hreg(0x9c97, hexbytes[1]);
mb.Hreg(0x9c98, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_12));
mb.Hreg(0x9c99, hexbytes[1]);
mb.Hreg(0x9c9a, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_23));
mb.Hreg(0x9c9b, hexbytes[1]);
mb.Hreg(0x9c9c, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_31));
mb.Hreg(0x9c9d, hexbytes[1]);
mb.Hreg(0x9c9e, hexbytes[0]);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_F));
mb.Hreg(0x9c9f, hexbytes[1]);
mb.Hreg(0x9ca0, hexbytes[0]);
// value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_PAC)*-1); //done above already!
// mb.Hreg(0x9ca1, hexbytes[1]); //done above already!
// mb.Hreg(0x9ca2, hexbytes[0]); //done above already!
value = ((inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_1) != 0) ? ((inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_1)) * (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_1N)) *-1) : ((inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC)) * (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC)) *-1));
mb.Hreg(0x9ca3, hexbytes[1]);
mb.Hreg(0x9ca4, hexbytes[0]);
value = ((inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_2)) * (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_2N)) *-1);
mb.Hreg(0x9ca5, hexbytes[1]);
mb.Hreg(0x9ca6, hexbytes[0]);
value = ((inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_IAC_3)) * (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_UAC_3N)) *-1);
mb.Hreg(0x9ca7, hexbytes[1]);
mb.Hreg(0x9ca8, hexbytes[0]);
// mb.Hreg(0x9ca9, 0);
// mb.Hreg(0x9caa, 0);
// mb.Hreg(0x9cab, 0);
// mb.Hreg(0x9cac, 0);
// mb.Hreg(0x9cad, 0);
// mb.Hreg(0x9cae, 0);
// mb.Hreg(0x9caf, 0);
// mb.Hreg(0x9cb0, 0);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_Q));
mb.Hreg(0x9cb1, hexbytes[1]);
mb.Hreg(0x9cb2, hexbytes[0]);
// mb.Hreg(0x9cb3, 0);
// mb.Hreg(0x9cb4, 0);
// mb.Hreg(0x9cb5, 0);
// mb.Hreg(0x9cb6, 0);
// mb.Hreg(0x9cb7, 0);
// mb.Hreg(0x9cb8, 0);
value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_PF));
mb.Hreg(0x9cb9, hexbytes[1]);
mb.Hreg(0x9cba, hexbytes[0]);
// mb.Hreg(0x9cbb, 0);
// mb.Hreg(0x9cbc, 0);
// mb.Hreg(0x9cbd, 0);
// mb.Hreg(0x9cbe, 0);
// mb.Hreg(0x9cbf, 0);
// mb.Hreg(0x9cc0, 0);
// value = (inv->Statistics()->getChannelFieldValue(TYPE_AC, CH0, FLD_YT)*1000); //done above already!
// if (value > _lasttotal) {
// _lasttotal = value;
// mb.Hreg(0x9cc1, hexbytes[1]); //done above already!
// mb.Hreg(0x9cc2, hexbytes[0]); //done above already!
// }
Comment on lines +212 to +223
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please remove commented lines if they are not needed

}
}
}
// MessageOutput.printf("Modbus: End additional SM Information\r\n");
}
}
}
14 changes: 14 additions & 0 deletions src/WebApi_network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ void WebApiNetworkClass::onNetworkAdminGet(AsyncWebServerRequest* request)
root["password"] = config.WiFi.Password;
root["aptimeout"] = config.WiFi.ApTimeout;
root["mdnsenabled"] = config.Mdns.Enabled;
root["modbus_tcp_enabled"] = config.modbus.modbus_tcp_enabled;
root["modbus_delaystart"] = config.modbus.modbus_delaystart;
root["mfrname"] = config.modbus.mfrname;
root["modelname"] = config.modbus.modelname;
root["options"] = config.modbus.options;
root["version"] = config.modbus.version;
root["serial"] = config.modbus.serial;

WebApi.sendJsonResponse(request, response, __FUNCTION__, __LINE__);
}
Expand Down Expand Up @@ -195,6 +202,13 @@ void WebApiNetworkClass::onNetworkAdminPost(AsyncWebServerRequest* request)
}
config.WiFi.ApTimeout = root["aptimeout"].as<uint>();
config.Mdns.Enabled = root["mdnsenabled"].as<bool>();
config.modbus.modbus_tcp_enabled = root["modbus_tcp_enabled"].as<bool>();
config.modbus.modbus_delaystart = root["modbus_delaystart"].as<bool>();
strlcpy(config.modbus.mfrname, root["mfrname"].as<String>().c_str(), sizeof(config.modbus.mfrname));
strlcpy(config.modbus.modelname, root["modelname"].as<String>().c_str(), sizeof(config.modbus.modelname));
strlcpy(config.modbus.options, root["options"].as<String>().c_str(), sizeof(config.modbus.options));
strlcpy(config.modbus.version, root["version"].as<String>().c_str(), sizeof(config.modbus.version));
strlcpy(config.modbus.serial, root["serial"].as<String>().c_str(), sizeof(config.modbus.serial));

WebApi.writeConfig(retMsg);

Expand Down
3 changes: 3 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "PinMapping.h"
#include "Scheduler.h"
#include "SunPosition.h"
#include "ModbusDtu.h"
#include "Utils.h"
#include "WebApi.h"
#include "defaults.h"
Expand Down Expand Up @@ -153,6 +154,8 @@ void setup()

InverterSettings.init(scheduler);

ModbusDtu.init(scheduler);

Datastore.init(scheduler);
}

Expand Down
17 changes: 16 additions & 1 deletion webapp/src/locales/de.json
Original file line number Diff line number Diff line change
Expand Up @@ -432,7 +432,22 @@
"ApTimeoutHint": "Zeit die der AccessPoint offen gehalten wird. Ein Wert von 0 bedeutet unendlich.",
"Minutes": "Minuten",
"EnableMdns": "mDNS aktivieren",
"MdnsSettings": "mDNS-Einstellungen"
"MdnsSettings": "mDNS-Einstellungen",
"ModbusSettings": "Modbus-Einstellungen",
"EnableModbusTCP": "Modbus TCP Server aktivieren",
"EnableModbusTCPHint": "SunSpec-kompatiblen Modbus TCP Server auf port 502 aktivieren",
"DelayModbusStart": "Modbus TCP Serverstart verzögern",
"DelayModbusStartHint": "Modbus Server startet erst, wenn alle Wechselrichter erreichbar sind und YieldTotal != 0 ist",
"ModbusMfrName": "SunSpec Modbus Manufacturer Name",
"ModbusMfrNameHint": "Wenn leer wird automatisch 'OpenDTU' verwendet",
"ModbusModelName": "SunSpec Modbus Model Name",
"ModbusModelNameHint": "Wenn leer wird automatisch 'OpenDTU-Sunspec' verwendet",
"ModbusOptions": "SunSpec Modbus Options",
"ModbusOptionsHint": "Sunspec Modbus Options String",
"ModbusVersion": "SunSpec Modbus Version",
"ModbusVersionHint": "Wenn leer wird '1.0' verwendet",
"Modbusserial": "SunSpec Modbus Serial Number",
"ModbusserialHint": "Wenn leer wird automatisch die OpenDTU Serial verwendet"
},
"mqttadmin": {
"MqttSettings": "MQTT-Einstellungen",
Expand Down
Loading