Browse Source

0.8.910006-zero

pull/1521/head
Patrick Amrhein 7 months ago
parent
commit
cf52731802
  1. 2
      src/app.cpp
  2. 15
      src/config/settings.h
  3. 2
      src/defines.h
  4. 336
      src/plugins/zeroExport/zeroExport.h

2
src/app.cpp

@ -126,7 +126,7 @@ void app::setup() {
#if defined(PLUGIN_ZEROEXPORT) #if defined(PLUGIN_ZEROEXPORT)
// TODO: aufräumen // TODO: aufräumen
// if (mConfig->plugin.zeroExport.enabled) { // if (mConfig->plugin.zeroExport.enabled) {
mZeroExport.setup(&mConfig->plugin.zeroExport, &mSys, mConfig, &mApi); mZeroExport.setup(&mConfig->plugin.zeroExport, &mSys, mConfig, &mApi, &mMqtt);
// } // }
#endif #endif
// Plugin ZeroExport - Ende // Plugin ZeroExport - Ende

15
src/config/settings.h

@ -241,15 +241,14 @@ typedef struct {
int8_t target; int8_t target;
uint16_t powerMin; uint16_t powerMin;
uint16_t powerMax; uint16_t powerMax;
//
float power; float power;
uint16_t limit; uint16_t limit;
uint16_t limitNew; uint16_t limitNew;
unsigned long limitTsp; unsigned long limitTsp;
// bool limitAck;
float dcVoltage; float dcVoltage;
// uint16_t waitingTime; bool state;
} zeroExportGroupInverter_t; } zeroExportGroupInverter_t;
typedef struct { typedef struct {
@ -273,7 +272,7 @@ typedef struct {
uint8_t refresh; uint8_t refresh;
uint8_t powerTolerance; uint8_t powerTolerance;
uint16_t powerMax; uint16_t powerMax;
//
zeroExportState state; zeroExportState state;
zeroExportState stateNext; zeroExportState stateNext;
@ -287,10 +286,10 @@ typedef struct {
float grpPowerL1; float grpPowerL1;
float grpPowerL2; float grpPowerL2;
float grpPowerL3; float grpPowerL3;
float grpLimit; // float grpLimit;
float grpLimitL1; // float grpLimitL1;
float grpLimitL2; // float grpLimitL2;
float grpLimitL3; // float grpLimitL3;
// uint16_t power; // Aktueller Verbrauch // uint16_t power; // Aktueller Verbrauch
// uint16_t powerLimitAkt; // Aktuelles Limit // uint16_t powerLimitAkt; // Aktuelles Limit

2
src/defines.h

@ -13,7 +13,7 @@
//------------------------------------- //-------------------------------------
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 8 #define VERSION_MINOR 8
#define VERSION_PATCH 910004 #define VERSION_PATCH 910006
//------------------------------------- //-------------------------------------
typedef struct { typedef struct {

336
src/plugins/zeroExport/zeroExport.h

@ -11,7 +11,7 @@
template <class HMSYSTEM> template <class HMSYSTEM>
// TODO: Anbindung an MQTT für Logausgabe zuzüglich DBG-Ausgabe in json. Deshalb alle Debugausgaben ersetzten durch json, dazu sollte ein jsonObject an die Funktion übergeben werden, zu dem die Funktion dann ihren Teil hinzufügt. // TODO: Anbindung an MQTT für Logausgabe.
// TODO: Powermeter erweitern // TODO: Powermeter erweitern
// TODO: Der Teil der noch in app.pp steckt komplett hier in die Funktion verschieben. // TODO: Der Teil der noch in app.pp steckt komplett hier in die Funktion verschieben.
@ -19,20 +19,35 @@ class ZeroExport {
public: public:
/**
* ZeroExport
*/
ZeroExport() { ZeroExport() {
mIsInitialized = false; mIsInitialized = false;
} }
void setup(zeroExport_t *cfg, HMSYSTEM *sys, settings_t *config, RestApiType *api) { /**
* ~ZeroExport
*/
~ZeroExport() {}
/**
* setup
*/
void setup(zeroExport_t *cfg, HMSYSTEM *sys, settings_t *config, RestApiType *api, PubMqttType *mqtt) {
mCfg = cfg; mCfg = cfg;
mSys = sys; mSys = sys;
mConfig = config; mConfig = config;
mApi = api; mApi = api;
mMqtt = mqtt;
// TODO: Sicherheitsreturn weil noch Sicherheitsfunktionen fehlen. // TODO: Sicherheitsreturn weil noch Sicherheitsfunktionen fehlen.
// mIsInitialized = true; // mIsInitialized = true;
} }
/**
* loop
*/
void loop(void) { void loop(void) {
if ((!mIsInitialized) || (!mCfg->enabled)) { if ((!mIsInitialized) || (!mCfg->enabled)) {
return; return;
@ -115,8 +130,12 @@ return;
} }
break; break;
default: default:
DBGPRINT(String("ze: ")); // TODO: Debug Webserial. Deaktiviert um CPU-Last zu verringern.
DBGPRINTLN(mDocLog.as<String>()); DBGPRINTLN(String("ze: "));
// DBGPRINTLN(mDocLog.as<String>());
if (mMqtt->isConnected()) {
mMqtt->publish("ze", mDocLog.as<std::string>().c_str(), false);
}
mDocLog.clear(); mDocLog.clear();
if (mCfg->groups[group].stateNext != mCfg->groups[group].state) { if (mCfg->groups[group].stateNext != mCfg->groups[group].state) {
mCfg->groups[group].state = mCfg->groups[group].stateNext; mCfg->groups[group].state = mCfg->groups[group].stateNext;
@ -129,6 +148,9 @@ return;
} }
} }
/**
* tickerSecond
*/
void tickerSecond() { void tickerSecond() {
// TODO: Warten ob benötigt, ggf ein bit setzen, das in der loop() abgearbeitet wird. // TODO: Warten ob benötigt, ggf ein bit setzen, das in der loop() abgearbeitet wird.
if ((!mIsInitialized) || (!mCfg->enabled)) { if ((!mIsInitialized) || (!mCfg->enabled)) {
@ -136,57 +158,6 @@ return;
} }
} }
/*
// TODO: Inverter sortieren nach Leistung
// -> Aufsteigend bei Leistungserhöhung
// -> Absteigend bei Leistungsreduzierung
for (uint8_t inv = 0; inv < ZEROEXPORT_GROUP_MAX_INVERTERS; inv++) {
if (!mCfg->groups[group].inverters[inv].enabled) {
continue;
}
if (mCfg->groups[group].inverters[inv].waitingTime) {
mCfg->groups[group].inverters[inv].waitingTime--;
continue;
}
// Leistung erhöhen
if (mCfg->groups[group].power < mCfg->groups[group].powerLimitAkt - mCfg->groups[group].powerHyst) {
// mCfg->groups[group].powerLimitAkt = mCfg->groups[group].power
mCfg->groups[group].inverters[inv].waitingTime = ZEROEXPORT_DEF_INV_WAITINGTIME_MS;
return;
}
// Leistung reduzieren
if (mCfg->groups[group].power > mCfg->groups[group].powerLimitAkt + mCfg->groups[group].powerHyst) {
mCfg->groups[group].inverters[inv].waitingTime = ZEROEXPORT_DEF_INV_WAITINGTIME_MS;
return;
}
if ((Power < PowerLimit - Hyst) || (Power > PowerLimit + Hyst)) {
if (Limit < 2%) {
setPower(Off);
setPowerLimit(100%)
} else {
setPower(On);
setPowerLimit(Limit);
mCfg->Inv[inv].waitingTime = ZEROEXPORT_DEF_INV_WAITINGTIME_MS;
}
}
}
*/
private: private:
/* /*
// TODO: Vorlage für nachfolgende Funktion getPowermeterWatts. Funktionen erst zusammenführen, wenn keine weiteren Powermeter mehr kommen. // TODO: Vorlage für nachfolgende Funktion getPowermeterWatts. Funktionen erst zusammenführen, wenn keine weiteren Powermeter mehr kommen.
@ -297,7 +268,10 @@ return;
return result; return result;
} }
int getPowermeterWattsShelly(JsonObject logObj, uint8_t group) { /**
* getPowermeterWattsShelly
*/
bool getPowermeterWattsShelly(JsonObject logObj, uint8_t group) {
bool result = false; bool result = false;
mCfg->groups[group].pmPower = 0; mCfg->groups[group].pmPower = 0;
@ -427,7 +401,10 @@ return;
return result; return result;
} }
int getPowermeterWattsTasmota(JsonObject logObj, uint8_t group) { /**
* getPowermeterWattsTasmota
*/
bool getPowermeterWattsTasmota(JsonObject logObj, uint8_t group) {
// TODO: nicht komplett // TODO: nicht komplett
bool ret = false; bool ret = false;
@ -484,7 +461,10 @@ return;
return ret; return ret;
} }
int getPowermeterWattsMqtt(JsonObject logObj, uint8_t group) { /**
* getPowermeterWattsMqtt
*/
bool getPowermeterWattsMqtt(JsonObject logObj, uint8_t group) {
// TODO: nicht komplett // TODO: nicht komplett
bool ret = false; bool ret = false;
@ -500,7 +480,10 @@ return;
return ret; return ret;
} }
int getPowermeterWattsHichi(JsonObject logObj, uint8_t group) { /**
* getPowermeterWattsHichi
*/
bool getPowermeterWattsHichi(JsonObject logObj, uint8_t group) {
// TODO: nicht komplett // TODO: nicht komplett
bool ret = false; bool ret = false;
@ -516,7 +499,10 @@ return;
return ret; return ret;
} }
int getPowermeterWattsTibber(JsonObject logObj, uint8_t group) { /**
* getPowermeterWattsTibber
*/
bool getPowermeterWattsTibber(JsonObject logObj, uint8_t group) {
// TODO: nicht komplett // TODO: nicht komplett
bool ret = false; bool ret = false;
@ -534,6 +520,9 @@ return;
// Inverter // Inverter
/**
* getInverterData
*/
bool getInverterData(uint8_t group) { bool getInverterData(uint8_t group) {
zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; zeroExportGroup_t *cfgGroup = &mCfg->groups[group];
@ -612,16 +601,15 @@ return;
// TODO: Eingang muss konfigurierbar sein // TODO: Eingang muss konfigurierbar sein
// ACK // ACK
if (cfgGroupInv->limitTsp != 0) { if (iv->powerLimitAck) {
if (iv->powerLimitAck) { iv->powerLimitAck = false;
iv->powerLimitAck = false; cfgGroupInv->limitTsp = 0;
cfgGroupInv->limitTsp = 0; }
} if (cfgGroupInv->limitTsp > 0) {
if ((millis() + 10000) > cfgGroupInv->limitTsp) { if ((millis() + 10000) > cfgGroupInv->limitTsp) {
cfgGroupInv->limitTsp = 0; cfgGroupInv->limitTsp = 0;
} }
} }
ret = true; ret = true;
} }
} }
@ -644,6 +632,7 @@ return;
bool batteryProtection(uint8_t group) { bool batteryProtection(uint8_t group) {
zeroExportGroup_t *cfgGroup = &mCfg->groups[group]; zeroExportGroup_t *cfgGroup = &mCfg->groups[group];
// TODO: Wenn kein WR gefunden wird, wird nicht abgeschaltet!!! // TODO: Wenn kein WR gefunden wird, wird nicht abgeschaltet!!!
// TODO: Es fehlt die Möglichkeit manuell einzuschalten
JsonObject logObj = mLog.createNestedObject("bp"); JsonObject logObj = mLog.createNestedObject("bp");
logObj["grp"] = group; logObj["grp"] = group;
@ -737,15 +726,9 @@ return;
long int bTsp = millis(); long int bTsp = millis();
// Führungsgröße w in Watt // Führungsgröße w in Watt
float w_Sum = cfgGroup->setPoint; float w = cfgGroup->setPoint;
float w_L1 = cfgGroup->setPoint / 3;
float w_L2 = cfgGroup->setPoint / 3;
float w_L3 = cfgGroup->setPoint / 3;
logObj["w_P"] = w_Sum; logObj["w"] = w;
logObj["w_P1"] = w_L1;
logObj["w_P2"] = w_L2;
logObj["w_P3"] = w_L3;
// Regelgröße x in Watt // Regelgröße x in Watt
float x_Sum = cfgGroup->pmPower; float x_Sum = cfgGroup->pmPower;
@ -759,10 +742,10 @@ return;
logObj["x_P3"] = x_L3; logObj["x_P3"] = x_L3;
// Regelabweichung e in Watt // Regelabweichung e in Watt
float e_Sum = 0 - (w_Sum - x_Sum); float e_Sum = w - x_Sum;
float e_L1 = 0 - (w_L1 - x_L1); float e_L1 = w - x_L1;
float e_L2 = 0 - (w_L2 - x_L2); float e_L2 = w - x_L2;
float e_L3 = 0 - (w_L3 - x_L3); float e_L3 = w - x_L3;
logObj["e_P"] = e_Sum; logObj["e_P"] = e_Sum;
logObj["e_P1"] = e_L1; logObj["e_P1"] = e_L1;
@ -771,11 +754,9 @@ return;
// Regler // Regler
// TODO: Regelparameter unter Advanced konfigurierbar? Aber erst wenn Regler komplett ingegriert. // TODO: Regelparameter unter Advanced konfigurierbar? Aber erst wenn Regler komplett ingegriert.
const float Kp = 1; const float Kp = -1;
const float Ki = 1; const float Ki = -1;
const float Kd = 1; const float Kd = -1;
// unsigned long tsp = millis();
// - P-Anteil // - P-Anteil
float yP_Sum = Kp * e_Sum; float yP_Sum = Kp * e_Sum;
@ -810,10 +791,10 @@ return;
logObj["yPID_P2"] = yPID_L2; logObj["yPID_P2"] = yPID_L2;
logObj["yPID_P3"] = yPID_L3; logObj["yPID_P3"] = yPID_L3;
cfgGroup->grpPower += yPID_Sum; cfgGroup->grpPower = yPID_Sum;
cfgGroup->grpPowerL1 += yPID_L1; cfgGroup->grpPowerL1 = yPID_L1;
cfgGroup->grpPowerL2 += yPID_L2; cfgGroup->grpPowerL2 = yPID_L2;
cfgGroup->grpPowerL3 += yPID_L3; cfgGroup->grpPowerL3 = yPID_L3;
long int eTsp = millis(); long int eTsp = millis();
logObj["b"] = bTsp; logObj["b"] = bTsp;
@ -836,13 +817,8 @@ return;
JsonObject logObj = mLog.createNestedObject("sl"); JsonObject logObj = mLog.createNestedObject("sl");
logObj["grp"] = group; logObj["grp"] = group;
// bool ret = true;
long int bTsp = millis(); long int bTsp = millis();
// JsonArray logArrInv = logObj.createNestedArray("iv");
// unsigned long tsp = millis();
float deltaY_Sum = cfgGroup->grpPower; float deltaY_Sum = cfgGroup->grpPower;
float deltaY_L1 = cfgGroup->grpPowerL1; float deltaY_L1 = cfgGroup->grpPowerL1;
float deltaY_L2 = cfgGroup->grpPowerL2; float deltaY_L2 = cfgGroup->grpPowerL2;
@ -871,6 +847,16 @@ return;
continue; continue;
} }
if ((cfgGroup->battSwitch) && (!cfgGroupInv->state)) {
setPower(&logObj, group, inv, 1);
return false;
}
if ((!cfgGroup->battSwitch) && (cfgGroupInv->state)) {
setPower(&logObj, group, inv, 0);
return false;
}
if (cfgGroupInv->power < ivPmin[cfgGroupInv->target]) { if (cfgGroupInv->power < ivPmin[cfgGroupInv->target]) {
grpTarget[cfgGroupInv->target] = true; grpTarget[cfgGroupInv->target] = true;
ivPmin[cfgGroupInv->target] = cfgGroupInv->power; ivPmin[cfgGroupInv->target] = cfgGroupInv->power;
@ -915,73 +901,70 @@ return;
// Leistung erhöhen // Leistung erhöhen
if (*deltaP > 0) { if (*deltaP > 0) {
// Toleranz
if (*deltaP < cfgGroup->powerTolerance) {
continue;
}
logObj["+deltaP"] = *deltaP; logObj["+deltaP"] = *deltaP;
zeroExportGroupInverter_t *cfgGroupInv = &cfgGroup->inverters[ivId_Pmin[i]]; zeroExportGroupInverter_t *cfgGroupInv = &cfgGroup->inverters[ivId_Pmin[i]];
cfgGroupInv->limitNew = cfgGroupInv->limit + *deltaP; cfgGroupInv->limitNew = (uint16_t)((float)cfgGroupInv->limit + *deltaP);
if (i != 0) { // if (i != 0) {
cfgGroup->grpPower - *deltaP; // cfgGroup->grpPower - *deltaP;
} // }
*deltaP = 0; *deltaP = 0;
if (cfgGroupInv->limitNew > cfgGroupInv->powerMax) { // if (cfgGroupInv->limitNew > cfgGroupInv->powerMax) {
*deltaP = cfgGroupInv->limitNew - cfgGroupInv->powerMax; // *deltaP = cfgGroupInv->limitNew - cfgGroupInv->powerMax;
cfgGroupInv->limitNew = cfgGroupInv->powerMax; // cfgGroupInv->limitNew = cfgGroupInv->powerMax;
if (i != 0) { // if (i != 0) {
cfgGroup->grpPower + *deltaP; // cfgGroup->grpPower + *deltaP;
} // }
} // }
setLimit(&logObj, group, ivId_Pmin[i]); setLimit(&logObj, group, ivId_Pmin[i]);
continue; continue;
} }
// Leistung reduzieren // Leistung reduzieren
if (*deltaP < 0) { if (*deltaP < 0) {
// Toleranz
if (*deltaP > -cfgGroup->powerTolerance) {
continue;
}
logObj["-deltaP"] = *deltaP; logObj["-deltaP"] = *deltaP;
zeroExportGroupInverter_t *cfgGroupInv = &cfgGroup->inverters[ivId_Pmax[i]]; zeroExportGroupInverter_t *cfgGroupInv = &cfgGroup->inverters[ivId_Pmax[i]];
cfgGroupInv->limitNew = cfgGroupInv->limit - *deltaP; cfgGroupInv->limitNew = (uint16_t)((float)cfgGroupInv->limit + *deltaP);
if (i != 0) { // if (i != 0) {
cfgGroup->grpPower - *deltaP; // cfgGroup->grpPower - *deltaP;
} // }
*deltaP = 0; *deltaP = 0;
if (cfgGroupInv->limitNew < cfgGroupInv->powerMin) { // if (cfgGroupInv->limitNew < cfgGroupInv->powerMin) {
*deltaP = cfgGroupInv->limitNew - cfgGroupInv->powerMin; // *deltaP = cfgGroupInv->limitNew - cfgGroupInv->powerMin;
cfgGroupInv->limitNew = cfgGroupInv->powerMin; // cfgGroupInv->limitNew = cfgGroupInv->powerMin;
if (i != 0) { // if (i != 0) {
cfgGroup->grpPower + *deltaP; // cfgGroup->grpPower + *deltaP;
} // }
} // }
setLimit(&logObj, group, ivId_Pmax[i]); setLimit(&logObj, group, ivId_Pmax[i]);
continue; continue;
} }
} }
// if (ret) {
// logObj["todo"] = "- nothing todo - ";
// }
long int eTsp = millis(); long int eTsp = millis();
logObj["b"] = bTsp; logObj["b"] = bTsp;
logObj["e"] = eTsp; logObj["e"] = eTsp;
logObj["d"] = eTsp - bTsp; logObj["d"] = eTsp - bTsp;
// return ret;
return true; return true;
} }
// Funktionen
/**
* setLimit
* @param objLog
* @param group
* @param inv
* @returns true/false
*/
// TODO: Hier folgen Unterfunktionen für SetControl die Erweitert werden müssen
// setLimit, checkLimit
// setPower, checkPower
// setReboot, checkReboot
bool setLimit(JsonObject *objlog, uint8_t group, uint8_t inv) { bool setLimit(JsonObject *objlog, uint8_t group, uint8_t inv) {
zeroExportGroupInverter_t *cfgGroupInv = &mCfg->groups[group].inverters[inv]; zeroExportGroupInverter_t *cfgGroupInv = &mCfg->groups[group].inverters[inv];
@ -990,11 +973,20 @@ return;
objLog["iv"] = inv; objLog["iv"] = inv;
// Reject limit if difference < 5 W // Reject limit if difference < 5 W
// if ((cfgGroupInv->limitNew > cfgGroupInv->limit - 5) && (cfgGroupInv->limitNew < cfgGroupInv->limit + 5)) { if ((cfgGroupInv->limitNew > cfgGroupInv->limit + 5) && (cfgGroupInv->limitNew < cfgGroupInv->limit - 5)) {
// TODO: 5W Toleranz konfigurierbar? objLog["err"] = "Diff < 5W";
// objLog["error"] = "Diff < 5W"; return false;
// return true; }
// }
// Restriction LimitNew >= Pmin
if (cfgGroupInv->limitNew < cfgGroupInv->powerMin) {
cfgGroupInv->limitNew = cfgGroupInv->powerMin;
}
// Restriction LimitNew <= Pmax
if (cfgGroupInv->limitNew > cfgGroupInv->powerMax) {
cfgGroupInv->limitNew = cfgGroupInv->powerMax;
}
cfgGroupInv->limit = cfgGroupInv->limitNew; cfgGroupInv->limit = cfgGroupInv->limitNew;
cfgGroupInv->limitTsp = millis(); cfgGroupInv->limitTsp = millis();
@ -1016,7 +1008,74 @@ return;
return true; return true;
} }
/**
* setPower
* @param objLog
* @param group
* @param inv
* @param state
* @returns true/false
*/
bool setPower(JsonObject *objlog, uint8_t group, uint8_t inv, bool state) {
zeroExportGroupInverter_t *cfgGroupInv = &mCfg->groups[group].inverters[inv];
JsonObject objLog = objlog->createNestedObject("setPower");
objLog["grp"] = group;
objLog["iv"] = inv;
// cfgGroupInv->limit = cfgGroupInv->limitNew;
cfgGroupInv->limitTsp = millis();
// objLog["P"] = cfgGroupInv->limit;
objLog["tsp"] = cfgGroupInv->limitTsp;
// State übergeben
DynamicJsonDocument doc(512);
JsonObject obj = doc.to<JsonObject>();
obj["val"] = state;
obj["id"] = cfgGroupInv->id;
obj["path"] = "ctrl";
obj["cmd"] = "power";
mApi->ctrlRequest(obj);
objLog["data"] = obj;
return false;
}
/**
* setReboot
* @param objLog
* @param group
* @param inv
* @returns true/false
*/
bool setReboot(JsonObject *objlog, uint8_t group, uint8_t inv) {
zeroExportGroupInverter_t *cfgGroupInv = &mCfg->groups[group].inverters[inv];
JsonObject objLog = objlog->createNestedObject("setReboot");
objLog["grp"] = group;
objLog["iv"] = inv;
// cfgGroupInv->limit = cfgGroupInv->limitNew;
cfgGroupInv->limitTsp = millis();
// objLog["P"] = cfgGroupInv->limit;
objLog["tsp"] = cfgGroupInv->limitTsp;
// Reboot übergeben
DynamicJsonDocument doc(512);
JsonObject obj = doc.to<JsonObject>();
// obj["val"] = cfgGroupInv->limit;
obj["id"] = cfgGroupInv->id;
obj["path"] = "ctrl";
obj["cmd"] = "restart";
mApi->ctrlRequest(obj);
objLog["data"] = obj;
return false;
}
/* /*
// TODO: Vorlage für Berechnung // TODO: Vorlage für Berechnung
@ -1060,6 +1119,7 @@ return;
RestApiType *mApi; RestApiType *mApi;
StaticJsonDocument<5000> mDocLog; StaticJsonDocument<5000> mDocLog;
JsonObject mLog = mDocLog.to<JsonObject>(); JsonObject mLog = mDocLog.to<JsonObject>();
PubMqttType *mMqtt;
}; };

Loading…
Cancel
Save