Browse Source

Merge branch 'development03' of https://github.com/lumapu/ahoy into development03

pull/317/head
lumapu 2 years ago
parent
commit
6bf6e357ca
  1. 47
      tools/esp8266/app.cpp
  2. 5
      tools/esp8266/defines.h
  3. 2
      tools/esp8266/hmInverter.h
  4. 2
      tools/esp8266/html/index.html
  5. 83
      tools/esp8266/html/serial.html
  6. 13
      tools/esp8266/html/setup.html
  7. 3
      tools/esp8266/html/visualization.html
  8. 25
      tools/esp8266/web.cpp
  9. 9
      tools/esp8266/webApi.cpp

47
tools/esp8266/app.cpp

@ -125,31 +125,13 @@ void app::loop(void) {
mPayload[iv->id].txId = p->packet[0]; mPayload[iv->id].txId = p->packet[0];
DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received")); DPRINTLN(DBG_DEBUG, F("Response from devcontrol request received"));
iv->devControlRequest = false; iv->devControlRequest = false;
switch (p->packet[12]) { if (p->packet[12] == ActivePowerContr && p->packet[13] == 0x00) {
case ActivePowerContr: if (p->packet[10] == 0x00 && p->packet[11] == 0x00)
if (iv->devControlCmd >= ActivePowerContr && iv->devControlCmd <= PFSet) { // ok inverter accepted the set point copy it to dtu eeprom
if ((iv->powerLimit[1] & 0xff00) > 0) { // User want to have it persistent
mEep->write(ADDR_INV_PWR_LIM + iv->id * 2, iv->powerLimit[0]);
mEep->write(ADDR_INV_PWR_LIM_CON + iv->id * 2, iv->powerLimit[1]);
updateCrc();
mEep->commit();
DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]) + F(", written to dtu eeprom"));
} else
DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1])); DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]));
iv->devControlCmd = Init; else
} DPRINTLN(DBG_INFO, F("Inverter ") + String(iv->id) + F(" has NOT accepted power limit set point") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]));
break;
default:
if (iv->devControlCmd == ActivePowerContr) {
//case inverter did not accept the sent limit; set back to last stored limit
mEep->read(ADDR_INV_PWR_LIM + iv->id * 2, (uint16_t *)&(iv->powerLimit[0]));
mEep->read(ADDR_INV_PWR_LIM_CON + iv->id * 2, (uint16_t *)&(iv->powerLimit[1]));
DPRINTLN(DBG_INFO, F("Inverter has not accepted power limit set point"));
} }
iv->devControlCmd = Init; iv->devControlCmd = Init;
break;
}
} }
} }
} }
@ -258,7 +240,7 @@ void app::loop(void) {
DPRINTLN(DBG_DEBUG, F("app:loop WiFi WiFi.status ") + String(WiFi.status())); DPRINTLN(DBG_DEBUG, F("app:loop WiFi WiFi.status ") + String(WiFi.status()));
DPRINTLN(DBG_INFO, F("Requesting Inverter SN ") + String(iv->serial.u64, HEX)); DPRINTLN(DBG_INFO, F("Requesting Inverter SN ") + String(iv->serial.u64, HEX));
} }
if(iv->devControlRequest && ((iv->devControlCmd != ActivePowerContr) || ((iv->devControlCmd == ActivePowerContr) && (iv->powerLimit[0] > 0) && (iv->powerLimit[1] != NoPowerLimit)))) { // prevent to "switch off" if(iv->devControlRequest) {
if(mConfig.serialDebug) if(mConfig.serialDebug)
DPRINTLN(DBG_INFO, F("Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0])); DPRINTLN(DBG_INFO, F("Devcontrol request ") + String(iv->devControlCmd) + F(" power limit ") + String(iv->powerLimit[0]));
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit); mSys->Radio.sendControlPacket(iv->radioId.u64, iv->devControlCmd, iv->powerLimit);
@ -787,23 +769,6 @@ void app::loadEEpconfig(void) {
if(0ULL != invSerial) { if(0ULL != invSerial) {
iv = mSys->addInverter(name, invSerial, modPwr); iv = mSys->addInverter(name, invSerial, modPwr);
if(NULL != iv) { // will run once on every dtu boot if(NULL != iv) { // will run once on every dtu boot
mEep->read(ADDR_INV_PWR_LIM + (i * 2),(uint16_t *)&(iv->powerLimit[0]));
mEep->read(ADDR_INV_PWR_LIM_CON + (i * 2),(uint16_t *)&(iv->powerLimit[1]));
// only set it, if it is changed by user. Default value in the html setup page is -1 = 0xffff
// it is "doppelt-gemoppelt" because the inverter shall remember the setting if the dtu makes a power cycle / reboot
if (iv->powerLimit[0] != 0xffff) {
iv->devControlCmd = ActivePowerContr; // set active power limit
DPRINT(DBG_INFO, F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX));
if(iv->powerLimit[1] != NoPowerLimit) {
DBGPRINT(F(", Power Limit: ") + String(iv->powerLimit[0]));
if ((iv->powerLimit[1] & 0x0001) == 0x0001)
DBGPRINTLN(F(" in %"));
else
DBGPRINTLN(F(" in Watt"));
}
else
DBGPRINTLN(F(" "));
}
for(uint8_t j = 0; j < 4; j++) { for(uint8_t j = 0; j < 4; j++) {
mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, iv->chName[j], MAX_NAME_LENGTH); mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, iv->chName[j], MAX_NAME_LENGTH);
} }
@ -833,8 +798,6 @@ void app::saveValues(void) {
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
iv = mSys->getInverterByPos(i, false); iv = mSys->getInverterByPos(i, false);
mEep->write(ADDR_INV_ADDR + (i * 8), iv->serial.u64); mEep->write(ADDR_INV_ADDR + (i * 8), iv->serial.u64);
mEep->write(ADDR_INV_PWR_LIM + i * 2, iv->powerLimit[0]);
mEep->write(ADDR_INV_PWR_LIM_CON + i * 2, iv->powerLimit[1]);
mEep->write(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), iv->name, MAX_NAME_LENGTH); mEep->write(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), iv->name, MAX_NAME_LENGTH);
// max channel power / name // max channel power / name
for(uint8_t j = 0; j < 4; j++) { for(uint8_t j = 0; j < 4; j++) {

5
tools/esp8266/defines.h

@ -58,7 +58,6 @@ typedef enum {
} DevControlCmdType; } DevControlCmdType;
typedef enum { typedef enum {
NoPowerLimit = 0xffff, // ahoy internal value, no hoymiles value!
AbsolutNonPersistent = 0UL, // 0x0000 AbsolutNonPersistent = 0UL, // 0x0000
RelativNonPersistent = 1UL, // 0x0001 RelativNonPersistent = 1UL, // 0x0001
AbsolutPersistent = 256UL, // 0x0100 AbsolutPersistent = 256UL, // 0x0100
@ -166,10 +165,8 @@ typedef struct {
#define ADDR_INV_CH_NAME ADDR_INV_CH_PWR + INV_CH_CH_PWR_LEN #define ADDR_INV_CH_NAME ADDR_INV_CH_PWR + INV_CH_CH_PWR_LEN
#define ADDR_INV_INTERVAL ADDR_INV_CH_NAME + INV_CH_CH_NAME_LEN #define ADDR_INV_INTERVAL ADDR_INV_CH_NAME + INV_CH_CH_NAME_LEN
#define ADDR_INV_MAX_RTRY ADDR_INV_INTERVAL + INV_INTERVAL_LEN #define ADDR_INV_MAX_RTRY ADDR_INV_INTERVAL + INV_INTERVAL_LEN
#define ADDR_INV_PWR_LIM ADDR_INV_MAX_RTRY + INV_MAX_RTRY_LEN
#define ADDR_INV_PWR_LIM_CON ADDR_INV_PWR_LIM + INV_PWR_LIM_LEN
#define ADDR_NEXT ADDR_INV_PWR_LIM_CON + INV_PWR_LIM_LEN #define ADDR_NEXT ADDR_INV_MAX_RTRY + INV_INTERVAL_LEN
#define ADDR_SETTINGS_CRC ADDR_NEXT + 2 #define ADDR_SETTINGS_CRC ADDR_NEXT + 2

2
tools/esp8266/hmInverter.h

@ -126,7 +126,7 @@ class Inverter {
Inverter() { Inverter() {
powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited powerLimit[0] = 0xffff; // 65535 W Limit -> unlimited
powerLimit[1] = NoPowerLimit; // default power limit setting powerLimit[1] = AbsolutNonPersistent; // default power limit setting
actPowerLimit = 0xffff; // init feedback from inverter to -1 actPowerLimit = 0xffff; // init feedback from inverter to -1
devControlRequest = false; devControlRequest = false;
devControlCmd = InitDataState; devControlCmd = InitDataState;

2
tools/esp8266/html/index.html

@ -13,7 +13,7 @@
<a href="/live">Visualization</a><br/> <a href="/live">Visualization</a><br/>
<br/> <br/>
<a href="/setup">Setup</a><br/> <a href="/setup">Setup</a><br/>
<a href="/serial">Serial Console</a><br/> <a href="/serial">Webserial & Commands</a><br/>
</p> </p>
<p><span class="des">Uptime: </span><span id="uptime"></span></p> <p><span class="des">Uptime: </span><span id="uptime"></span></p>
<p><span class="des">ESP-Time: </span><span id="date"></span></p> <p><span class="des">ESP-Time: </span><span id="date"></span></p>

83
tools/esp8266/html/serial.html

@ -15,25 +15,41 @@
Uptime: <span id="uptime"></span> Uptime: <span id="uptime"></span>
<input type="button" value="clear" class="btn" id="clear"/> <input type="button" value="clear" class="btn" id="clear"/>
<input type="button" value="autoscroll" class="btn" id="scroll"/> <input type="button" value="autoscroll" class="btn" id="scroll"/>
<br/> <br/>
<br/> <br/>
<br/> <br/>
<br/> <br/>
<hr> <hr>
<h3>handle next buttons with care - test / debug only!!</h3> <h3>Commands</h3>
<br/> <br/>
<label for="iv">Select Inverter:</label> <label for="iv">Select Inverter:</label>
<select name="iv" id="InvID"> <select name="iv" id="InvID">
</select> </select>
<br/> <br/>
<input type="button" value="power limit 100%" class="btn" id="pwrlim2"/> <div id="power">
<input type="button" value="power limit 10%" class="btn" id="pwrlim"/>
<input type="button" value="Restart" class="btn" id="restart"/> <input type="button" value="Restart" class="btn" id="restart"/>
<input type="button" value="Turn Off" class="btn" id="turnoff"/> <input type="button" value="Turn Off" class="btn" id="power_off"/>
<input type="button" value="Turn On" class="btn" id="turnon"/> <input type="button" value="Turn On" class="btn" id="power_on"/>
</div>
<br/>
<br/>
<br/>
<br/>
<br/>
<label>Send Power Limit: </label>
<input type="number" class="text" name="pwrlimval" maxlength="4"/>
<label> </label>
<select name="pwrlimcntrl" id="pwrlimcntrl">
<option value="" selected disabled hidden>select the unit and persistence</option>
<option value="0">absolute in Watt non persistent</option>
<option value="1">relativ in percent non persistent</option>
<option value="256">absolute in Watt persistent</option>
<option value="257">relativ in percent persistent</option>
</select>
<br/>
<input type="button" value="Send Power Limit" class="btn" id="sendpwrlim"/>
<br/> <br/>
Ctrl result: <span id="result">n/a</span> <p>Ctrl result: <span id="result">n/a</span></p>
</div> </div>
</div> </div>
<div id="footer"> <div id="footer">
@ -120,48 +136,49 @@
function get_selected_iv() function get_selected_iv()
{ {
var e = document.getElementById("InvID"); var e = document.getElementById("InvID");
return e.value; return parseInt(e.value);
} }
document.getElementById("turnon").addEventListener("click", function() { const wrapper = document.getElementById('power');
var obj = new Object();
obj.inverter = get_selected_iv();
obj.cmd = 0;
obj.tx_request = 81;
getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj));
});
document.getElementById("turnoff").addEventListener("click", function() { wrapper.addEventListener('click', (event) => {
var power = event.target.value;
var obj = new Object(); var obj = new Object();
obj.inverter = get_selected_iv();
obj.cmd = 1;
obj.tx_request = 81;
getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj));
});
document.getElementById("restart").addEventListener("click", function() { switch (power)
var obj = new Object(); {
obj.inverter = get_selected_iv(); case "Turn On":
obj.cmd = 0;
break;
case "Turn Off":
obj.cmd = 1;
break;
default:
obj.cmd = 2; obj.cmd = 2;
obj.tx_request = 81; }
getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj));
});
document.getElementById("pwrlim").addEventListener("click", function() {
var obj = new Object();
obj.inverter = get_selected_iv(); obj.inverter = get_selected_iv();
obj.cmd = 11;
obj.tx_request = 81; obj.tx_request = 81;
obj.payload = [10, 1];
getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj)); getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj));
}); });
document.getElementById("pwrlim2").addEventListener("click", function() { document.getElementById("sendpwrlim").addEventListener("click", function() {
var val = parseInt(document.getElementsByName('pwrlimval')[0].value);
var ctrl = parseInt(document.getElementsByName('pwrlimcntrl')[0].value);
if((ctrl == 1 || ctrl == 257) && unit < 2) unit = 2;
if(isNaN(val) || isNaN(ctrl))
{
var tmp = (isNaN(val)) ? "Value" : "Unit";
document.getElementById("result").textContent = tmp + " is missing";
return;
}
var obj = new Object(); var obj = new Object();
obj.inverter = get_selected_iv(); obj.inverter = get_selected_iv();
obj.cmd = 11; obj.cmd = 11;
obj.tx_request = 81; obj.tx_request = 81;
obj.payload = [2000, 1]; obj.payload = [val, ctrl];
getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj)); getAjax("/api/ctrl", ctrlCb, "POST", JSON.stringify(obj));
}); });

