Browse Source

0.8.850032-zero

pull/1474/head
Patrick Amrhein 1 year ago
parent
commit
fa94909d05
  1. 9
      src/app.cpp
  2. 18
      src/config/settings.h
  3. 2
      src/defines.h
  4. 251
      src/plugins/zeroExport/zeroExport.h
  5. 86
      src/web/html/setup.html

9
src/app.cpp

@ -172,6 +172,15 @@ void app::loop(void) {
if (mMqttEnabled && mNetworkConnected)
mMqtt.loop();
#endif
// Plugin ZeroExport
#if defined(PLUGIN_ZEROEXPORT)
if(mConfig->nrf.enabled || mConfig->cmt.enabled) {
mZeroExport.loop();
}
#endif
// Plugin ZeroExport - Ende
yield();
}

18
src/config/settings.h

@ -198,6 +198,10 @@ typedef struct {
#define ZEROEXPORT_DEF_INV_WAITINGTIME_MS 10000
#if defined(PLUGIN_ZEROEXPORT)
enum class zeroExportState : uint8_t {
RESET, GETPOWERMETER, GETINVERTERPOWER, FINISH
};
typedef enum {
None = 0,
Shelly = 1,
@ -268,7 +272,12 @@ typedef struct {
uint16_t powerMax;
uint16_t startTimestamp;
zeroExportState state;
unsigned long lastRun;
float pmPower;
float pmPowerL1;
float pmPowerL2;
float pmPowerL3;
// uint16_t power; // Aktueller Verbrauch
// uint16_t powerLimitAkt; // Aktuelles Limit
// uint16_t powerHyst; // Hysterese
@ -629,6 +638,13 @@ class settings {
mCfg.plugin.zeroExport.groups[group].refresh = 10;
mCfg.plugin.zeroExport.groups[group].powerTolerance = 10;
mCfg.plugin.zeroExport.groups[group].powerMax = 600;
//
mCfg.plugin.zeroExport.groups[group].state = zeroExportState::RESET;
mCfg.plugin.zeroExport.groups[group].lastRun = 0;
mCfg.plugin.zeroExport.groups[group].pmPower = 0;
mCfg.plugin.zeroExport.groups[group].pmPowerL1 = 0;
mCfg.plugin.zeroExport.groups[group].pmPowerL2 = 0;
mCfg.plugin.zeroExport.groups[group].pmPowerL3 = 0;
}
#warning("Defaultsettings")

2
src/defines.h

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

251
src/plugins/zeroExport/zeroExport.h

@ -57,19 +57,71 @@ class ZeroExport {
continue;
}
// if (millis() - mCfg->groups[group].startTimestamp < mCfg->groups[group].refresh) {
// mCfg->groups[group].startTimestamp = mCfg->groups[group].startTimestamp + mCfg->groups[group].refresh;
switch (mCfg->groups[group].state) {
case zeroExportState::RESET:
//DBGPRINT(F("State::RESET: "));
//DBGPRINTLN(String(group));
mCfg->groups[group].lastRun = millis();
// Weiter zum nächsten State
mCfg->groups[group].state = zeroExportState::GETPOWERMETER;
break;
case zeroExportState::GETPOWERMETER:
if ((millis() - mCfg->groups[group].lastRun) > (mCfg->groups[group].refresh * 1000UL)) {
//DBGPRINT(F("State::GETPOWERMETER:"));
//DBGPRINTLN(String(group));
if (getPowermeterWatts(group)) {
// Weiter zum nächsten State
mCfg->groups[group].state = zeroExportState::GETINVERTERPOWER;
} else {
// Wartezeit wenn Keine Daten vom Powermeter
mCfg->groups[group].lastRun = (millis() - (mCfg->groups[group].refresh * 100UL));
}
}
break;
case zeroExportState::GETINVERTERPOWER:
if ((millis() - mCfg->groups[group].lastRun) > (mCfg->groups[group].refresh * 1000UL)) {
//DBGPRINT(F("State::GETINVERTERPOWER:"));
//DBGPRINTLN(String(group));
if (getInverterPowerWatts(group)) {
// Weiter zum nächsten State
mCfg->groups[group].state = zeroExportState::FINISH;
} else {
// Wartezeit wenn Keine Daten vom Powermeter
mCfg->groups[group].lastRun = (millis() - (mCfg->groups[group].refresh * 100UL));
}
}
break;
/*
if (getPowermeterWatts(group)) {
mCfg->groups[group].powermeter.nextRun = millis() + mCfg->groups[group].powermeter.interval;
mCfg->groups[group].powermeter.error = 0;
DBGPRINTLN(String("Powermeter: ") + String(mCfg->groups[group].powermeter.power) + String(" W"));
} else {
mCfg->groups[group].powermeter.error++;
continue;
}
case 4:
//
mCfg->groups[group].state = zeroExportState::RESET;
break;
case 5:
//
mCfg->groups[group].state = zeroExportState::RESET;
break;
*/
// }
default:
//
//DBGPRINT(F("State::?: "));
//DBGPRINTLN(String(group));
mCfg->groups[group].state = zeroExportState::RESET;
break;
}
/*
if (!mCfg->groups[group].powermeter.error) {
DBGPRINTLN(String("ok verarbeiten."));
@ -270,65 +322,149 @@ DBGPRINTLN(String("nok Notmodus."));
bool getPowermeterWatts(uint8_t group) {
bool ret = false;
// switch (mCfg->groups[group].powermeter.type) {
// case 1:
// ret = getPowermeterWattsTibber();
// break;
DBGPRINT(String("getPowermeterWatts: "));
DBGPRINTLN(String(group));
switch (mCfg->groups[group].pm_type) {
case 1:
ret = getPowermeterWattsShelly(group);
break;
// case 2:
// ret = getPowermeterWattsShelly();
// ret = getPowermeterWattsTasmota(group);
// break;
// case 3:
// ret = getPowermeterWattsTasmota();
// ret = getPowermeterWattsMqtt(group);
// break;
// case 4:
// ret = getPowermeterWattsMqtt();
// ret = getPowermeterWattsHichi(group);
// break;
// case 5:
// ret = getPowermeterWattsTibber(group);
// break;
/// default:
/// ret = false;
/// break;
// }
}
return ret;
}
int getPowermeterWattsTibber(void) {
// TODO:
return 0;
}
int getPowermeterWattsShelly(void) {
/*
int getPowermeterWattsShelly(uint8_t group) {
bool ret = false;
HTTPClient http;
char url[100] = "http://";
strcat(url, mCfg->monitor_url);
strcat(url, "/status");
http.begin(url);
if (http.GET() == 200)
// httpClient.setFollowRedirects(HTTPC_STRICT_FOLLOW_REDIRECTS);
httpClient.setUserAgent("Ahoy-Agent");
// TODO: Ahoy-0.8.850024-zero
// httpClient.setConnectTimeout(1000);
// httpClient.setTimeout(1000);
// httpClient.addHeader("Content-Type", "application/json");
// httpClient.addHeader("Accept", "application/json");
http.begin(mCfg->groups[group].pm_url);
if (http.GET() == HTTP_CODE_OK)
{
// Parsing
DynamicJsonDocument doc(2048);
DeserializationError error = deserializeJson(doc, http.getString());
if (error)
{
Serial.print("deserializeJson() failed: ");
Serial.println(error.c_str());
return 0;
DBGPRINT(String("deserializeJson() failed: "));
DBGPRINTLN(String(error.c_str()));
return ret;
}
float total_power = doc["total_power"];
int Shelly_Power = (int)(total_power + .5);
return Shelly_Power;
*/
/*
String url = "http://" + String(SHELLY_IP) + "/status";
ParsedData = http.get(url).json();
int Watts = ParsedData['total_power'].toInt();
return Watts;
*/
// }
// http.end();
// Shelly 3EM
if (doc.containsKey(F("total_power"))) {
mCfg->groups[group].pmPower = doc["total_power"];
ret = true;
// Shelly pro 3EM
} else if (doc.containsKey(F("em:0"))) {
mCfg->groups[group].pmPower = doc["em:0"]["total_act_power"];
ret = true;
// Keine Daten
} else {
mCfg->groups[group].pmPower = 0;
}
return 0;
// Shelly 3EM
if (doc.containsKey(F("emeters"))) {
mCfg->groups[group].pmPowerL1 = doc["emeters"][0]["power"];
ret = true;
// Shelly pro 3EM
} else if (doc.containsKey(F("em:0"))) {
mCfg->groups[group].pmPowerL1 = doc["em:0"]["a_act_power"];
ret = true;
// Shelly plus1pm plus2pm
} else if (doc.containsKey(F("switch:0"))) {
mCfg->groups[group].pmPowerL1 = doc["switch:0"]["apower"];
mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL1;
ret = true;
// Shelly Alternative
} else if (doc.containsKey(F("apower"))) {
mCfg->groups[group].pmPowerL1 = doc["apower"];
mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL1;
ret = true;
// Keine Daten
} else {
mCfg->groups[group].pmPowerL1 = 0;
}
DBGPRINT(String("pmPowerL1: "));
DBGPRINTLN(String(mCfg->groups[group].pmPowerL1));
// Shelly 3EM
if (doc.containsKey(F("emeters"))) {
mCfg->groups[group].pmPowerL2 = doc["emeters"][1]["power"];
ret = true;
// Shelly pro 3EM
} else if (doc.containsKey(F("em:0"))) {
mCfg->groups[group].pmPowerL2 = doc["em:0"]["b_act_power"];
ret = true;
// Shelly plus1pm plus2pm
} else if (doc.containsKey(F("switch:1"))) {
mCfg->groups[group].pmPowerL2 = doc["switch.1"]["apower"];
mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL2;
ret = true;
// // Shelly Alternative
// } else if (doc.containsKey(F("apower"))) {
// mCfg->groups[group].pmPowerL2 = doc["apower"];
// mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL2;
// ret = true;
// Keine Daten
} else {
mCfg->groups[group].pmPowerL2 = 0;
}
DBGPRINT(String("pmPowerL2: "));
DBGPRINTLN(String(mCfg->groups[group].pmPowerL2));
// Shelly 3EM
if (doc.containsKey(F("emeters"))) {
mCfg->groups[group].pmPowerL3 = doc["emeters"][2]["power"];
ret = true;
// Shelly pro 3EM
} else if (doc.containsKey(F("em:0"))) {
mCfg->groups[group].pmPowerL3 = doc["em:0"]["c_act_power"];
ret = true;
// Shelly plus1pm plus2pm
} else if (doc.containsKey(F("switch:2"))) {
mCfg->groups[group].pmPowerL3 = doc["switch:2"]["apower"];
mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL3;
ret = true;
// // Shelly Alternative
// } else if (doc.containsKey(F("apower"))) {
// mCfg->groups[group].pmPowerL3 = doc["apower"];
// mCfg->groups[group].pmPower += mCfg->groups[group].pmPowerL3;
// ret = true;
// Keine Daten
} else {
mCfg->groups[group].pmPowerL3 = 0;
}
DBGPRINT(String("pmPowerL3: "));
DBGPRINTLN(String(mCfg->groups[group].pmPowerL3));
DBGPRINT(String("pmPower: "));
DBGPRINTLN(String(mCfg->groups[group].pmPower));
}
http.end();
return ret;
}
int getPowermeterWattsTasmota(void) {
@ -369,11 +505,30 @@ DBGPRINTLN(String("nok Notmodus."));
return 0;
}
int getPowermeterWattsHichi(void) {
// TODO:
return 0;
}
int getPowermeterWattsTibber(void) {
// TODO:
return 0;
}
bool getInverterPowerWatts(uint8_t group) {
bool ret = false;
DBGPRINT(String("getInverterPowerWatts: "));
DBGPRINTLN(String(group));
// switch (mCfg->groups[group].pm_type) {
return ret;
}

86
src/web/html/setup.html

@ -1249,14 +1249,20 @@
divRow("{#ZE_GROUP_TAB_POWERMETER_TYPE}",
ml("select", {name: "pm_type", class: "text", id: "pm_type"}, null),
),
divRow("{#ZE_GROUP_TAB_POWERMETER_URL}",
divRow("{#ZE_GROUP_TAB_POWERMETER_URL}", [
ml("input", {name: "pm_url", class: "text", type: "text", value: obj.pm_url, maxlength: "100"}, null),
ml("p", {}, "(3em) - http://IP/status"),
ml("p", {}, "(pro3em) - http://IP/rpc/Shelly.GetStatus"),
ml("p", {}, "(plus1pm) - http://IP/rpc/Shelly.GetStatus"),
ml("p", {}, "(plus2pm) - http://IP/rpc/Shelly.GetStatus"),
ml("p", {}, "(plus1pmAlternative) - http://IP/rpc/switch.GetStatus?id=0"),
ml("p", {}, "(plus2pmAlternative) - http://IP/rpc/switch.GetStatus?id=0"),
ml("p", {}, "A JSON-Format is required to work properly.<br>HICHI: http://IP_Address/cm?cmnd=status%208"),
),
divRow("{#ZE_GROUP_TAB_POWERMETER_JSONPATH}",
]),
divRow("{#ZE_GROUP_TAB_POWERMETER_JSONPATH}", [
ml("input", {name: "pm_jsonPath", class: "text", type: "text", value: obj.pm_jsonPath}, null),
ml("p", {}, "Only for HICHI needed!"),
),
]),
divRow("{#ZE_GROUP_TAB_POWERMETER_USER}",
ml("input", {name: "pm_user", class: "text", type: "text", value: obj.pm_user}, null),
),
@ -1299,7 +1305,6 @@
e.appendChild(opt("3", "Mqtt"));
e.appendChild(opt("4", "Hichi"));
e.appendChild(opt("5", "Tibber"));
//e.selectedIndex = obj.pm_type;
for (var i = 0; i < e.options.length; i++) {
if (e.options[i].value == obj.pm_type) {
e.selectedIndex = i;
@ -1317,11 +1322,9 @@
var e = document.getElementById("invId"+inv);
selDelAllOpt(e);
e.appendChild(opt("-1", "---"));
// TODO: Verhindert die Funktion des selects egal ob -1 oder "-1"
for (var i = 0; i < ivObj.inverter.length; i++) {
e.appendChild(opt((ivObj.inverter[i].id), (ivObj.inverter[i].name)));
}
//e.selectedIndex = (obj.inverters[inv].id);
for (var i = 0; i < (e.length); i++) {
if (e.options[i].value == obj.inverters[inv].id) {
e.selectedIndex = i;
@ -1340,7 +1343,6 @@
e.appendChild(opt("4", "L1 + Sum"));
e.appendChild(opt("5", "L2 + Sum"));
e.appendChild(opt("6", "L3 + Sum"));
//e.selectedIndex = (obj.inverters[inv].target);
for (var i = 0; i < e.options.length; i++) {
if (e.options[i].value == obj.inverters[inv].target) {
e.selectedIndex = i;
@ -1380,10 +1382,8 @@
for(var inv = 0; inv < o.invMax; inv++) {
var q = new Object();
q.enabled = document.getElementById("invEnabled"+inv).checked;
//q.id = document.getElementById("invId"+inv).selectedIndex+1;
var e = document.getElementById("invId"+inv);
q.id = e.options[e.selectedIndex].value;
//q.target = document.getElementById("invTarget"+inv).selectedIndex;
var e = document.getElementById("invTarget"+inv);
q.target = e.options[e.selectedIndex].value;
q.twoPercent = document.getElementById("invTwoPercent"+inv).checked;
@ -1422,6 +1422,7 @@
modal("{#ZE_GROUP_DELETE_MODAL}: " + obj.name, html);
function del() {
// TODO: Es wäre gut, wenn die Defaultwerte nicht hier sondern wie in der settings.h gesetzt würden.
var o = new Object();
o.cmd = "ze_save_group";
// General
@ -1435,20 +1436,27 @@
o.pm_user = "";
o.pm_pass = "";
// Inverters
// o.ser = 0;
// o.ch = [];
// for(let i = 0; i < 6; i++) {
// var q = new Object();
// q.pwr = 0;
// q.name = "";
// q.yld = 0;
// o.ch.push(q);
// }
o.invMax = obj.inverters.length;
o.inverters = [];
for(var inv = 0; inv < o.invMax; inv++) {
var q = new Object();
q.enabled = false;
var e = document.getElementById("invId"+inv);
q.id = -1;
var e = document.getElementById("invTarget"+inv);
q.target = -1;
q.twoPercent = false;
q.powerMax = 0;
o.inverters.push(q);
}
// Battery
o.battEnabled = false;
o.battVoltageOn = 0;
o.battVoltageOff = 0;
// Advanced
o.refresh = 10;
o.powerTolerance = 10;
o.powerMax = 600;
// TODO: Default aus Settings.h laden
// Global
getAjax("/api/setup", cb, "POST", JSON.stringify(o));
}
@ -1510,7 +1518,7 @@
]));
}
//#warning("groups")
// TODO: Das Add sollte anders / überhaupt gelöst werden
var add = new Object();
add.enabled = true;
add.id = obj.groups.length;
@ -1530,43 +1538,7 @@
// ivGlob(obj);
//#warning("groups")
// document.getElementsByName("en_zeroexport")[0].checked = obj["en_zeroexport"];
// document.getElementsByName("two_percent")[0].checked = obj["two_percent"];
// document.getElementsByName("query_device")[0].checked = (obj["query_device"] == 1);
// document.getElementsByName("query_device")[1].checked = (obj["query_device"] == 2);
// document.getElementsByName("query_device")[2].checked = (obj["query_device"] == 3);
// getAjax("/api/inverter/list", parseZeroExportIv);
// for(var i of [["monitor_url", "monitor_url"], ["power_avg", "power_avg"], ["count_avg", "count_avg"], ["json_path", "json_path"], ["max_power", "max_power"], ["query_device", "query_device"]])
// for(var i of [["monitor_url", "monitor_url"], ["power_avg", "power_avg"], ["count_avg", "count_avg"], ["json_path", "json_path"], ["max_power", "max_power"]])
// if(null != obj[i[1]])
// document.getElementsByName(i[0])[0].value = obj[i[1]];
// document.getElementsByName("total_power")[0].innerHTML = "Total: " + obj["total_power"].toFixed(2) + "W";
// document.getElementById("Inv_ID").selectedIndex = obj["Iv"];
}
/*
function parseZeroExportGroupInverterId(root) {
e = document.getElementById("");
selDelAllOpt(e);
for (it of root.inverter) {
e.appendChild(opt(it.id, it.name));
}
}
function parseZeroExportGroupIverterTarget(root) {
e = document.getElementById("");
selDelAllOpt(e);
for (it of root.inverter) {
e.appendChild(opt(it.id, it.name));
}
}
*/
// Plugin ZeroExport - Ende
/*ENDIF_PLUGIN_ZEROEXPORT*/

Loading…
Cancel
Save