Browse Source

0.8.1030011

pull/1615/head
Patrick Amrhein 9 months ago
parent
commit
e25045dbd9
  1. 50
      src/config/settings.h
  2. 2
      src/defines.h
  3. 135
      src/plugins/zeroExport/zeroExport.h
  4. 16
      src/web/RestApi.h
  5. 50
      src/web/html/setup.html
  6. 24
      src/web/lang.json

50
src/config/settings.h

@ -210,7 +210,7 @@ typedef struct {
#define ZEROEXPORT_GROUP_MAX_LEN_PM_JSONPATH 100
#define ZEROEXPORT_GROUP_MAX_LEN_PM_USER 25
#define ZEROEXPORT_GROUP_MAX_LEN_PM_PASS 25
#define ZEROEXPORT_GROUP_MAX_LEN_BATTERY_SOC 100
#define ZEROEXPORT_GROUP_MAX_LEN_BATT_TOPIC 100
#define ZEROEXPORT_GROUP_MAX_INVERTERS 3
#define ZEROEXPORT_POWERMETER_MAX_ERRORS 5
#define ZEROEXPORT_DEF_INV_WAITINGTIME_MS 10000
@ -242,6 +242,13 @@ typedef enum {
L3Sum = 6,
} zeroExportInverterTarget_t;
typedef enum {
none = 0,
invUdc,
mqttU,
mqttSoC
} zeroExportBatteryCfg;
typedef enum {
doNone = 0,
doRestart,
@ -293,10 +300,11 @@ typedef struct {
// Inverters
zeroExportGroupInverter_t inverters[ZEROEXPORT_GROUP_MAX_INVERTERS];
// Battery
bool battEnabled;
float battVoltageOn;
float battVoltageOff;
char battSoC[ZEROEXPORT_GROUP_MAX_LEN_BATTERY_SOC];
uint8_t battCfg;
char battTopic[ZEROEXPORT_GROUP_MAX_LEN_BATT_TOPIC];
float battValue;
float battLimitOn;
float battLimitOff;
// Advanced
int16_t setPoint;
bool minimum;
@ -696,10 +704,10 @@ class settings {
mCfg.plugin.zeroExport.groups[group].inverters[inv].limitNew = 0;
}
// Battery
mCfg.plugin.zeroExport.groups[group].battEnabled = false;
mCfg.plugin.zeroExport.groups[group].battVoltageOn = 0;
mCfg.plugin.zeroExport.groups[group].battVoltageOff = 0;
snprintf(mCfg.plugin.zeroExport.groups[group].battSoC, ZEROEXPORT_GROUP_MAX_LEN_BATTERY_SOC, "%s", DEF_ZEXPORT);
mCfg.plugin.zeroExport.groups[group].battCfg = zeroExportBatteryCfg::none;
snprintf(mCfg.plugin.zeroExport.groups[group].battTopic, ZEROEXPORT_GROUP_MAX_LEN_BATT_TOPIC, "%s", DEF_ZEXPORT);
mCfg.plugin.zeroExport.groups[group].battLimitOn = 0;
mCfg.plugin.zeroExport.groups[group].battLimitOff = 0;
// Advanced
mCfg.plugin.zeroExport.groups[group].setPoint = 0;
mCfg.plugin.zeroExport.groups[group].minimum = true;
@ -1047,10 +1055,10 @@ class settings {
jsonZeroExportGroupInverter(invArr.createNestedObject(), group, inv, set);
}
// Battery
obj[F("battEnabled")] = mCfg.plugin.zeroExport.groups[group].battEnabled;
obj[F("battVoltageOn")] = mCfg.plugin.zeroExport.groups[group].battVoltageOn;
obj[F("battVoltageOff")] = mCfg.plugin.zeroExport.groups[group].battVoltageOff;
obj[F("battSoC")] = mCfg.plugin.zeroExport.groups[group].battSoC;
obj[F("battCfg")] = mCfg.plugin.zeroExport.groups[group].battCfg;
obj[F("battTopic")] = mCfg.plugin.zeroExport.groups[group].battTopic;
obj[F("battLimitOn")] = mCfg.plugin.zeroExport.groups[group].battLimitOn;
obj[F("battLimitOff")] = mCfg.plugin.zeroExport.groups[group].battLimitOff;
// Advanced
obj[F("setPoint")] = mCfg.plugin.zeroExport.groups[group].setPoint;
obj[F("minimum")] = mCfg.plugin.zeroExport.groups[group].minimum;
@ -1085,14 +1093,14 @@ class settings {
}
}
// Battery
if (obj.containsKey(F("battEnabled")))
getVal<bool>(obj, F("battEnabled"), &mCfg.plugin.zeroExport.groups[group].battEnabled);
if (obj.containsKey(F("battVoltageOn")))
getVal<float>(obj, F("battVoltageOn"), &mCfg.plugin.zeroExport.groups[group].battVoltageOn);
if (obj.containsKey(F("battVoltageOff")))
getVal<float>(obj, F("battVoltageOff"), &mCfg.plugin.zeroExport.groups[group].battVoltageOff);
if (obj.containsKey(F("battSoC")))
getChar(obj, F("battSoC"), mCfg.plugin.zeroExport.groups[group].battSoC, ZEROEXPORT_GROUP_MAX_LEN_BATTERY_SOC);
if (obj.containsKey(F("battCfg")))
getVal<uint8_t>(obj, F("battCfg"), &mCfg.plugin.zeroExport.groups[group].battCfg);
if (obj.containsKey(F("battTopic")))
getChar(obj, F("battTopic"), mCfg.plugin.zeroExport.groups[group].battTopic, ZEROEXPORT_GROUP_MAX_LEN_BATT_TOPIC);
if (obj.containsKey(F("battLimitOn")))
getVal<float>(obj, F("battLimitOn"), &mCfg.plugin.zeroExport.groups[group].battLimitOn);
if (obj.containsKey(F("battLimitOff")))
getVal<float>(obj, F("battLimitOff"), &mCfg.plugin.zeroExport.groups[group].battLimitOff);
// Advanced
if (obj.containsKey(F("setPoint")))
getVal<int16_t>(obj, F("setPoint"), &mCfg.plugin.zeroExport.groups[group].setPoint);

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 8
#define VERSION_PATCH 1030010
#define VERSION_PATCH 1030011
//-------------------------------------
typedef struct {
uint8_t ch;

135
src/plugins/zeroExport/zeroExport.h

@ -121,29 +121,40 @@ class ZeroExport {
mLog["gL"] = groupLimit;
// Batteryprotection
mLog["bEn"] = CfgGroup->battEnabled;
if (CfgGroup->battEnabled) {
mLog["bEn"] = (uint8_t)CfgGroup->battCfg;
switch (CfgGroup->battCfg) {
case zeroExportBatteryCfg::none:
if (CfgGroup->battSwitch != true) {
if (CfgGroupInv->dcVoltage > CfgGroup->battVoltageOn) {
CfgGroup->battSwitch = true;
mLog["bA"] = "turn on";
}
if ((CfgGroupInv->dcVoltage > CfgGroup->battVoltageOff) && (CfgGroupInv->power > 0)) {
break;
case zeroExportBatteryCfg::invUdc:
case zeroExportBatteryCfg::mqttU:
case zeroExportBatteryCfg::mqttSoC:
if (CfgGroup->battSwitch != true) {
if (CfgGroup->battValue > CfgGroup->battLimitOn) {
CfgGroup->battSwitch = true;
mLog["bA"] = "turn on";
}
if ((CfgGroup->battValue > CfgGroup->battLimitOff) && (CfgGroupInv->power > 0)) {
CfgGroup->battSwitch = true;
mLog["bA"] = "turn on";
}
} else {
if (CfgGroupInv->dcVoltage < CfgGroup->battVoltageOff) {
if (CfgGroup->battValue < CfgGroup->battLimitOff) {
CfgGroup->battSwitch = false;
mLog["bA"] = "turn off";
}
}
mLog["bU"] = ah::round1(CfgGroupInv->dcVoltage);
} else {
if (CfgGroup->battSwitch != true) {
CfgGroup->battSwitch = true;
mLog["bA"] = "turn on";
mLog["bU"] = ah::round1(CfgGroup->battValue);
break;
default:
if (CfgGroup->battSwitch == true) {
CfgGroup->battSwitch = false;
mLog["bA"] = "turn off";
}
break;
}
mLog["bSw"] = CfgGroup->battSwitch;
@ -309,8 +320,8 @@ class ZeroExport {
}
}
// CfgGroupInv->actionTimer = 0;
// TODO: Timer stoppen wenn Limit gesetzt wird.
// CfgGroupInv->actionTimer = 0;
// TODO: Timer stoppen wenn Limit gesetzt wird.
mLog["lN"] = CfgGroupInv->limitNew;
CfgGroupInv->limit = CfgGroupInv->limitNew;
@ -553,14 +564,24 @@ class ZeroExport {
CfgGroupInv->dcVoltage = iv->getChannelFieldValue(CH1, FLD_UDC, rec);
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)) {
// Batterieüberwachung - Überwachung über die DC-Spannung am PV-Eingang 1 des Inverters
if (CfgGroup->battCfg == zeroExportBatteryCfg::invUdc) {
if ((CfgGroup->battSwitch == false) && (CfgGroup->battValue < CfgGroupInv->dcVoltage)) {
CfgGroup->battValue = CfgGroupInv->dcVoltage;
}
if ((CfgGroup->battSwitch == true) && (CfgGroup->battValue > CfgGroupInv->dcVoltage)) {
CfgGroup->battValue = 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;
@ -572,8 +593,8 @@ if ((delta > 10) && (CfgGroupInv->power > 0)) {
CfgGroupInv->action = zeroExportAction_t::doRestart;
mLog["do"] = "doRestart";
}
}
}
}
}
}
zeroExportQueue_t Entry;
@ -600,12 +621,15 @@ if ((delta > 10) && (CfgGroupInv->power > 0)) {
mPowermeter.onMqttConnect();
// "topic":"userdefined battSoCTopic"
for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
if (!mCfg->groups [group].enabled) continue;
if (!mCfg->groups[group].enabled) continue;
if(!strcmp(mCfg->groups[group].battSoC, "")) continue;
if ((!mCfg->groups[group].battCfg == zeroExportBatteryCfg::mqttU) && (!mCfg->groups[group].battCfg == zeroExportBatteryCfg::mqttSoC)) continue;
mMqtt->subscribeExtern(String(mCfg->groups[group].battSoC).c_str(), QOS_2);
if (!strcmp(mCfg->groups[group].battTopic, "")) continue;
mMqtt->subscribeExtern(String(mCfg->groups[group].battTopic).c_str(), QOS_2);
}
}
@ -621,13 +645,22 @@ if ((delta > 10) && (CfgGroupInv->power > 0)) {
String topic = String(obj["topic"]);
/// TODO: Receive Message für SoC
// if ((topicGroup >= 0) && (topicGroup < ZEROEXPORT_MAX_GROUPS)) {
// if (topic.indexOf("xxx") != -1) {
// "topic":"userdefined battSoCTopic"
for (uint8_t group = 0; group < ZEROEXPORT_MAX_GROUPS; group++) {
if (!mCfg->groups[group].enabled) continue;
if ((!mCfg->groups[group].battCfg == zeroExportBatteryCfg::mqttU) && (!mCfg->groups[group].battCfg == zeroExportBatteryCfg::mqttSoC)) continue;
// }
// }
if (!strcmp(mCfg->groups[group].battTopic, "")) continue;
if (strcmp(mCfg->groups[group].battTopic, String(topic).c_str())) {
mCfg->groups[group].battValue = (bool)obj["val"];
mLog["k"] = mCfg->groups[group].battTopic;
mLog["v"] = mCfg->groups[group].battValue;
}
}
// "topic":"ctrl/zero"
if (topic.indexOf("ctrl/zero") == -1) return;
if (mCfg->debug) mLog["d"] = obj;
@ -669,27 +702,27 @@ if ((delta > 10) && (CfgGroupInv->power > 0)) {
mLog["v"] = mCfg->groups[topicGroup].sleep;
}
// Auf Eis gelegt, dafür 2 Gruppen mehr
// 0.8.103008.2
// // "topic":"ctrl/zero/groups/+/pm_ip"
// if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/pm_ip") != -1) {
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", obj[F("val")].as<const char *>());
/// TODO:
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", obj[F("val")].as<const char *>());
// strncpy(mCfg->groups[topicGroup].pm_url, obj[F("val")], ZEROEXPORT_GROUP_MAX_LEN_PM_URL);
// strncpy(mCfg->groups[topicGroup].pm_url, String(obj[F("val")]).c_str(), ZEROEXPORT_GROUP_MAX_LEN_PM_URL);
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", String(obj[F("val")]).c_str());
// mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/pm_ip";
// mLog["v"] = mCfg->groups[topicGroup].pm_url;
// }
//
// // "topic":"ctrl/zero/groups/+/pm_jsonPath"
// if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/pm_jsonPath") != -1) {
/// TODO:
// snprintf(mCfg->groups[topicGroup].pm_jsonPath, ZEROEXPORT_GROUP_MAX_LEN_PM_JSONPATH, "%s", obj[F("val")].as<const char *>());
// mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/pm_jsonPath";
// mLog["v"] = mCfg->groups[topicGroup].pm_jsonPath;
// }
// Auf Eis gelegt, dafür 2 Gruppen mehr
// 0.8.103008.2
// // "topic":"ctrl/zero/groups/+/pm_ip"
// if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/pm_ip") != -1) {
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", obj[F("val")].as<const char *>());
/// TODO:
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", obj[F("val")].as<const char *>());
// strncpy(mCfg->groups[topicGroup].pm_url, obj[F("val")], ZEROEXPORT_GROUP_MAX_LEN_PM_URL);
// strncpy(mCfg->groups[topicGroup].pm_url, String(obj[F("val")]).c_str(), ZEROEXPORT_GROUP_MAX_LEN_PM_URL);
// snprintf(mCfg->groups[topicGroup].pm_url, ZEROEXPORT_GROUP_MAX_LEN_PM_URL, "%s", String(obj[F("val")]).c_str());
// mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/pm_ip";
// mLog["v"] = mCfg->groups[topicGroup].pm_url;
// }
//
// // "topic":"ctrl/zero/groups/+/pm_jsonPath"
// if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/pm_jsonPath") != -1) {
/// TODO:
// snprintf(mCfg->groups[topicGroup].pm_jsonPath, ZEROEXPORT_GROUP_MAX_LEN_PM_JSONPATH, "%s", obj[F("val")].as<const char *>());
// mLog["k"] = "ctrl/zero/groups/" + String(topicGroup) + "/pm_jsonPath";
// mLog["v"] = mCfg->groups[topicGroup].pm_jsonPath;
// }
// "topic":"ctrl/zero/groups/+/battery/switch"
if (topic.indexOf("ctrl/zero/groups/" + String(topicGroup) + "/battery/switch") != -1) {

16
src/web/RestApi.h

@ -856,10 +856,10 @@ class RestApi {
objGroupInv[F("turnOff")] = (uint16_t)mConfig->plugin.zeroExport.groups[group].inverters[inv].turnOff;
}
// Battery
objGroup[F("battEnabled")] = (bool)mConfig->plugin.zeroExport.groups[group].battEnabled;
objGroup[F("battVoltageOn")] = ah::round1((float)mConfig->plugin.zeroExport.groups[group].battVoltageOn);
objGroup[F("battVoltageOff")] = ah::round1((float)mConfig->plugin.zeroExport.groups[group].battVoltageOff);
objGroup[F("battSoC")] = String(mConfig->plugin.zeroExport.groups[group].battSoC);
objGroup[F("battCfg")] = (uint8_t)mConfig->plugin.zeroExport.groups[group].battCfg;
objGroup[F("battTopic")] = String(mConfig->plugin.zeroExport.groups[group].battTopic);
objGroup[F("battLimitOn")] = ah::round1((float)mConfig->plugin.zeroExport.groups[group].battLimitOn);
objGroup[F("battLimitOff")] = ah::round1((float)mConfig->plugin.zeroExport.groups[group].battLimitOff);
// Advanced
objGroup[F("setPoint")] = (int16_t)mConfig->plugin.zeroExport.groups[group].setPoint;
objGroup[F("minimum")] = (bool)mConfig->plugin.zeroExport.groups[group].minimum;
@ -1173,10 +1173,10 @@ class RestApi {
mConfig->plugin.zeroExport.groups[group].inverters[inv].turnOff = jsonIn[F("inverters")][inv][F("turnOff")];
}
// Battery
mConfig->plugin.zeroExport.groups[group].battEnabled = jsonIn[F("battEnabled")];
mConfig->plugin.zeroExport.groups[group].battVoltageOn = jsonIn[F("battVoltageOn")];
mConfig->plugin.zeroExport.groups[group].battVoltageOff = jsonIn[F("battVoltageOff")];
snprintf(mConfig->plugin.zeroExport.groups[group].battSoC, ZEROEXPORT_GROUP_MAX_LEN_BATTERY_SOC, "%s", jsonIn[F("battSoC")].as<const char*>());
mConfig->plugin.zeroExport.groups[group].battCfg = jsonIn[F("battCfg")];
snprintf(mConfig->plugin.zeroExport.groups[group].battTopic, ZEROEXPORT_GROUP_MAX_LEN_BATT_TOPIC, "%s", jsonIn[F("battTopic")].as<const char*>());
mConfig->plugin.zeroExport.groups[group].battLimitOn = jsonIn[F("battLimitOn")];
mConfig->plugin.zeroExport.groups[group].battLimitOff = jsonIn[F("battLimitOff")];
// Advanced
mConfig->plugin.zeroExport.groups[group].setPoint = jsonIn[F("setPoint")];
mConfig->plugin.zeroExport.groups[group].minimum = jsonIn[F("minimum")];

50
src/web/html/setup.html

@ -1364,8 +1364,6 @@
}
// Tab_Battery
var cb_battEnabled = ml("input", {name: "battEnabled", type: "checkbox"}, null);
cb_battEnabled.checked = (obj.battEnabled);
// Tab_Advanced
var cb_minimum = ml("input", {name: "minimum", type: "checkbox"}, null);
@ -1432,10 +1430,18 @@
]),
// Battery
ml("div", {id: "div{#ZE_GROUP_TAB_BATTERY}", class: "tab-content hide"}, [
divRow("{#ZE_GROUP_TAB_BATTERY_ENABLED}", cb_battEnabled),
divRow("{#ZE_GROUP_TAB_BATTERY_VOLTAGEON}", ml("input", {name: "battVoltageOn", class: "text", type: "number", min: "0", max: "100", step: "0.1", value: obj.battVoltageOn}, null)),
divRow("{#ZE_GROUP_TAB_BATTERY_VOLTAGEOFF}", ml("input", {name: "battVoltageOff", class: "text", type: "number", min: "0", max: "100", step: "0.1", value: obj.battVoltageOff}, null)),
divRow("{#ZE_GROUP_TAB_BATTERY_SOC}", ml("input", {name: "battSoC", class: "text", type: "text", value: obj.battSoC}, null)),
divRow("{#ZE_GROUP_TAB_BATTERY_CFG}",
ml("select", {name: "battCfg", class: "text", id: "battCfg"}, null),
),
divRow("{#ZE_GROUP_TAB_BATTERY_TOPIC}",
ml("input", {name: "battTopic", class: "text", type: "text", value: obj.battTopic}, null),
),
divRow("{#ZE_GROUP_TAB_BATTERY_LIMITON}",
ml("input", {name: "battLimitOn", class: "text", type: "number", min: "0", max: "100", step: "0.1", value: obj.battLimitOn}, null),
),
divRow("{#ZE_GROUP_TAB_BATTERY_LIMITOFF}",
ml("input", {name: "battLimitOff", class: "text", type: "number", min: "0", max: "100", step: "0.1", value: obj.battLimitOff}, null),
),
divRow("{#ZE_GROUP_TAB_BATTERY_ONOFF}", ml("input", {name: "battSwitch", id: "battSwitch", class: "btn", type: "button", value: "{#BTN_ONOFF}", onclick: battOnOff()}, null)),
// TODO: Uebersetzen mit lang.json und auf die entsprechende Dokuseite verlinken
divRow("Hinweis: ",
@ -1546,6 +1552,21 @@
e.checked = (obj.inverters[inv].turnOff);
}
// Tab_Battery
// battCfg
var e = document.getElementById("battCfg");
selDelAllOpt(e);
// TODO: uebersetzen?
e.appendChild(opt("0", "---"));
e.appendChild(opt("1", "Inverter U dc"));
e.appendChild(opt("2", "MQTT U"));
e.appendChild(opt("3", "MQTT Soc"));
for (var i = 0; i < e.options.length; i++) {
if (e.options[i].value == obj.battCfg) {
e.selectedIndex = i;
}
}
function save() {
var o = new Object();
o.cmd = "ze_save_group"
@ -1578,10 +1599,11 @@
o.inverters.push(q);
}
// Battery
o.battEnabled = document.getElementsByName("battEnabled")[0].checked;
o.battVoltageOn = document.getElementsByName("battVoltageOn")[0].value;
o.battVoltageOff = document.getElementsByName("battVoltageOff")[0].value;
o.battSoC = document.getElementsByName("battSoC")[0].value;
var e = document.getElementsByName("battCfg")[0];
o.battCfg = e.options[e.selectedIndex].value;
o.battTopic = document.getElementsByName("battTopic")[0].value;
o.battLimitOn = document.getElementsByName("battLimitOn")[0].value;
o.battLimitOff = document.getElementsByName("battLimitOff")[0].value;
// Advanced
o.setPoint = document.getElementsByName("setPoint")[0].value;
o.minimum = document.getElementsByName("minimum")[0].checked;
@ -1644,10 +1666,10 @@
o.inverters.push(q);
}
// Battery
o.battEnabled = false;
o.battVoltageOn = 0;
o.battVoltageOff = 0;
o.battSoC = "";
o.battCfg = 0;
o.battTopic = "";
o.battLimitOn = 0;
o.battLimitOff = 0;
// Advanced
o.setPoint = 0;
o.minimum = true;

24
src/web/lang.json

@ -954,24 +954,24 @@
"de": "Batterie"
},
{
"token": "ZE_GROUP_TAB_BATTERY_ENABLED",
"en": "Enabled:",
"de": "Aktiviert:"
"token": "ZE_GROUP_TAB_BATTERY_CFG",
"en": "Mode:",
"de": "Modus:"
},
{
"token": "ZE_GROUP_TAB_BATTERY_VOLTAGEON",
"en": "Voltage on (Volt):",
"de": "Spannung Ein (Volt):"
"token": "ZE_GROUP_TAB_BATTERY_TOPIC",
"en": "Topic:",
"de": "Topic:"
},
{
"token": "ZE_GROUP_TAB_BATTERY_VOLTAGEOFF",
"en": "Voltage off (Volt):",
"de": "Spannung Aus (Volt):"
"token": "ZE_GROUP_TAB_BATTERY_LIMITON",
"en": "Limit On:",
"de": "Limit Ein:"
},
{
"token": "ZE_GROUP_TAB_BATTERY_SOC",
"en": "SoC % (MQTT Topic):",
"de": "SoC (MQTT Topic):"
"token": "ZE_GROUP_TAB_BATTERY_LIMITOFF",
"en": "Limit Off:",
"de": "Limit Aus:"
},
{
"token": "ZE_GROUP_TAB_BATTERY_ONOFF",

Loading…
Cancel
Save