13
tools/esp8266/html/setup.html

@ -129,7 +129,7 @@
document.getElementsByName("btnAdd")[0].addEventListener("click", function() { document.getElementsByName("btnAdd")[0].addEventListener("click", function() {
if(highestId < (maxInv-1)) if(highestId < (maxInv-1))
ivHtml(JSON.parse('{"name":"","serial":"","channels":4,"ch_max_power":[0,0,0,0],"ch_name":["","","",""],"power_limit":1500,"power_limit_option":65535}'), highestId + 1); ivHtml(JSON.parse('{"name":"","serial":"","channels":4,"ch_max_power":[0,0,0,0],"ch_name":["","","",""]}'), highestId + 1);
}); });
function apiCb(obj) { function apiCb(obj) {
@ -189,20 +189,11 @@
} }
}); });
for(var i of [["Name", "name", "Name*", 32], ["ActivePowerLimit", "power_limit", "Active Power Limit", 5]]) { for(var i of [["Name", "name", "Name*", 32]]) { // so richtig?
iv.appendChild(lbl(id + i[0], i[2])); iv.appendChild(lbl(id + i[0], i[2]));
iv.appendChild(inp(id + i[0], obj[i[1]], i[3])); iv.appendChild(inp(id + i[0], obj[i[1]], i[3]));
} }
iv.appendChild(lbl(id + "PowerLimitControl", "Active Power Limit Control Type"));
iv.appendChild(sel(id + "PowerLimitControl", [
[65535, "no power limit"],
[0, "absolute in Watt non persistent"],
[1, "absolute in Watt persistent"],
[256, "relativ in percent non persistent"],
[257, "relativ in percent persistent"]
], obj.power_limit_option));
for(var j of [["ModPwr", "ch_max_power", "Max Module Power (Wp)", 4], ["ModName", "ch_name", "Module Name", 16]]) { for(var j of [["ModPwr", "ch_max_power", "Max Module Power (Wp)", 4], ["ModName", "ch_name", "Module Name", 16]]) {
var cl = (re.test(obj["serial"])) ? null : ["hide"]; var cl = (re.test(obj["serial"])) ? null : ["hide"];
iv.appendChild(lbl(null, j[2], cl, "lbl" + id + j[0])); iv.appendChild(lbl(null, j[2], cl, "lbl" + id + j[0]));

3
tools/esp8266/html/visualization.html

@ -39,8 +39,7 @@
var limit = iv["power_limit_read"] + "%"; var limit = iv["power_limit_read"] + "%";
if(limit == "65535%") if(limit == "65535%")
limit = "n/a"; limit = "n/a";
var ctrl = (iv["power_limit_active"]) ? "" : " (not controlled)"; ch0.appendChild(span(iv["name"] + " Limit " + limit + " | last Alarm: " + iv["last_alarm"], ["head"]));
ch0.appendChild(span(iv["name"] + " Limit " + limit + ctrl + " | last Alarm: " + iv["last_alarm"], ["head"]));
for(var j = 0; j < root.ch0_fld_names.length; j++) { for(var j = 0; j < root.ch0_fld_names.length; j++) {
var val = Math.round(iv["ch"][0][j] * 100) / 100; var val = Math.round(iv["ch"][0][j] * 100) / 100;

25
tools/esp8266/web.cpp

@ -237,31 +237,6 @@ void web::showSave(AsyncWebServerRequest *request) {
memset(buf, 0, 20); memset(buf, 0, 20);
iv->serial.u64 = mMain->Serial2u64(buf); iv->serial.u64 = mMain->Serial2u64(buf);
// active power limit
uint16_t actPwrLimit = request->arg("inv" + String(i) + "ActivePowerLimit").toInt();
uint16_t actPwrLimitControl = request->arg("inv" + String(i) + "PowerLimitControl").toInt();
if(NoPowerLimit != actPwrLimitControl) {
if (actPwrLimit != 0xffff && actPwrLimit > 0){
iv->powerLimit[0] = actPwrLimit;
iv->powerLimit[1] = actPwrLimitControl;
iv->devControlCmd = ActivePowerContr;
iv->devControlRequest = true;
if ((iv->powerLimit[1] & 0x0001) == 0x0001)
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("%") );
else {
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W") );
DPRINTLN(DBG_INFO, F("Power Limit Control Setting ") + String(iv->powerLimit[1]));
}
}
if (actPwrLimit == 0xffff) { // set to 100%
iv->powerLimit[0] = 100;
iv->powerLimit[1] = RelativPersistent;
iv->devControlCmd = ActivePowerContr;
iv->devControlRequest = true;
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to unlimted"));
}
}
// name // name
request->arg("inv" + String(i) + "Name").toCharArray(iv->name, MAX_NAME_LENGTH); request->arg("inv" + String(i) + "Name").toCharArray(iv->name, MAX_NAME_LENGTH);

9
tools/esp8266/webApi.cpp

@ -158,9 +158,6 @@ void webApi::getInverterList(JsonObject obj) {
obj2[F("ch_max_power")][j] = iv->chMaxPwr[j]; obj2[F("ch_max_power")][j] = iv->chMaxPwr[j];
obj2[F("ch_name")][j] = iv->chName[j]; obj2[F("ch_name")][j] = iv->chName[j];
} }
obj2[F("power_limit")] = iv->powerLimit[0];
obj2[F("power_limit_option")] = iv->powerLimit[1];
} }
} }
obj[F("interval")] = String(mConfig->sendInterval); obj[F("interval")] = String(mConfig->sendInterval);
@ -276,7 +273,6 @@ void webApi::getLive(JsonObject obj) {
obj2[F("name")] = String(iv->name); obj2[F("name")] = String(iv->name);
obj2[F("channels")] = iv->channels; obj2[F("channels")] = iv->channels;
obj2[F("power_limit_read")] = round3(iv->actPowerLimit); obj2[F("power_limit_read")] = round3(iv->actPowerLimit);
obj2[F("power_limit_active")] = NoPowerLimit != iv->powerLimit[1];
obj2[F("last_alarm")] = String(iv->lastAlarmMsg); obj2[F("last_alarm")] = String(iv->lastAlarmMsg);
obj2[F("ts_last_success")] = rec->ts; obj2[F("ts_last_success")] = rec->ts;
@ -342,8 +338,9 @@ bool webApi::setCtrl(DynamicJsonDocument jsonIn, JsonObject jsonOut) {
// Todo: num is the inverter number 0-3. For better display in DPRINTLN // Todo: num is the inverter number 0-3. For better display in DPRINTLN
uint8_t num = jsonIn[F("inverter")]; uint8_t num = jsonIn[F("inverter")];
uint8_t tx_request = jsonIn[F("tx_request")];
if(TX_REQ_DEVCONTROL == jsonIn[F("tx_request")]) if(TX_REQ_DEVCONTROL == tx_request)
{ {
DPRINTLN(DBG_INFO, F("devcontrol [") + String(num) + F("], cmd: 0x") + String(cmd, HEX)); DPRINTLN(DBG_INFO, F("devcontrol [") + String(num) + F("], cmd: 0x") + String(cmd, HEX));
@ -371,6 +368,8 @@ bool webApi::setCtrl(DynamicJsonDocument jsonIn, JsonObject jsonOut) {
iv->devControlRequest = true; iv->devControlRequest = true;
break; break;
case ActivePowerContr: case ActivePowerContr:
iv->devControlCmd = ActivePowerContr;
iv->devControlRequest = true;
iv->powerLimit[0] = payload[0]; iv->powerLimit[0] = payload[0];
iv->powerLimit[1] = payload[1]; iv->powerLimit[1] = payload[1];
break; break;

Loading…
Cancel
Save