mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-02 19:55:54 +02:00
0.8.1030008
This commit is contained in:
parent
139baf680a
commit
06b34b16c4
4 changed files with 117 additions and 30 deletions
|
@ -265,6 +265,8 @@ typedef struct {
|
||||||
//
|
//
|
||||||
|
|
||||||
zeroExportAction_t action;
|
zeroExportAction_t action;
|
||||||
|
int8_t actionTimer;
|
||||||
|
unsigned long actionTimestamp;
|
||||||
uint16_t power;
|
uint16_t power;
|
||||||
uint16_t MaxPower;
|
uint16_t MaxPower;
|
||||||
int32_t limit;
|
int32_t limit;
|
||||||
|
@ -682,6 +684,7 @@ class settings {
|
||||||
//
|
//
|
||||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].waitAck = 0;
|
mCfg.plugin.zeroExport.groups[group].inverters[inv].waitAck = 0;
|
||||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].action = zeroExportAction_t::doNone;
|
mCfg.plugin.zeroExport.groups[group].inverters[inv].action = zeroExportAction_t::doNone;
|
||||||
|
mCfg.plugin.zeroExport.groups[group].inverters[inv].actionTimer = 0;;
|
||||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].dcVoltage = 0;
|
mCfg.plugin.zeroExport.groups[group].inverters[inv].dcVoltage = 0;
|
||||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].limit = 0;
|
mCfg.plugin.zeroExport.groups[group].inverters[inv].limit = 0;
|
||||||
mCfg.plugin.zeroExport.groups[group].inverters[inv].limitNew = 0;
|
mCfg.plugin.zeroExport.groups[group].inverters[inv].limitNew = 0;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
#define VERSION_MAJOR 0
|
#define VERSION_MAJOR 0
|
||||||
#define VERSION_MINOR 8
|
#define VERSION_MINOR 8
|
||||||
#define VERSION_PATCH 1030007
|
#define VERSION_PATCH 1030008
|
||||||
//-------------------------------------
|
//-------------------------------------
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint8_t ch;
|
uint8_t ch;
|
||||||
|
|
|
@ -109,6 +109,8 @@ class powermeter {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ((power.P == 0) and (power.P1 == 0) && (power.P2 == 0) && (power.P3 == 0)) return;
|
||||||
|
|
||||||
bufferWrite(power, group);
|
bufferWrite(power, group);
|
||||||
|
|
||||||
// MQTT - Powermeter
|
// MQTT - Powermeter
|
||||||
|
@ -153,6 +155,19 @@ class powermeter {
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
void onMqttConnect(void) {
|
void onMqttConnect(void) {
|
||||||
|
|
||||||
|
#if defined(ZEROEXPORT_POWERMETER_MQTT)
|
||||||
|
|
||||||
|
for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||||
|
if (mCfg->groups[group].pm_type == zeroExportPowermeterType_t::Mqtt) {
|
||||||
|
// if (String(mCfg->groups[group].pm_jsonPath) == "") return;
|
||||||
|
|
||||||
|
mMqtt->subscribe(String(mCfg->groups[group].pm_jsonPath).c_str(), QOS_2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /*defined(ZEROEXPORT_POWERMETER_MQTT)*/
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -163,17 +178,39 @@ class powermeter {
|
||||||
|
|
||||||
#if defined(ZEROEXPORT_POWERMETER_MQTT)
|
#if defined(ZEROEXPORT_POWERMETER_MQTT)
|
||||||
// topic for powermeter?
|
// topic for powermeter?
|
||||||
for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
// for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||||
if (mCfg->groups[group].pm_type == zeroExportPowermeterType_t::Mqtt) {
|
// if (mCfg->groups[group].pm_type == zeroExportPowermeterType_t::Mqtt) {
|
||||||
// mLog["mqttDevice"] = "topicInverter";
|
// // mLog["mqttDevice"] = "topicInverter";
|
||||||
if (!topic.equals(mCfg->groups[group].pm_jsonPath)) return;
|
// if (!topic.equals(mCfg->groups[group].pm_jsonPath)) return;
|
||||||
mCfg->groups[group].pm_P = (int32_t)obj["val"];
|
// mCfg->groups[group].pm_P = (int32_t)obj["val"];
|
||||||
}
|
// }
|
||||||
}
|
// }
|
||||||
#endif /*defined(ZEROEXPORT_POWERMETER_MQTT)*/
|
#endif /*defined(ZEROEXPORT_POWERMETER_MQTT)*/
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
/** mqttSubscribe
|
||||||
|
* when a MQTT Msg is needed to subscribe, then a publish is leading
|
||||||
|
* @param gr
|
||||||
|
* @param payload
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
|
void mqttSubscribe(String gr, String payload) {
|
||||||
|
// mqttPublish(gr, payload);
|
||||||
|
mMqtt->subscribe(gr.c_str(), QOS_2);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** mqttPublish
|
||||||
|
* when a MQTT Msg is needed to Publish, but not to subscribe.
|
||||||
|
* @param gr
|
||||||
|
* @param payload
|
||||||
|
* @param retain
|
||||||
|
* @returns void
|
||||||
|
*/
|
||||||
|
void mqttPublish(String gr, String payload, bool retain = false) {
|
||||||
|
mMqtt->publish(gr.c_str(), payload.c_str(), retain);
|
||||||
|
}
|
||||||
|
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
|
|
||||||
zeroExport_t *mCfg;
|
zeroExport_t *mCfg;
|
||||||
|
|
|
@ -239,35 +239,35 @@ class ZeroExport {
|
||||||
// Regelbegrenzung
|
// Regelbegrenzung
|
||||||
// TODO: Hier könnte man den maximalen Sprung begrenzen
|
// TODO: Hier könnte man den maximalen Sprung begrenzen
|
||||||
|
|
||||||
// Keine Regelung wenn Maximalleistung des Inverters unbekannt ist
|
|
||||||
if (CfgGroupInv->MaxPower == 0) {
|
|
||||||
y = 0;
|
|
||||||
mLog["yK"] = y;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stellgröße y in W
|
// Stellgröße y in W
|
||||||
CfgGroupInv->limitNew += y;
|
CfgGroupInv->limitNew += y;
|
||||||
|
|
||||||
// Check
|
// Check
|
||||||
|
|
||||||
if (CfgGroupInv->action == zeroExportAction_t::doNone) {
|
if (CfgGroupInv->action == zeroExportAction_t::doNone) {
|
||||||
// if ((CfgGroup->battSwitch == true) && (CfgGroupInv->limitNew > CfgGroupInv->powerMin) && (CfgGroupInv->power == 0) && (mCfg->sleep != true) && (CfgGroup->sleep != true)) {
|
if ((CfgGroup->battSwitch == true) && (CfgGroupInv->limitNew > CfgGroupInv->powerMin) && (CfgGroupInv->power == 0) && (mCfg->sleep != true) && (CfgGroup->sleep != true)) {
|
||||||
// TODO: Schlägt fehl, weil wenn MaxPower = 0 wird y auf 0 gesetzt und damit ist limitNew = powerMin
|
if (CfgGroupInv->actionTimer < 0) CfgGroupInv->actionTimer = 0;
|
||||||
if ((CfgGroup->battSwitch == true) && (CfgGroupInv->power == 0) && (mCfg->sleep != true) && (CfgGroup->sleep != true)) {
|
if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = 1;
|
||||||
CfgGroupInv->action = zeroExportAction_t::doTurnOn;
|
if (CfgGroupInv->actionTimer > 10) {
|
||||||
mLog["do"] = "doTurnOn";
|
CfgGroupInv->action = zeroExportAction_t::doTurnOn;
|
||||||
|
mLog["do"] = "doTurnOn";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
// TODO: hier kommt eine CheckBox je Gruppe rein, die es verhindert, dass Inv ausgeschaltet werden.
|
||||||
if (((CfgGroup->battSwitch == false) || (CfgGroupInv->limitNew < 0)) && (CfgGroupInv->power > 0)) {
|
if ((CfgGroupInv->limitNew <= 0) && (CfgGroupInv->power > 0)) {
|
||||||
CfgGroupInv->action = zeroExportAction_t::doTurnOff;
|
if (CfgGroupInv->actionTimer > 0) CfgGroupInv->actionTimer = 0;
|
||||||
mLog["do"] = "doTurnOff";
|
if (CfgGroupInv->actionTimer == 0) CfgGroupInv->actionTimer = -1;
|
||||||
|
if (CfgGroupInv->actionTimer < 30) {
|
||||||
|
CfgGroupInv->action = zeroExportAction_t::doTurnOff;
|
||||||
|
mLog["do"] = "doTurnOff";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
if (((CfgGroup->battSwitch == false) || (mCfg->sleep == true) || (CfgGroup->sleep == true)) && (CfgGroupInv->power > 0)) {
|
||||||
if (((mCfg->sleep == true) || (CfgGroup->sleep == true)) && (CfgGroupInv->power > 0)) {
|
|
||||||
CfgGroupInv->action = zeroExportAction_t::doTurnOff;
|
CfgGroupInv->action = zeroExportAction_t::doTurnOff;
|
||||||
mLog["do"] = "sleep";
|
mLog["do"] = "sleep";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
mLog["doT"] = CfgGroupInv->action;
|
||||||
|
|
||||||
if (CfgGroupInv->action == zeroExportAction_t::doNone) {
|
if (CfgGroupInv->action == zeroExportAction_t::doNone) {
|
||||||
mLog["l"] = CfgGroupInv->limit;
|
mLog["l"] = CfgGroupInv->limit;
|
||||||
|
@ -302,6 +302,16 @@ class ZeroExport {
|
||||||
|
|
||||||
if (CfgGroupInv->limit != CfgGroupInv->limitNew) CfgGroupInv->action = zeroExportAction_t::doActivePowerContr;
|
if (CfgGroupInv->limit != CfgGroupInv->limitNew) CfgGroupInv->action = zeroExportAction_t::doActivePowerContr;
|
||||||
|
|
||||||
|
if ((CfgGroupInv->limit == powerMin) && (CfgGroupInv->power == 0)) {
|
||||||
|
CfgGroupInv->action = zeroExportAction_t::doNone;
|
||||||
|
if (!mCfg->debug) {
|
||||||
|
clearLog();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// CfgGroupInv->actionTimer = 0;
|
||||||
|
// TODO: Timer stoppen wenn Limit gesetzt wird.
|
||||||
mLog["lN"] = CfgGroupInv->limitNew;
|
mLog["lN"] = CfgGroupInv->limitNew;
|
||||||
|
|
||||||
CfgGroupInv->limit = CfgGroupInv->limitNew;
|
CfgGroupInv->limit = CfgGroupInv->limitNew;
|
||||||
|
@ -316,6 +326,8 @@ class ZeroExport {
|
||||||
mApp->triggerTickSend(iv->id);
|
mApp->triggerTickSend(iv->id);
|
||||||
CfgGroupInv->waitAck = 120;
|
CfgGroupInv->waitAck = 120;
|
||||||
CfgGroupInv->action = zeroExportAction_t::doNone;
|
CfgGroupInv->action = zeroExportAction_t::doNone;
|
||||||
|
CfgGroupInv->actionTimer = 0;
|
||||||
|
CfgGroupInv->actionTimestamp = Tsp;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case zeroExportAction_t::doTurnOn:
|
case zeroExportAction_t::doTurnOn:
|
||||||
|
@ -323,6 +335,8 @@ class ZeroExport {
|
||||||
mApp->triggerTickSend(iv->id);
|
mApp->triggerTickSend(iv->id);
|
||||||
CfgGroupInv->waitAck = 120;
|
CfgGroupInv->waitAck = 120;
|
||||||
CfgGroupInv->action = zeroExportAction_t::doNone;
|
CfgGroupInv->action = zeroExportAction_t::doNone;
|
||||||
|
CfgGroupInv->actionTimer = 0;
|
||||||
|
CfgGroupInv->actionTimestamp = Tsp;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case zeroExportAction_t::doTurnOff:
|
case zeroExportAction_t::doTurnOff:
|
||||||
|
@ -330,20 +344,19 @@ class ZeroExport {
|
||||||
mApp->triggerTickSend(iv->id);
|
mApp->triggerTickSend(iv->id);
|
||||||
CfgGroupInv->waitAck = 120;
|
CfgGroupInv->waitAck = 120;
|
||||||
CfgGroupInv->action = zeroExportAction_t::doNone;
|
CfgGroupInv->action = zeroExportAction_t::doNone;
|
||||||
|
CfgGroupInv->actionTimer = 0;
|
||||||
|
CfgGroupInv->actionTimestamp = Tsp;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case zeroExportAction_t::doActivePowerContr:
|
case zeroExportAction_t::doActivePowerContr:
|
||||||
if ((CfgGroupInv->limit <= CfgGroupInv->powerMin) && (CfgGroupInv->power == 0)) {
|
|
||||||
clearLog();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
iv->powerLimit[0] = static_cast<uint16_t>(CfgGroupInv->limit * 10.0);
|
iv->powerLimit[0] = static_cast<uint16_t>(CfgGroupInv->limit * 10.0);
|
||||||
iv->powerLimit[1] = AbsolutNonPersistent;
|
iv->powerLimit[1] = AbsolutNonPersistent;
|
||||||
if (iv->setDevControlRequest(ActivePowerContr)) {
|
if (iv->setDevControlRequest(ActivePowerContr)) {
|
||||||
mApp->triggerTickSend(iv->id);
|
mApp->triggerTickSend(iv->id);
|
||||||
CfgGroupInv->waitAck = 60;
|
CfgGroupInv->waitAck = 60;
|
||||||
CfgGroupInv->action = zeroExportAction_t::doNone;
|
CfgGroupInv->action = zeroExportAction_t::doNone;
|
||||||
|
CfgGroupInv->actionTimer = 0;
|
||||||
|
CfgGroupInv->actionTimestamp = Tsp;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -382,6 +395,9 @@ class ZeroExport {
|
||||||
if (mCfg->groups[group].inverters[inv].waitAck > 0) {
|
if (mCfg->groups[group].inverters[inv].waitAck > 0) {
|
||||||
mCfg->groups[group].inverters[inv].waitAck--;
|
mCfg->groups[group].inverters[inv].waitAck--;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mCfg->groups[group].inverters[inv].actionTimer > 0) mCfg->groups[group].inverters[inv].actionTimer++;
|
||||||
|
if (mCfg->groups[group].inverters[inv].actionTimer < 0) mCfg->groups[group].inverters[inv].actionTimer--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -537,6 +553,28 @@ class ZeroExport {
|
||||||
|
|
||||||
CfgGroupInv->dcVoltage = iv->getChannelFieldValue(CH1, FLD_UDC, rec);
|
CfgGroupInv->dcVoltage = iv->getChannelFieldValue(CH1, FLD_UDC, rec);
|
||||||
mLog["bU"] = ah::round1(CfgGroupInv->dcVoltage);
|
mLog["bU"] = ah::round1(CfgGroupInv->dcVoltage);
|
||||||
|
|
||||||
|
// Fallschirm 2: Für nicht übernommene Limits bzw. nicht regelnde Inverter
|
||||||
|
// Bisher ist nicht geklärt ob der Inverter das Limit bestätigt hat
|
||||||
|
// Erstmalig aufgetreten bei @knickohr am 28.04.2024 ... l=300 pM=300, p=9
|
||||||
|
if (CfgGroupInv->MaxPower > 0) {
|
||||||
|
uint16_t limitPercent = 100 / CfgGroupInv->MaxPower * CfgGroupInv->limit;
|
||||||
|
uint16_t powerPercent = 100 / CfgGroupInv->MaxPower * CfgGroupInv->power;
|
||||||
|
uint16_t delta = abs(limitPercent - powerPercent);
|
||||||
|
if ((delta > 10) && (CfgGroupInv->power > 0)) {
|
||||||
|
mLog["delta"] = delta;
|
||||||
|
unsigned long delay = iv->getLastTs(rec) - CfgGroupInv->actionTimestamp;
|
||||||
|
mLog["delay"] = delay;
|
||||||
|
if (delay > 30000) {
|
||||||
|
CfgGroupInv->action = zeroExportAction_t::doActivePowerContr;
|
||||||
|
mLog["do"] = "doActivePowerContr";
|
||||||
|
}
|
||||||
|
if (delay > 60000) {
|
||||||
|
CfgGroupInv->action = zeroExportAction_t::doRestart;
|
||||||
|
mLog["do"] = "doRestart";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
zeroExportQueue_t Entry;
|
zeroExportQueue_t Entry;
|
||||||
|
@ -560,6 +598,12 @@ class ZeroExport {
|
||||||
*/
|
*/
|
||||||
void onMqttConnect(void) {
|
void onMqttConnect(void) {
|
||||||
mPowermeter.onMqttConnect();
|
mPowermeter.onMqttConnect();
|
||||||
|
|
||||||
|
for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
|
||||||
|
// if (String(mCfg->groups[group].battSoC) == "") return;
|
||||||
|
|
||||||
|
mMqtt->subscribe(String(mCfg->groups[group].battSoC).c_str(), QOS_2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** onMqttMessage
|
/** onMqttMessage
|
||||||
|
@ -570,6 +614,9 @@ class ZeroExport {
|
||||||
void onMqttMessage(JsonObject obj) {
|
void onMqttMessage(JsonObject obj) {
|
||||||
if (!mIsInitialized) return;
|
if (!mIsInitialized) return;
|
||||||
|
|
||||||
|
if (mCfg->debug) mLog["d"] = obj;
|
||||||
|
sendLog();
|
||||||
|
clearLog();
|
||||||
mPowermeter.onMqttMessage(obj);
|
mPowermeter.onMqttMessage(obj);
|
||||||
|
|
||||||
String topic = String(obj["topic"]);
|
String topic = String(obj["topic"]);
|
||||||
|
|
Loading…
Add table
Reference in a new issue