mirror of
https://github.com/lumapu/ahoy.git
synced 2025-06-07 05:01:39 +02:00
0.8.1030019
0.8.1030019
This commit is contained in:
commit
fe1689979f
5 changed files with 303 additions and 114 deletions
|
@ -13,7 +13,7 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 8
|
#define VERSION_MINOR 8
|
||||||
#define VERSION_PATCH 1030018
|
#define VERSION_PATCH 1030019
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "plugins/zeroExport/lib/sml.h"
|
#include "plugins/zeroExport/lib/sml.h"
|
||||||
|
#include "utils/DynamicJsonHandler.h"
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const unsigned char OBIS[6];
|
const unsigned char OBIS[6];
|
||||||
void (*Fn)(double &);
|
void (*Fn)(double &);
|
||||||
|
@ -46,7 +46,7 @@ class powermeter {
|
||||||
* @param *log
|
* @param *log
|
||||||
* @returns void
|
* @returns void
|
||||||
*/
|
*/
|
||||||
bool setup(IApp *app, zeroExport_t *cfg, PubMqttType *mqtt, JsonObject *log) {
|
bool setup(IApp *app, zeroExport_t *cfg, PubMqttType *mqtt, DynamicJsonHandler *log) {
|
||||||
mApp = app;
|
mApp = app;
|
||||||
mCfg = cfg;
|
mCfg = cfg;
|
||||||
mMqtt = mqtt;
|
mMqtt = mqtt;
|
||||||
|
@ -84,7 +84,7 @@ class powermeter {
|
||||||
switch (mCfg->groups[group].pm_type) {
|
switch (mCfg->groups[group].pm_type) {
|
||||||
#if defined(ZEROEXPORT_POWERMETER_SHELLY)
|
#if defined(ZEROEXPORT_POWERMETER_SHELLY)
|
||||||
case zeroExportPowermeterType_t::Shelly:
|
case zeroExportPowermeterType_t::Shelly:
|
||||||
result = getPowermeterWattsShelly(*mLog, group, &power);
|
result = getPowermeterWattsShelly(group, &power);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(ZEROEXPORT_POWERMETER_TASMOTA)
|
#if defined(ZEROEXPORT_POWERMETER_TASMOTA)
|
||||||
|
@ -105,12 +105,12 @@ class powermeter {
|
||||||
*/
|
*/
|
||||||
case zeroExportPowermeterType_t::Tibber:
|
case zeroExportPowermeterType_t::Tibber:
|
||||||
if (mCfg->groups[group].pm_refresh < 3) mCfg->groups[group].pm_refresh = 3;
|
if (mCfg->groups[group].pm_refresh < 3) mCfg->groups[group].pm_refresh = 3;
|
||||||
result = getPowermeterWattsTibber(*mLog, group, &power);
|
result = getPowermeterWattsTibber(group, &power);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
#if defined(ZEROEXPORT_POWERMETER_SHRDZM)
|
#if defined(ZEROEXPORT_POWERMETER_SHRDZM)
|
||||||
case zeroExportPowermeterType_t::Shrdzm:
|
case zeroExportPowermeterType_t::Shrdzm:
|
||||||
result = getPowermeterWattsShrdzm(*mLog, group, &power);
|
result = getPowermeterWattsShrdzm(group, &power);
|
||||||
break;
|
break;
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -118,7 +118,7 @@ class powermeter {
|
||||||
if (result) {
|
if (result) {
|
||||||
bufferWrite(power, group);
|
bufferWrite(power, group);
|
||||||
mCfg->groups[group].power = power;
|
mCfg->groups[group].power = power;
|
||||||
|
|
||||||
// MQTT - Powermeter
|
// MQTT - Powermeter
|
||||||
/// BUG: 002 Anfang - Muss dieser Teil raus? Führt er zu abstürzen wie BUG 001?
|
/// BUG: 002 Anfang - Muss dieser Teil raus? Führt er zu abstürzen wie BUG 001?
|
||||||
if (mMqtt->isConnected()) {
|
if (mMqtt->isConnected()) {
|
||||||
|
@ -239,7 +239,7 @@ class powermeter {
|
||||||
|
|
||||||
bufferWrite(power, group);
|
bufferWrite(power, group);
|
||||||
mCfg->groups[group].power = power; // TODO: join two sites together (PM & MQTT)
|
mCfg->groups[group].power = power; // TODO: join two sites together (PM & MQTT)
|
||||||
|
|
||||||
// MQTT - Powermeter
|
// MQTT - Powermeter
|
||||||
/// BUG: 001 Anfang - Dieser Teil ist deaktiviert weil er zu abstürzen der DTU führt
|
/// BUG: 001 Anfang - Dieser Teil ist deaktiviert weil er zu abstürzen der DTU führt
|
||||||
// if (mCfg->debug) {
|
// if (mCfg->debug) {
|
||||||
|
@ -280,7 +280,7 @@ class powermeter {
|
||||||
|
|
||||||
zeroExport_t *mCfg;
|
zeroExport_t *mCfg;
|
||||||
PubMqttType *mMqtt = nullptr;
|
PubMqttType *mMqtt = nullptr;
|
||||||
JsonObject *mLog;
|
DynamicJsonHandler* mLog;
|
||||||
IApp *mApp = nullptr;
|
IApp *mApp = nullptr;
|
||||||
|
|
||||||
unsigned long mPreviousTsp = millis();
|
unsigned long mPreviousTsp = millis();
|
||||||
|
@ -294,7 +294,7 @@ class powermeter {
|
||||||
/** setHeader
|
/** setHeader
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void setHeader(HTTPClient *h) {
|
void setHeader(HTTPClient *h, String auth = "", u8_t realm = NULL) {
|
||||||
h->setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
h->setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
|
||||||
/// h->setUserAgent("Ahoy-Agent");
|
/// h->setUserAgent("Ahoy-Agent");
|
||||||
/// // TODO: Ahoy-0.8.850024-zero
|
/// // TODO: Ahoy-0.8.850024-zero
|
||||||
|
@ -303,6 +303,43 @@ class powermeter {
|
||||||
h->setTimeout(1000);
|
h->setTimeout(1000);
|
||||||
h->addHeader("Content-Type", "application/json");
|
h->addHeader("Content-Type", "application/json");
|
||||||
h->addHeader("Accept", "application/json");
|
h->addHeader("Accept", "application/json");
|
||||||
|
|
||||||
|
/*
|
||||||
|
Shelly PM Mini Gen3
|
||||||
|
Shelly Plus 1PM
|
||||||
|
Shelly Plus 2PM
|
||||||
|
Shelly Pro 3EM - 120A
|
||||||
|
Shelly Pro 4PM
|
||||||
|
Shelly Pro Dual Cover / Shutter PM
|
||||||
|
Shelly Pro 1PM
|
||||||
|
Shelly Pro 2PM
|
||||||
|
Shelly Pro EM - 50
|
||||||
|
Shelly Qubino Wave 1PM Mini
|
||||||
|
Shelly Qubino Wave PM Mini
|
||||||
|
Shelly Qubino Wave Shutter
|
||||||
|
Shelly Qubino Wave 1PM
|
||||||
|
Shelly Qubino Wave 2PM
|
||||||
|
Shelly Qubino Wave Pro 1PM
|
||||||
|
Shelly Qubino Wave Pro 2PM
|
||||||
|
Shelly 3EM
|
||||||
|
Shelly EM + 120A Clamp
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
/*if (auth != NULL && realm) http.addHeader("WWW-Authenticate", "Digest qop=\"auth\", realm=\"" + shellypro4pm-f008d1d8b8b8 + "\", nonce=\"60dc59c6\", algorithm=SHA-256");
|
||||||
|
else if (auth != NULL) http.addHeader("Authorization", "Basic " + auth);*/
|
||||||
|
/*
|
||||||
|
All Required:
|
||||||
|
realm: string, device_id of the Shelly device.
|
||||||
|
username: string, must be set to admin.
|
||||||
|
nonce: number, random or pseudo-random number to prevent replay attacks, taken from the error message.
|
||||||
|
cnonce: number, client nonce, random number generated by the client.
|
||||||
|
response: string, encoding of the string <ha1> + ":" + <nonce> + ":" + <nc> + ":" + <cnonce> + ":" + "auth" + ":" + <ha2> in SHA256.
|
||||||
|
ha1: string, <user>:<realm>:<password> encoded in SHA256
|
||||||
|
ha2: string, "dummy_method:dummy_uri" encoded in SHA256
|
||||||
|
algorithm: string, SHA-256.
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
#if defined(ZEROEXPORT_POWERMETER_SHELLY)
|
#if defined(ZEROEXPORT_POWERMETER_SHELLY)
|
||||||
|
@ -312,13 +349,13 @@ class powermeter {
|
||||||
* @param group
|
* @param group
|
||||||
* @returns true/false
|
* @returns true/false
|
||||||
*/
|
*/
|
||||||
bool getPowermeterWattsShelly(JsonObject logObj, uint8_t group, float *power) {
|
bool getPowermeterWattsShelly(uint8_t group, float *power) {
|
||||||
logObj["mod"] = "getPowermeterWattsShelly";
|
mLog->addProperty("mod", "getPowermeterWattsShelly");
|
||||||
|
|
||||||
setHeader(&http);
|
setHeader(&http);
|
||||||
|
|
||||||
String url = String("http://") + String(mCfg->groups[group].pm_src) + String("/") + String(mCfg->groups[group].pm_jsonPath);
|
String url = String("http://") + String(mCfg->groups[group].pm_src) + String("/") + String(mCfg->groups[group].pm_jsonPath);
|
||||||
logObj["HTTP_URL"] = url;
|
mLog->addProperty("HTTP_URL", url);
|
||||||
|
|
||||||
http.begin(url);
|
http.begin(url);
|
||||||
|
|
||||||
|
@ -327,7 +364,7 @@ class powermeter {
|
||||||
DynamicJsonDocument doc(2048);
|
DynamicJsonDocument doc(2048);
|
||||||
DeserializationError error = deserializeJson(doc, http.getString());
|
DeserializationError error = deserializeJson(doc, http.getString());
|
||||||
if (error) {
|
if (error) {
|
||||||
logObj["err"] = "deserializeJson: " + String(error.c_str());
|
mLog->addProperty("err", "deserializeJson: " + String(error.c_str()));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
switch (mCfg->groups[group].pm_target) {
|
switch (mCfg->groups[group].pm_target) {
|
||||||
|
@ -395,7 +432,7 @@ class powermeter {
|
||||||
* @param group
|
* @param group
|
||||||
* @returns true/false
|
* @returns true/false
|
||||||
*/
|
*/
|
||||||
bool getPowermeterWattsTasmota(JsonObject logObj, uint8_t group, float *power) {
|
bool getPowermeterWattsTasmota(DynamicJsonHandler logObj, uint8_t group, float *power) {
|
||||||
logObj["mod"] = "getPowermeterWattsTasmota";
|
logObj["mod"] = "getPowermeterWattsTasmota";
|
||||||
/*
|
/*
|
||||||
// TODO: nicht komplett
|
// TODO: nicht komplett
|
||||||
|
@ -467,7 +504,7 @@ class powermeter {
|
||||||
* @param group
|
* @param group
|
||||||
* @returns true/false
|
* @returns true/false
|
||||||
*/
|
*/
|
||||||
bool getPowermeterWattsHichi(JsonObject logObj, uint8_t group, float *power) {
|
bool getPowermeterWattsHichi(DynamicJsonHandler logObj, uint8_t group, float *power) {
|
||||||
logObj["mod"] = "getPowermeterWattsHichi";
|
logObj["mod"] = "getPowermeterWattsHichi";
|
||||||
|
|
||||||
// Hier neuer Code - Anfang
|
// Hier neuer Code - Anfang
|
||||||
|
@ -518,17 +555,20 @@ class powermeter {
|
||||||
{{0x01, 0x00, 0x01, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterImport},
|
{{0x01, 0x00, 0x01, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterImport},
|
||||||
{{0x01, 0x00, 0x02, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterExport}};
|
{{0x01, 0x00, 0x02, 0x08, 0x00, 0xff}, &smlOBISWh, &_powerMeterExport}};
|
||||||
|
|
||||||
bool getPowermeterWattsTibber(JsonObject logObj, uint8_t group, float *power) {
|
/*
|
||||||
|
Daniel92: https://tibber.com/de/api/lookup/price-overview?postalCode=
|
||||||
|
Hab ich mal ausgelesen... hintendran die PLZ eingeben
|
||||||
|
energy/todayHours/<aktuelleStunde>/priceIncludingVat
|
||||||
|
*/
|
||||||
|
bool getPowermeterWattsTibber(uint8_t group, float *power) {
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
mLog->addProperty("mod", "getPowermeterWattsTibber");
|
||||||
logObj["mod"] = "getPowermeterWattsTibber";
|
|
||||||
|
|
||||||
String auth = mCfg->groups[group].pm_pass;
|
String auth = mCfg->groups[group].pm_pass;
|
||||||
String url = String("http://") + mCfg->groups[group].pm_src + String("/") + String(mCfg->groups[group].pm_jsonPath);
|
String url = String("http://") + mCfg->groups[group].pm_src + String("/") + String(mCfg->groups[group].pm_jsonPath);
|
||||||
|
|
||||||
setHeader(&http);
|
setHeader(&http, auth);
|
||||||
http.begin(url);
|
http.begin(url);
|
||||||
http.addHeader("Authorization", "Basic " + auth);
|
|
||||||
|
|
||||||
if (http.GET() == HTTP_CODE_OK && http.getSize() > 0) {
|
if (http.GET() == HTTP_CODE_OK && http.getSize() > 0) {
|
||||||
String myString = http.getString();
|
String myString = http.getString();
|
||||||
|
@ -571,8 +611,8 @@ class powermeter {
|
||||||
* @TODO: Username & Passwort wird mittels base64 verschlüsselt. Dies wird für die Authentizierung benötigt. Wichtig diese im WebUI unkenntlich zu machen und base64 im eeprom zu speichern, statt klartext.
|
* @TODO: Username & Passwort wird mittels base64 verschlüsselt. Dies wird für die Authentizierung benötigt. Wichtig diese im WebUI unkenntlich zu machen und base64 im eeprom zu speichern, statt klartext.
|
||||||
* @TODO: Abfrage Interval einbauen. Info: Datei-Size kann auch mal 0-bytes sein?
|
* @TODO: Abfrage Interval einbauen. Info: Datei-Size kann auch mal 0-bytes sein?
|
||||||
*/
|
*/
|
||||||
bool getPowermeterWattsShrdzm(JsonObject logObj, uint8_t group, float *power) {
|
bool getPowermeterWattsShrdzm(uint8_t group, float *power) {
|
||||||
logObj["mod"] = "getPowermeterWattsShrdzm";
|
mLog->addProperty("mod", "getPowermeterWattsShrdzm");
|
||||||
|
|
||||||
setHeader(&http);
|
setHeader(&http);
|
||||||
|
|
||||||
|
@ -587,7 +627,7 @@ class powermeter {
|
||||||
DynamicJsonDocument doc(512);
|
DynamicJsonDocument doc(512);
|
||||||
DeserializationError error = deserializeJson(doc, http.getString());
|
DeserializationError error = deserializeJson(doc, http.getString());
|
||||||
if (error) {
|
if (error) {
|
||||||
logObj["err"] = "deserializeJson: " + String(error.c_str());
|
mLog->addProperty("err", "deserializeJson: " + String(error.c_str()));
|
||||||
return false;
|
return false;
|
||||||
} else {
|
} else {
|
||||||
if (doc.containsKey(F("16.7.0"))) {
|
if (doc.containsKey(F("16.7.0"))) {
|
||||||
|
@ -606,8 +646,7 @@ class powermeter {
|
||||||
*/
|
*/
|
||||||
void bufferWrite(float raw, short group) {
|
void bufferWrite(float raw, short group) {
|
||||||
mPowermeterBuffer[group][mPowermeterBufferPos[group]] = raw;
|
mPowermeterBuffer[group][mPowermeterBufferPos[group]] = raw;
|
||||||
mPowermeterBufferPos[group]++;
|
mPowermeterBufferPos[group] = (mPowermeterBufferPos[group] + 1) % 5;
|
||||||
if (mPowermeterBufferPos[group] >= 5) mPowermeterBufferPos[group] = 0;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,8 @@
|
||||||
#include "AsyncJson.h"
|
#include "AsyncJson.h"
|
||||||
#include "powermeter.h"
|
#include "powermeter.h"
|
||||||
|
|
||||||
|
#include "utils/DynamicJsonHandler.h"
|
||||||
|
|
||||||
template <class HMSYSTEM>
|
template <class HMSYSTEM>
|
||||||
|
|
||||||
class ZeroExport {
|
class ZeroExport {
|
||||||
|
@ -47,9 +49,16 @@ class ZeroExport {
|
||||||
mApi = api;
|
mApi = api;
|
||||||
mMqtt = mqtt;
|
mMqtt = mqtt;
|
||||||
|
|
||||||
mIsInitialized = mPowermeter.setup(mApp, mCfg, mqtt, &mLog);
|
mIsInitialized = mPowermeter.setup(mApp, mCfg, mqtt, &_log);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*void printJson() {
|
||||||
|
serializeJson(doc, Serial);
|
||||||
|
Serial.println();
|
||||||
|
serializeJsonPretty(doc, Serial);
|
||||||
|
}*/
|
||||||
|
|
||||||
/** loop
|
/** loop
|
||||||
* Arbeitsschleife
|
* Arbeitsschleife
|
||||||
* @param void
|
* @param void
|
||||||
|
@ -83,13 +92,13 @@ class ZeroExport {
|
||||||
zeroExportGroupInverter_t *CfgGroupInv = &CfgGroup->inverters[inv];
|
zeroExportGroupInverter_t *CfgGroupInv = &CfgGroup->inverters[inv];
|
||||||
Inverter<> *iv = mSys->getInverterByPos(Queue.id);
|
Inverter<> *iv = mSys->getInverterByPos(Queue.id);
|
||||||
|
|
||||||
mLog["g"] = group;
|
_log.addProperty("g", group);
|
||||||
mLog["i"] = inv;
|
_log.addProperty("i", inv);
|
||||||
|
|
||||||
// Check Data->iv
|
// Check Data->iv
|
||||||
if (!iv->isAvailable()) {
|
if (!iv->isAvailable()) {
|
||||||
if (mCfg->debug) {
|
if (mCfg->debug) {
|
||||||
mLog["nA"] = "!isAvailable";
|
_log.addProperty("nA", "!isAvailable");
|
||||||
sendLog();
|
sendLog();
|
||||||
}
|
}
|
||||||
clearLog();
|
clearLog();
|
||||||
|
@ -99,7 +108,7 @@ class ZeroExport {
|
||||||
// Check Data->waitAck
|
// Check Data->waitAck
|
||||||
if (CfgGroupInv->waitAck > 0) {
|
if (CfgGroupInv->waitAck > 0) {
|
||||||
if (mCfg->debug) {
|
if (mCfg->debug) {
|
||||||
mLog["wA"] = CfgGroupInv->waitAck;
|
_log.addProperty("wA", CfgGroupInv->waitAck);
|
||||||
sendLog();
|
sendLog();
|
||||||
}
|
}
|
||||||
clearLog();
|
clearLog();
|
||||||
|
@ -113,16 +122,19 @@ class ZeroExport {
|
||||||
groupPower += mCfg->groups[group].inverters[inv].power; // Calc Data->groupPower
|
groupPower += mCfg->groups[group].inverters[inv].power; // Calc Data->groupPower
|
||||||
groupLimit += mCfg->groups[group].inverters[inv].limit; // Calc Data->groupLimit
|
groupLimit += mCfg->groups[group].inverters[inv].limit; // Calc Data->groupLimit
|
||||||
}
|
}
|
||||||
mLog["gP"] = groupPower;
|
|
||||||
mLog["gL"] = groupLimit;
|
_log.addProperty("gP", groupPower);
|
||||||
|
_log.addProperty("gL", groupLimit);
|
||||||
|
|
||||||
// Batteryprotection
|
// Batteryprotection
|
||||||
mLog["bEn"] = (uint8_t)CfgGroup->battCfg;
|
_log.addProperty("bEn", (uint8_t)CfgGroup->battCfg);
|
||||||
|
|
||||||
switch (CfgGroup->battCfg) {
|
switch (CfgGroup->battCfg) {
|
||||||
case zeroExportBatteryCfg::none:
|
case zeroExportBatteryCfg::none:
|
||||||
if (CfgGroup->battSwitch != true) {
|
if (CfgGroup->battSwitch != true) {
|
||||||
CfgGroup->battSwitch = true;
|
CfgGroup->battSwitch = true;
|
||||||
mLog["bA"] = "turn on";
|
|
||||||
|
_log.addProperty("bA", "turn on");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case zeroExportBatteryCfg::invUdc:
|
case zeroExportBatteryCfg::invUdc:
|
||||||
|
@ -131,34 +143,34 @@ class ZeroExport {
|
||||||
if (CfgGroup->battSwitch != true) {
|
if (CfgGroup->battSwitch != true) {
|
||||||
if (CfgGroup->battValue > CfgGroup->battLimitOn) {
|
if (CfgGroup->battValue > CfgGroup->battLimitOn) {
|
||||||
CfgGroup->battSwitch = true;
|
CfgGroup->battSwitch = true;
|
||||||
mLog["bA"] = "turn on";
|
_log.addProperty("bA", "turn on");
|
||||||
}
|
}
|
||||||
if ((CfgGroup->battValue > CfgGroup->battLimitOff) && (CfgGroupInv->power > 0)) {
|
if ((CfgGroup->battValue > CfgGroup->battLimitOff) && (CfgGroupInv->power > 0)) {
|
||||||
CfgGroup->battSwitch = true;
|
CfgGroup->battSwitch = true;
|
||||||
mLog["bA"] = "turn on";
|
_log.addProperty("bA", "turn on");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (CfgGroup->battValue < CfgGroup->battLimitOff) {
|
if (CfgGroup->battValue < CfgGroup->battLimitOff) {
|
||||||
CfgGroup->battSwitch = false;
|
CfgGroup->battSwitch = false;
|
||||||
mLog["bA"] = "turn off";
|
_log.addProperty("bA", "turn off");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLog["bU"] = ah::round1(CfgGroup->battValue);
|
_log.addProperty("bU", ah::round1(CfgGroup->battValue));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
if (CfgGroup->battSwitch == true) {
|
if (CfgGroup->battSwitch == true) {
|
||||||
CfgGroup->battSwitch = false;
|
CfgGroup->battSwitch = false;
|
||||||
mLog["bA"] = "turn off";
|
_log.addProperty("bA", "turn off");
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
mLog["bSw"] = CfgGroup->battSwitch;
|
_log.addProperty("bSw", CfgGroup->battSwitch);
|
||||||
|
|
||||||
// Controller
|
// Controller
|
||||||
|
|
||||||
// Führungsgröße w in Watt
|
// Führungsgröße w in Watt
|
||||||
int16_t w = CfgGroup->setPoint;
|
int16_t w = CfgGroup->setPoint;
|
||||||
mLog["w"] = w;
|
_log.addProperty("w", w);
|
||||||
|
|
||||||
// Regelgröße x in Watt
|
// Regelgröße x in Watt
|
||||||
int16_t x = 0.0;
|
int16_t x = 0.0;
|
||||||
|
@ -167,16 +179,16 @@ class ZeroExport {
|
||||||
} else {
|
} else {
|
||||||
x = mPowermeter.getDataAVG(group);
|
x = mPowermeter.getDataAVG(group);
|
||||||
}
|
}
|
||||||
mLog["x"] = x;
|
_log.addProperty("x", x);
|
||||||
|
|
||||||
// Regelabweichung e in Watt
|
// Regelabweichung e in Watt
|
||||||
int16_t e = w - x;
|
int16_t e = w - x;
|
||||||
mLog["e"] = e;
|
_log.addProperty("e", e);
|
||||||
|
|
||||||
// Keine Regelung innerhalb der Toleranzgrenzen
|
// Keine Regelung innerhalb der Toleranzgrenzen
|
||||||
if ((e < CfgGroup->powerTolerance) && (e > -CfgGroup->powerTolerance)) {
|
if ((e < CfgGroup->powerTolerance) && (e > -CfgGroup->powerTolerance)) {
|
||||||
e = 0;
|
e = 0;
|
||||||
mLog["eK"] = e;
|
_log.addProperty("eK", e);
|
||||||
sendLog();
|
sendLog();
|
||||||
clearLog();
|
clearLog();
|
||||||
return;
|
return;
|
||||||
|
@ -192,7 +204,7 @@ class ZeroExport {
|
||||||
CfgGroup->eSum += e;
|
CfgGroup->eSum += e;
|
||||||
int16_t yI = Ki * Ta * CfgGroup->eSum;
|
int16_t yI = Ki * Ta * CfgGroup->eSum;
|
||||||
if (Ta == 0) {
|
if (Ta == 0) {
|
||||||
mLog["Error"] = "Ta = 0";
|
_log.addProperty("Error", "Ta = 0");
|
||||||
sendLog();
|
sendLog();
|
||||||
clearLog();
|
clearLog();
|
||||||
return;
|
return;
|
||||||
|
@ -200,21 +212,21 @@ class ZeroExport {
|
||||||
int16_t yD = Kd * (e - CfgGroup->eOld) / Ta;
|
int16_t yD = Kd * (e - CfgGroup->eOld) / Ta;
|
||||||
|
|
||||||
if (mCfg->debug) {
|
if (mCfg->debug) {
|
||||||
mLog["Kp"] = Kp;
|
_log.addProperty("Kp", Kp);
|
||||||
mLog["Ki"] = Ki;
|
_log.addProperty("Ki", Ki);
|
||||||
mLog["Kd"] = Kd;
|
_log.addProperty("Kd", Kd);
|
||||||
mLog["Ta"] = Ta;
|
_log.addProperty("Ta", Ta);
|
||||||
mLog["yP"] = yP;
|
_log.addProperty("yP", yP);
|
||||||
mLog["yI"] = yI;
|
_log.addProperty("yI", yI);
|
||||||
mLog["eSum"] = CfgGroup->eSum;
|
_log.addProperty("eSum", CfgGroup->eSum);
|
||||||
mLog["yD"] = yD;
|
_log.addProperty("yD", yD);
|
||||||
mLog["eOld"] = CfgGroup->eOld;
|
_log.addProperty("eOld", CfgGroup->eOld);
|
||||||
}
|
}
|
||||||
|
|
||||||
CfgGroup->eOld = e;
|
CfgGroup->eOld = e;
|
||||||
int16_t y = yP + yI + yD;
|
int16_t y = yP + yI + yD;
|
||||||
|
|
||||||
mLog["y"] = y;
|
_log.addProperty("y", y);
|
||||||
|
|
||||||
// Regelbegrenzung
|
// Regelbegrenzung
|
||||||
// TODO: Hier könnte man den maximalen Sprung begrenzen
|
// TODO: Hier könnte man den maximalen Sprung begrenzen
|
||||||
|
@ -230,7 +242,7 @@ class ZeroExport {
|
||||||
if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = 1;
|
if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = 1;
|
||||||
if (CfgGroupInv->actionTimer > 10) {
|
if (CfgGroupInv->actionTimer > 10) {
|
||||||
CfgGroupInv->action = zeroExportAction_t::doTurnOn;
|
CfgGroupInv->action = zeroExportAction_t::doTurnOn;
|
||||||
mLog["do"] = "doTurnOn";
|
_log.addProperty("do", "doTurnOn");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ((CfgGroupInv->turnOff) && (CfgGroupInv->limitNew <= 0) && (CfgGroupInv->power > 0)) {
|
if ((CfgGroupInv->turnOff) && (CfgGroupInv->limitNew <= 0) && (CfgGroupInv->power > 0)) {
|
||||||
|
@ -238,26 +250,28 @@ class ZeroExport {
|
||||||
if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = -1;
|
if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = -1;
|
||||||
if (CfgGroupInv->actionTimer < 30) {
|
if (CfgGroupInv->actionTimer < 30) {
|
||||||
CfgGroupInv->action = zeroExportAction_t::doTurnOff;
|
CfgGroupInv->action = zeroExportAction_t::doTurnOff;
|
||||||
mLog["do"] = "doTurnOff";
|
_log.addProperty("do", "doTurnOff");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (((CfgGroup->battSwitch == false) || (mCfg->sleep == true) || (CfgGroup->sleep == true)) && (CfgGroupInv->power > 0)) {
|
if (((CfgGroup->battSwitch == false) || (mCfg->sleep == true) || (CfgGroup->sleep == true)) && (CfgGroupInv->power > 0)) {
|
||||||
CfgGroupInv->action = zeroExportAction_t::doTurnOff;
|
CfgGroupInv->action = zeroExportAction_t::doTurnOff;
|
||||||
mLog["do"] = "sleep";
|
_log.addProperty("do", "sleep");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
mLog["doT"] = CfgGroupInv->action;
|
_log.addProperty("doT", CfgGroupInv->action);
|
||||||
|
|
||||||
if (CfgGroupInv->action == zeroExportAction_t::doNone) {
|
if (CfgGroupInv->action == zeroExportAction_t::doNone) {
|
||||||
mLog["l"] = CfgGroupInv->limit;
|
_log.addProperty("l", CfgGroupInv->limit);
|
||||||
mLog["ln"] = CfgGroupInv->limitNew;
|
_log.addProperty("ln", CfgGroupInv->limitNew);
|
||||||
|
|
||||||
// groupMax
|
// groupMax
|
||||||
uint16_t otherIvLimit = groupLimit - CfgGroupInv->limit;
|
uint16_t otherIvLimit = groupLimit - CfgGroupInv->limit;
|
||||||
if ((otherIvLimit + CfgGroupInv->limitNew) > CfgGroup->powerMax) {
|
if ((otherIvLimit + CfgGroupInv->limitNew) > CfgGroup->powerMax) {
|
||||||
CfgGroupInv->limitNew = CfgGroup->powerMax - otherIvLimit;
|
CfgGroupInv->limitNew = CfgGroup->powerMax - otherIvLimit;
|
||||||
}
|
}
|
||||||
if (mCfg->debug) mLog["gPM"] = CfgGroup->powerMax;
|
if (mCfg->debug) {
|
||||||
|
_log.addProperty("gPM", CfgGroup->powerMax);
|
||||||
|
}
|
||||||
|
|
||||||
// PowerMax
|
// PowerMax
|
||||||
uint16_t powerMax = 100;
|
uint16_t powerMax = 100;
|
||||||
|
@ -291,13 +305,13 @@ class ZeroExport {
|
||||||
|
|
||||||
// CfgGroupInv->actionTimer = 0;
|
// CfgGroupInv->actionTimer = 0;
|
||||||
// TODO: Timer stoppen wenn Limit gesetzt wird.
|
// TODO: Timer stoppen wenn Limit gesetzt wird.
|
||||||
mLog["lN"] = CfgGroupInv->limitNew;
|
_log.addProperty("lN", CfgGroupInv->limitNew);
|
||||||
|
|
||||||
CfgGroupInv->limit = CfgGroupInv->limitNew;
|
CfgGroupInv->limit = CfgGroupInv->limitNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
// doAction
|
// doAction
|
||||||
mLog["a"] = CfgGroupInv->action;
|
_log.addProperty("a", CfgGroupInv->action);
|
||||||
|
|
||||||
switch (CfgGroupInv->action) {
|
switch (CfgGroupInv->action) {
|
||||||
case zeroExportAction_t::doRestart:
|
case zeroExportAction_t::doRestart:
|
||||||
|
@ -422,14 +436,20 @@ class ZeroExport {
|
||||||
if (!mCfg->groups[group].inverters[inv].enabled) continue;
|
if (!mCfg->groups[group].inverters[inv].enabled) continue;
|
||||||
|
|
||||||
if (iv->id == (uint8_t)mCfg->groups[group].inverters[inv].id) {
|
if (iv->id == (uint8_t)mCfg->groups[group].inverters[inv].id) {
|
||||||
mLog["g"] = group;
|
_log.addProperty("g", group);
|
||||||
mLog["i"] = inv;
|
_log.addProperty("i", inv);
|
||||||
|
|
||||||
mCfg->groups[group].inverters[inv].waitAck = 0;
|
mCfg->groups[group].inverters[inv].waitAck = 0;
|
||||||
mLog["wA"] = mCfg->groups[group].inverters[inv].waitAck;
|
|
||||||
|
_log.addProperty("wA", mCfg->groups[group].inverters[inv].waitAck);
|
||||||
|
|
||||||
|
// Wenn ein neuer LimitWert da ist. Soll es in group schreiben.
|
||||||
if (iv->actPowerLimit != 0xffff) {
|
if (iv->actPowerLimit != 0xffff) {
|
||||||
mLog["l"] = mCfg->groups[group].inverters[inv].limit;
|
_log.addProperty("l", mCfg->groups[group].inverters[inv].limit);
|
||||||
|
|
||||||
mCfg->groups[group].inverters[inv].limit = iv->actPowerLimit;
|
mCfg->groups[group].inverters[inv].limit = iv->actPowerLimit;
|
||||||
mLog["lF"] = mCfg->groups[group].inverters[inv].limit;
|
|
||||||
|
_log.addProperty("lF", mCfg->groups[group].inverters[inv].limit);
|
||||||
}
|
}
|
||||||
sendLog();
|
sendLog();
|
||||||
clearLog();
|
clearLog();
|
||||||
|
@ -453,10 +473,12 @@ class ZeroExport {
|
||||||
if (!mCfg->groups[group].inverters[inv].enabled) continue;
|
if (!mCfg->groups[group].inverters[inv].enabled) continue;
|
||||||
|
|
||||||
if (iv->id == mCfg->groups[group].inverters[inv].id) {
|
if (iv->id == mCfg->groups[group].inverters[inv].id) {
|
||||||
mLog["g"] = group;
|
_log.addProperty("g", group);
|
||||||
mLog["i"] = inv;
|
_log.addProperty("i", inv);
|
||||||
|
|
||||||
mCfg->groups[group].inverters[inv].waitAck = 0;
|
mCfg->groups[group].inverters[inv].waitAck = 0;
|
||||||
mLog["wA"] = mCfg->groups[group].inverters[inv].waitAck;
|
|
||||||
|
_log.addProperty("wA", mCfg->groups[group].inverters[inv].waitAck);
|
||||||
sendLog();
|
sendLog();
|
||||||
clearLog();
|
clearLog();
|
||||||
}
|
}
|
||||||
|
@ -479,10 +501,12 @@ class ZeroExport {
|
||||||
if (!mCfg->groups[group].inverters[inv].enabled) continue;
|
if (!mCfg->groups[group].inverters[inv].enabled) continue;
|
||||||
|
|
||||||
if (iv->id == mCfg->groups[group].inverters[inv].id) {
|
if (iv->id == mCfg->groups[group].inverters[inv].id) {
|
||||||
mLog["g"] = group;
|
_log.addProperty("g", group);
|
||||||
mLog["i"] = inv;
|
_log.addProperty("i", inv);
|
||||||
|
|
||||||
mCfg->groups[group].inverters[inv].waitAck = 0;
|
mCfg->groups[group].inverters[inv].waitAck = 0;
|
||||||
mLog["wA"] = mCfg->groups[group].inverters[inv].waitAck;
|
|
||||||
|
_log.addProperty("wA", mCfg->groups[group].inverters[inv].waitAck);
|
||||||
|
|
||||||
mCfg->groups[group].inverters[inv].limit = mCfg->groups[group].inverters[inv].powerMin;
|
mCfg->groups[group].inverters[inv].limit = mCfg->groups[group].inverters[inv].powerMin;
|
||||||
iv->powerLimit[0] = static_cast<uint16_t>(mCfg->groups[group].inverters[inv].limit * 10.0);
|
iv->powerLimit[0] = static_cast<uint16_t>(mCfg->groups[group].inverters[inv].limit * 10.0);
|
||||||
|
@ -518,8 +542,8 @@ class ZeroExport {
|
||||||
if (!CfgGroupInv->enabled) continue;
|
if (!CfgGroupInv->enabled) continue;
|
||||||
if (CfgGroupInv->id != iv->id) continue;
|
if (CfgGroupInv->id != iv->id) continue;
|
||||||
|
|
||||||
mLog["g"] = group;
|
_log.addProperty("g", group);
|
||||||
mLog["i"] = inv;
|
_log.addProperty("i", inv);
|
||||||
|
|
||||||
// TODO: Ist nach eventAckSetLimit verschoben
|
// TODO: Ist nach eventAckSetLimit verschoben
|
||||||
// if (iv->actPowerLimit != 0xffff) {
|
// if (iv->actPowerLimit != 0xffff) {
|
||||||
|
@ -531,17 +555,19 @@ class ZeroExport {
|
||||||
// TODO: Es dauert bis getMaxPower übertragen wird.
|
// TODO: Es dauert bis getMaxPower übertragen wird.
|
||||||
if (iv->getMaxPower() > 0) {
|
if (iv->getMaxPower() > 0) {
|
||||||
CfgGroupInv->MaxPower = iv->getMaxPower();
|
CfgGroupInv->MaxPower = iv->getMaxPower();
|
||||||
mLog["pM"] = CfgGroupInv->MaxPower;
|
|
||||||
|
_log.addProperty("pM", CfgGroupInv->MaxPower);
|
||||||
}
|
}
|
||||||
|
|
||||||
record_t<> *rec;
|
record_t<> *rec;
|
||||||
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
rec = iv->getRecordStruct(RealTimeRunData_Debug);
|
||||||
if (iv->getLastTs(rec) > (millis() - 15000)) {
|
if (iv->getLastTs(rec) > (millis() - 15000)) {
|
||||||
CfgGroupInv->power = iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
CfgGroupInv->power = iv->getChannelFieldValue(CH0, FLD_PAC, rec);
|
||||||
mLog["p"] = CfgGroupInv->power;
|
|
||||||
|
_log.addProperty("pM", CfgGroupInv->MaxPower);
|
||||||
|
|
||||||
CfgGroupInv->dcVoltage = iv->getChannelFieldValue(CH1, FLD_UDC, rec);
|
CfgGroupInv->dcVoltage = iv->getChannelFieldValue(CH1, FLD_UDC, rec);
|
||||||
mLog["bU"] = ah::round1(CfgGroupInv->dcVoltage);
|
_log.addProperty("bU", ah::round1(CfgGroupInv->dcVoltage));
|
||||||
|
|
||||||
// Batterieüberwachung - Überwachung über die DC-Spannung am PV-Eingang 1 des Inverters
|
// Batterieüberwachung - Überwachung über die DC-Spannung am PV-Eingang 1 des Inverters
|
||||||
if (CfgGroup->battCfg == zeroExportBatteryCfg::invUdc) {
|
if (CfgGroup->battCfg == zeroExportBatteryCfg::invUdc) {
|
||||||
|
@ -561,16 +587,16 @@ class ZeroExport {
|
||||||
uint16_t powerPercent = 100 / CfgGroupInv->MaxPower * CfgGroupInv->power;
|
uint16_t powerPercent = 100 / CfgGroupInv->MaxPower * CfgGroupInv->power;
|
||||||
uint16_t delta = abs(limitPercent - powerPercent);
|
uint16_t delta = abs(limitPercent - powerPercent);
|
||||||
if ((delta > 10) && (CfgGroupInv->power > 0)) {
|
if ((delta > 10) && (CfgGroupInv->power > 0)) {
|
||||||
mLog["delta"] = delta;
|
_log.addProperty("delta", delta);
|
||||||
unsigned long delay = iv->getLastTs(rec) - CfgGroupInv->actionTimestamp;
|
unsigned long delay = iv->getLastTs(rec) - CfgGroupInv->actionTimestamp;
|
||||||
mLog["delay"] = delay;
|
_log.addProperty("delay", delay);
|
||||||
if (delay > 30000) {
|
if (delay > 30000) {
|
||||||
CfgGroupInv->action = zeroExportAction_t::doActivePowerContr;
|
CfgGroupInv->action = zeroExportAction_t::doActivePowerContr;
|
||||||
mLog["do"] = "doActivePowerContr";
|
_log.addProperty("do", "doActivePowerContr");
|
||||||
}
|
}
|
||||||
if (delay > 60000) {
|
if (delay > 60000) {
|
||||||
CfgGroupInv->action = zeroExportAction_t::doRestart;
|
CfgGroupInv->action = zeroExportAction_t::doRestart;
|
||||||
mLog["do"] = "doRestart";
|
_log.addProperty("do", "doRestart");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -584,7 +610,6 @@ class ZeroExport {
|
||||||
|
|
||||||
sendLog();
|
sendLog();
|
||||||
clearLog();
|
clearLog();
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -634,40 +659,59 @@ class ZeroExport {
|
||||||
|
|
||||||
if (strcmp(mCfg->groups[group].battTopic, String(topic).c_str())) {
|
if (strcmp(mCfg->groups[group].battTopic, String(topic).c_str())) {
|
||||||
mCfg->groups[group].battValue = (bool)obj["val"];
|
mCfg->groups[group].battValue = (bool)obj["val"];
|
||||||
mLog["k"] = mCfg->groups[group].battTopic;
|
|
||||||
mLog["v"] = mCfg->groups[group].battValue;
|
|
||||||
|
_log.addProperty("k", mCfg->groups[group].battTopic);
|
||||||
|
_log.addProperty("v", mCfg->groups[group].battValue);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// "topic":"ctrl/zero"
|
// "topic":"ctrl/zero"
|
||||||
if (topic.indexOf("ctrl/zero") == -1) return;
|
if (topic.indexOf("ctrl/zero") == -1) return;
|
||||||
|
|
||||||
if (mCfg->debug) mLog["d"] = obj;
|
|
||||||
|
_log.addProperty("d", obj);
|
||||||
|
|
||||||
if (obj["path"] == "ctrl" && obj["cmd"] == "zero") {
|
if (obj["path"] == "ctrl" && obj["cmd"] == "zero") {
|
||||||
int8_t topicGroup = getGroupFromTopic(topic.c_str());
|
int8_t topicGroup = getGroupFromTopic(topic.c_str());
|
||||||
int8_t topicInverter = getInverterFromTopic(topic.c_str());
|
int8_t topicInverter = getInverterFromTopic(topic.c_str());
|
||||||
|
|
||||||
if (topicGroup != -1) mLog["g"] = topicGroup;
|
if (topicGroup != -1) {
|
||||||
if (topicInverter == -1) mLog["i"] = topicInverter;
|
_log.addProperty("g", topicGroup);
|
||||||
|
}
|
||||||
|
if (topicInverter == -1) {
|
||||||
|
_log.addProperty("i", topicInverter);
|
||||||
|
}
|
||||||
|
|
||||||
mLog["k"] = topic;
|
_log.addProperty("k", topic);
|
||||||
|
|
||||||
// "topic":"ctrl/zero/enabled"
|
// "topic":"ctrl/zero/enabled"
|
||||||
if (topic.indexOf("ctrl/zero/enabled") != -1) mCfg->enabled = mLog["v"] = (bool)obj["val"];
|
if (topic.indexOf("ctrl/zero/enabled") != -1) {
|
||||||
|
_log.addProperty("v", (bool)obj["val"]);
|
||||||
|
mCfg->enabled = (bool)obj["val"];
|
||||||
|
}
|
||||||
|
|
||||||
// "topic":"ctrl/zero/sleep"
|
// "topic":"ctrl/zero/sleep"
|
||||||
else if (topic.indexOf("ctrl/zero/sleep") != -1) mCfg->sleep = mLog["v"] = (bool)obj["val"];
|
else if (topic.indexOf("ctrl/zero/sleep") != -1) {
|
||||||
|
_log.addProperty("v", (bool)obj["val"]);
|
||||||
|
mCfg->sleep = (bool)obj["val"];
|
||||||
|
}
|
||||||
|
|
||||||
else if ((topicGroup >= 0) && (topicGroup < ZEROEXPORT_MAX_GROUPS))
|
else if ((topicGroup >= 0) && (topicGroup < ZEROEXPORT_MAX_GROUPS))
|
||||||
{
|
{
|
||||||
String stopicGroup = String(topicGroup);
|
String stopicGroup = String(topicGroup);
|
||||||
|
|
||||||
// "topic":"ctrl/zero/groups/+/enabled"
|
// "topic":"ctrl/zero/groups/+/enabled"
|
||||||
if (topic.endsWith("/enabled")) mCfg->groups[topicGroup].enabled = mLog["v"] = (bool)obj["val"];
|
if (topic.endsWith("/enabled")) {
|
||||||
|
_log.addProperty("v", (bool)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].enabled = (bool)obj["val"];
|
||||||
|
}
|
||||||
|
|
||||||
// "topic":"ctrl/zero/groups/+/sleep"
|
// "topic":"ctrl/zero/groups/+/sleep"
|
||||||
else if (topic.endsWith("/sleep")) mCfg->groups[topicGroup].sleep = mLog["v"] = (bool)obj["val"];
|
else if (topic.endsWith("/sleep")) {
|
||||||
|
_log.addProperty("v", (bool)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].sleep = (bool)obj["val"];
|
||||||
|
}
|
||||||
|
|
||||||
// Auf Eis gelegt, dafür 2 Gruppen mehr
|
// Auf Eis gelegt, dafür 2 Gruppen mehr
|
||||||
// 0.8.103008.2
|
// 0.8.103008.2
|
||||||
|
@ -692,36 +736,59 @@ class ZeroExport {
|
||||||
// }
|
// }
|
||||||
|
|
||||||
// "topic":"ctrl/zero/groups/+/battery/switch"
|
// "topic":"ctrl/zero/groups/+/battery/switch"
|
||||||
else if (topic.endsWith("/battery/switch")) mCfg->groups[topicGroup].battSwitch = mLog["v"] = (bool)obj["val"];
|
else if (topic.endsWith("/battery/switch")) {
|
||||||
|
_log.addProperty("v", (bool)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].battSwitch = (bool)obj["val"];
|
||||||
|
}
|
||||||
|
|
||||||
else if (topic.indexOf("/advanced/") != -1)
|
else if (topic.indexOf("/advanced/") != -1)
|
||||||
{
|
{
|
||||||
// "topic":"ctrl/zero/groups/+/advanced/setPoint"
|
// "topic":"ctrl/zero/groups/+/advanced/setPoint"
|
||||||
if (topic.endsWith("/setPoint")) mCfg->groups[topicGroup].setPoint = mLog["v"] = (int16_t)obj["val"];
|
if (topic.endsWith("/setPoint")) {
|
||||||
|
_log.addProperty("v", (int16_t)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].setPoint = (int16_t)obj["val"];
|
||||||
|
}
|
||||||
|
|
||||||
// "topic":"ctrl/zero/groups/+/advanced/powerTolerance"
|
// "topic":"ctrl/zero/groups/+/advanced/powerTolerance"
|
||||||
else if (topic.endsWith("/powerTolerance")) mCfg->groups[topicGroup].powerTolerance = mLog["v"] = (uint8_t)obj["val"];
|
else if (topic.endsWith("/powerTolerance")) {
|
||||||
|
_log.addProperty("v", (uint8_t)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].powerTolerance = (uint8_t)obj["val"];
|
||||||
|
}
|
||||||
|
|
||||||
// "topic":"ctrl/zero/groups/+/advanced/powerMax"
|
// "topic":"ctrl/zero/groups/+/advanced/powerMax"
|
||||||
else if (topic.endsWith("/powerMax")) mCfg->groups[topicGroup].powerMax = mLog["v"] = (uint16_t)obj["val"];
|
else if (topic.endsWith("/powerMax")) {
|
||||||
|
_log.addProperty("v", (uint16_t)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].powerMax = (uint16_t)obj["val"];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else if (topic.indexOf("/inverter/") != -1)
|
else if (topic.indexOf("/inverter/") != -1)
|
||||||
{
|
{
|
||||||
if ((topicInverter >= 0) && (topicInverter < ZEROEXPORT_GROUP_MAX_INVERTERS))
|
if ((topicInverter >= 0) && (topicInverter < ZEROEXPORT_GROUP_MAX_INVERTERS))
|
||||||
{
|
{
|
||||||
// "topic":"ctrl/zero/groups/+/inverter/+/enabled"
|
// "topic":"ctrl/zero/groups/+/inverter/+/enabled"
|
||||||
if (topic.endsWith("/enabled")) mCfg->groups[topicGroup].inverters[topicInverter].enabled = mLog["v"] = (bool)obj["val"];
|
if (topic.endsWith("/enabled")) {
|
||||||
|
_log.addProperty("v", (bool)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].inverters[topicInverter].enabled = (bool)obj["val"];
|
||||||
|
}
|
||||||
|
|
||||||
// "topic":"ctrl/zero/groups/+/inverter/+/powerMin"
|
// "topic":"ctrl/zero/groups/+/inverter/+/powerMin"
|
||||||
else if (topic.endsWith("/powerMin")) mCfg->groups[topicGroup].inverters[topicInverter].powerMin = mLog["v"] = (uint16_t)obj["val"];
|
else if (topic.endsWith("/powerMin")) {
|
||||||
|
_log.addProperty("v", (uint16_t)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].inverters[topicInverter].powerMin = (uint16_t)obj["val"];
|
||||||
|
}
|
||||||
// "topic":"ctrl/zero/groups/+/inverter/+/powerMax"
|
// "topic":"ctrl/zero/groups/+/inverter/+/powerMax"
|
||||||
else if (topic.endsWith("/powerMax")) mCfg->groups[topicGroup].inverters[topicInverter].powerMax = mLog["v"] = (uint16_t)obj["val"];
|
else if (topic.endsWith("/powerMax")) {
|
||||||
else mLog["k"] = "error";
|
_log.addProperty("v", (uint16_t)obj["val"]);
|
||||||
|
mCfg->groups[topicGroup].inverters[topicInverter].powerMax = (uint16_t)obj["val"];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
_log.addProperty("k", "error");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
mLog["k"] = "error";
|
_log.addProperty("k", "error");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -770,7 +837,8 @@ class ZeroExport {
|
||||||
while (*pGroupSection != '/' && digitsCopied < 2) strGroup[digitsCopied++] = *pGroupSection++;
|
while (*pGroupSection != '/' && digitsCopied < 2) strGroup[digitsCopied++] = *pGroupSection++;
|
||||||
strGroup[digitsCopied] = '\0';
|
strGroup[digitsCopied] = '\0';
|
||||||
int8_t group = atoi(strGroup);
|
int8_t group = atoi(strGroup);
|
||||||
mLog["getGroupFromTopic"] = group;
|
|
||||||
|
_log.addProperty("getGroupFromTopic", "group");
|
||||||
return group;
|
return group;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -819,7 +887,7 @@ class ZeroExport {
|
||||||
void sendLog(void) {
|
void sendLog(void) {
|
||||||
// Log over Webserial
|
// Log over Webserial
|
||||||
if (mCfg->log_over_webserial) {
|
if (mCfg->log_over_webserial) {
|
||||||
DPRINTLN(DBG_INFO, String("ze: ") + mDocLog.as<String>());
|
DPRINTLN(DBG_INFO, String("ze: ") + _log.toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Log over MQTT
|
// Log over MQTT
|
||||||
|
@ -836,12 +904,15 @@ class ZeroExport {
|
||||||
* Löscht den LogSpeicher
|
* Löscht den LogSpeicher
|
||||||
*/
|
*/
|
||||||
void clearLog(void) {
|
void clearLog(void) {
|
||||||
mDocLog.clear();
|
_log.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
// private member variables
|
// private member variables
|
||||||
bool mIsInitialized = false;
|
bool mIsInitialized = false;
|
||||||
|
|
||||||
|
// Maximale Größe des JSON-Dokuments
|
||||||
|
static const size_t max_size = 5000;
|
||||||
|
|
||||||
IApp *mApp = nullptr;
|
IApp *mApp = nullptr;
|
||||||
uint32_t *mTimestamp = nullptr;
|
uint32_t *mTimestamp = nullptr;
|
||||||
zeroExport_t *mCfg = nullptr;
|
zeroExport_t *mCfg = nullptr;
|
||||||
|
@ -855,15 +926,12 @@ class ZeroExport {
|
||||||
|
|
||||||
unsigned long mLastRun = 0;
|
unsigned long mLastRun = 0;
|
||||||
|
|
||||||
StaticJsonDocument<5000> mDocLog;
|
|
||||||
JsonObject mLog = mDocLog.to<JsonObject>();
|
|
||||||
|
|
||||||
powermeter mPowermeter;
|
powermeter mPowermeter;
|
||||||
|
|
||||||
PubMqttType *mMqtt = nullptr;
|
PubMqttType *mMqtt = nullptr;
|
||||||
bool mIsSubscribed = false;
|
bool mIsSubscribed = false;
|
||||||
StaticJsonDocument<512> mqttDoc; // DynamicJsonDocument mqttDoc(512);
|
|
||||||
JsonObject mqttObj = mqttDoc.to<JsonObject>();
|
DynamicJsonHandler _log;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /*__ZEROEXPORT__*/
|
#endif /*__ZEROEXPORT__*/
|
||||||
|
|
38
src/utils/DynamicJsonHandler.cpp
Normal file
38
src/utils/DynamicJsonHandler.cpp
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
#include "DynamicJsonHandler.h"
|
||||||
|
|
||||||
|
DynamicJsonHandler::DynamicJsonHandler() : doc(min_size) {
|
||||||
|
}
|
||||||
|
|
||||||
|
DynamicJsonHandler::~DynamicJsonHandler() {
|
||||||
|
delete &doc;
|
||||||
|
}
|
||||||
|
|
||||||
|
String DynamicJsonHandler::toString() {
|
||||||
|
String jsonString;
|
||||||
|
serializeJson(doc, jsonString);
|
||||||
|
return jsonString;
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicJsonHandler::clear() {
|
||||||
|
doc.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DynamicJsonHandler::size() const {
|
||||||
|
return doc.memoryUsage();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DynamicJsonHandler::resizeDocument(size_t requiredSize) {
|
||||||
|
// TODO: multiplikator zwei muss ersetzt werden? Kann noch minimal werden.
|
||||||
|
size_t newCapacity = min(max(requiredSize * 2, min_size), max_size);
|
||||||
|
DynamicJsonDocument newDoc(newCapacity);
|
||||||
|
newDoc.set(doc); // Bestehende Daten kopieren
|
||||||
|
doc = std::move(newDoc);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DynamicJsonHandler::min(size_t a, size_t b) {
|
||||||
|
return (a < b) ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t DynamicJsonHandler::max(size_t a, size_t b) {
|
||||||
|
return (a > b) ? a : b;
|
||||||
|
}
|
44
src/utils/DynamicJsonHandler.h
Normal file
44
src/utils/DynamicJsonHandler.h
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// 2022 Ahoy, https://github.com/lumpapu/ahoy
|
||||||
|
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
#ifndef __DYNAMICJSONHANDLER_H__
|
||||||
|
#define __DYNAMICJSONHANDLER_H__
|
||||||
|
|
||||||
|
#include <Arduino.h>
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class DynamicJsonHandler {
|
||||||
|
public:
|
||||||
|
DynamicJsonHandler();
|
||||||
|
~DynamicJsonHandler();
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void addProperty(const std::string& key, const T& value);
|
||||||
|
|
||||||
|
String toString();
|
||||||
|
void clear();
|
||||||
|
size_t size() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
DynamicJsonDocument doc;
|
||||||
|
static const size_t min_size = 256;
|
||||||
|
static const size_t max_size = 5000; // Max RAM : 2 = da es für resizeDocument eng werden könnte?
|
||||||
|
|
||||||
|
void resizeDocument(size_t requiredSize);
|
||||||
|
size_t min(size_t a, size_t b);
|
||||||
|
size_t max(size_t a, size_t b);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
void DynamicJsonHandler::addProperty(const std::string& key, const T& value) {
|
||||||
|
size_t additionalSize = JSON_OBJECT_SIZE(1) + key.length() + sizeof(value);
|
||||||
|
if (doc.memoryUsage() + additionalSize > doc.capacity()) {
|
||||||
|
resizeDocument(doc.memoryUsage() + additionalSize);
|
||||||
|
}
|
||||||
|
doc[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*__DYNAMICJSONHANDLER_H__*/
|
Loading…
Add table
Add a link
Reference in a new issue