mirror of
https://github.com/lumapu/ahoy.git
synced 2025-05-10 15:36:38 +02:00
ESP8266 v0.4.16
* request only one inverter per loop (https://github.com/grindylow/ahoy/issues/53#issuecomment-1147042489) * mqtt loop interval calculated by # of inverters and inverter request interval * limit maximum number of retries * added feature request #62 (readable names for channels) * improved setup page, added javascript to hide / show channel fields ** IMORTANT: memory layout change, all configuration will be lost, except WiFI **
This commit is contained in:
parent
b995cc0a93
commit
f148c41a1f
13 changed files with 260 additions and 117 deletions
|
@ -19,6 +19,8 @@ app::app() : Main() {
|
|||
mTicker = 0;
|
||||
mRxTicker = 0;
|
||||
|
||||
mSendLastIvId = 0;
|
||||
|
||||
mShowRebootRequest = false;
|
||||
|
||||
mSerialValues = true;
|
||||
|
@ -53,25 +55,40 @@ void app::setup(uint32_t timeout) {
|
|||
mWeb->on("/livedata", std::bind(&app::showLiveData, this));
|
||||
|
||||
if(mSettingsValid) {
|
||||
uint64_t invSerial;
|
||||
char invName[MAX_NAME_LENGTH + 1] = {0};
|
||||
uint16_t modPwr[4];
|
||||
|
||||
// inverter
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
||||
mEep->read(ADDR_INV_ADDR + (i * 8), &invSerial);
|
||||
mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), invName, MAX_NAME_LENGTH);
|
||||
mEep->read(ADDR_INV_MOD_PWR + (i * 2 * 4), modPwr, 4);
|
||||
if(0ULL != invSerial) {
|
||||
mSys->addInverter(invName, invSerial, modPwr);
|
||||
DPRINTLN(F("add inverter: ") + String(invName) + ", SN: " + String(invSerial, HEX));
|
||||
}
|
||||
}
|
||||
mEep->read(ADDR_INV_INTERVAL, &mSendInterval);
|
||||
if(mSendInterval < 5)
|
||||
mSendInterval = 5;
|
||||
mSendTicker = mSendInterval;
|
||||
|
||||
// inverter
|
||||
uint64_t invSerial;
|
||||
char name[MAX_NAME_LENGTH + 1] = {0};
|
||||
uint16_t modPwr[4];
|
||||
Inverter<> *iv;
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
||||
mEep->read(ADDR_INV_ADDR + (i * 8), &invSerial);
|
||||
mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), name, MAX_NAME_LENGTH);
|
||||
mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4);
|
||||
if(0ULL != invSerial) {
|
||||
iv = mSys->addInverter(name, invSerial, modPwr);
|
||||
if(NULL != iv) {
|
||||
DPRINTLN(F("add inverter: ") + String(name) + ", SN: " + String(invSerial, HEX));
|
||||
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, name, MAX_NAME_LENGTH);
|
||||
snprintf(iv->chName[j], MAX_NAME_LENGTH, "%s", name);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
mMqttInterval += mSendInterval;
|
||||
}
|
||||
}
|
||||
|
||||
mEep->read(ADDR_INV_MAX_RTRY, &mMaxRetransPerPyld);
|
||||
if(0 == mMaxRetransPerPyld)
|
||||
mMaxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD;
|
||||
|
||||
// pinout
|
||||
mEep->read(ADDR_PINOUT, &mSys->Radio.pinCs);
|
||||
mEep->read(ADDR_PINOUT+1, &mSys->Radio.pinCe);
|
||||
|
@ -103,7 +120,7 @@ void app::setup(uint32_t timeout) {
|
|||
mEep->read(ADDR_MQTT_USER, mqttUser, MQTT_USER_LEN);
|
||||
mEep->read(ADDR_MQTT_PWD, mqttPwd, MQTT_PWD_LEN);
|
||||
mEep->read(ADDR_MQTT_TOPIC, mqttTopic, MQTT_TOPIC_LEN);
|
||||
mEep->read(ADDR_MQTT_INTERVAL, &mMqttInterval);
|
||||
//mEep->read(ADDR_MQTT_INTERVAL, &mMqttInterval);
|
||||
mEep->read(ADDR_MQTT_PORT, &mqttPort);
|
||||
|
||||
char addr[16] = {0};
|
||||
|
@ -112,18 +129,38 @@ void app::setup(uint32_t timeout) {
|
|||
if(mqttAddr[0] > 0) {
|
||||
mMqttActive = true;
|
||||
if(mMqttInterval < 1)
|
||||
mMqttInterval = 1;
|
||||
mMqttInterval = 10;
|
||||
|
||||
snprintf(mqttTopic, MQTT_TOPIC_LEN, "inverter");
|
||||
}
|
||||
else
|
||||
mMqttInterval = 0xffff;
|
||||
|
||||
if(0 == mqttPort)
|
||||
mqttPort = 1883;
|
||||
|
||||
|
||||
mMqtt.setup(addr, mqttTopic, mqttUser, mqttPwd, mqttPort);
|
||||
mMqttTicker = 0;
|
||||
|
||||
mSerialTicker = 0;
|
||||
|
||||
mMqtt.sendMsg("version", mVersion);
|
||||
if(mqttAddr[0] > 0) {
|
||||
char topic[30];
|
||||
mMqtt.sendMsg("version", mVersion);
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
||||
iv = mSys->getInverterByPos(i);
|
||||
if(NULL != iv) {
|
||||
for(uint8_t i = 0; i < 4; i++) {
|
||||
if(0 != iv->chName[i][0]) {
|
||||
snprintf(topic, 30, "%s/ch%d/%s", iv->name, i+1, "name");
|
||||
mMqtt.sendMsg(topic, iv->chName[i]);
|
||||
yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DPRINTLN(F("Settings not valid, erasing ..."));
|
||||
|
@ -212,7 +249,7 @@ void app::loop(void) {
|
|||
mMqtt.loop();
|
||||
|
||||
if(checkTicker(&mTicker, 1000)) {
|
||||
if(++mMqttTicker >= mMqttInterval) {
|
||||
if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff)) {
|
||||
mMqttTicker = 0;
|
||||
mMqtt.isConnected(true);
|
||||
char topic[30], val[10];
|
||||
|
@ -258,20 +295,25 @@ void app::loop(void) {
|
|||
if(++mSendTicker >= mSendInterval) {
|
||||
mSendTicker = 0;
|
||||
|
||||
if(mSerialDebug)
|
||||
DPRINTLN(F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX));
|
||||
|
||||
if(!mSys->BufCtrl.empty()) {
|
||||
if(0 != mTimestamp) {
|
||||
if(mSerialDebug)
|
||||
DPRINTLN(F("recbuf not empty! #") + String(mSys->BufCtrl.getFill()));
|
||||
}
|
||||
Inverter<> *iv;
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
||||
iv = mSys->getInverterByPos(i);
|
||||
DPRINTLN(F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX));
|
||||
|
||||
if(!mSys->BufCtrl.empty()) {
|
||||
if(mSerialDebug)
|
||||
DPRINTLN(F("recbuf not empty! #") + String(mSys->BufCtrl.getFill()));
|
||||
}
|
||||
|
||||
int8_t maxLoop = MAX_NUM_INVERTERS;
|
||||
Inverter<> *iv = mSys->getInverterByPos(mSendLastIvId);
|
||||
do {
|
||||
if(NULL != iv)
|
||||
mPayload[iv->id].requested = false;
|
||||
mSendLastIvId = ((MAX_NUM_INVERTERS-1) == mSendLastIvId) ? 0 : mSendLastIvId + 1;
|
||||
iv = mSys->getInverterByPos(mSendLastIvId);
|
||||
} while((NULL == iv) && ((maxLoop--) > 0));
|
||||
|
||||
if(NULL != iv) {
|
||||
// reset payload data
|
||||
memset(mPayload[iv->id].len, 0, MAX_PAYLOAD_ENTRIES);
|
||||
mPayload[iv->id].maxPackId = 0;
|
||||
if(!mPayload[iv->id].complete)
|
||||
processPayload(false);
|
||||
|
||||
|
@ -283,7 +325,12 @@ void app::loop(void) {
|
|||
}
|
||||
}
|
||||
|
||||
mPayload[iv->id].complete = false;
|
||||
// reset payload data
|
||||
memset(mPayload[iv->id].len, 0, MAX_PAYLOAD_ENTRIES);
|
||||
mPayload[iv->id].retransmits = 0;
|
||||
mPayload[iv->id].maxPackId = 0;
|
||||
mPayload[iv->id].complete = false;
|
||||
mPayload[iv->id].requested = true;
|
||||
mPayload[iv->id].ts = mTimestamp;
|
||||
|
||||
yield();
|
||||
|
@ -292,8 +339,10 @@ void app::loop(void) {
|
|||
mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].ts);
|
||||
mRxTicker = 0;
|
||||
}
|
||||
yield();
|
||||
}
|
||||
else if(mSerialDebug)
|
||||
DPRINTLN(F("time not set, can't request inverter!"));
|
||||
yield();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -340,25 +389,32 @@ void app::processPayload(bool retransmit) {
|
|||
if(NULL != iv) {
|
||||
if(!mPayload[iv->id].complete) {
|
||||
if(!buildPayload(iv->id)) {
|
||||
if(retransmit) {
|
||||
if(mPayload[iv->id].maxPackId != 0) {
|
||||
for(uint8_t i = 0; i < (mPayload[iv->id].maxPackId-1); i ++) {
|
||||
if(mPayload[iv->id].len[i] == 0) {
|
||||
if(mSerialDebug)
|
||||
DPRINTLN(F("Error while retrieving data: Frame ") + String(i+1) + F(" missing: Request Retransmit"));
|
||||
mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x15, (0x81+i), true);
|
||||
if(mPayload[iv->id].requested) {
|
||||
if(mPayload[iv->id].retransmits < mMaxRetransPerPyld) {
|
||||
mPayload[iv->id].retransmits++;
|
||||
if(retransmit) {
|
||||
if(mPayload[iv->id].maxPackId != 0) {
|
||||
for(uint8_t i = 0; i < (mPayload[iv->id].maxPackId-1); i ++) {
|
||||
if(mPayload[iv->id].len[i] == 0) {
|
||||
if(mSerialDebug)
|
||||
DPRINTLN(F("Error while retrieving data: Frame ") + String(i+1) + F(" missing: Request Retransmit"));
|
||||
mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x15, (0x81+i), true);
|
||||
break; // only retransmit one frame per loop
|
||||
}
|
||||
yield();
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(mSerialDebug)
|
||||
DPRINTLN(F("Error while retrieving data: last frame missing: Request Retransmit"));
|
||||
if(0x00 != mLastPacketId)
|
||||
mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x15, mLastPacketId, true);
|
||||
else
|
||||
mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].ts);
|
||||
}
|
||||
mSys->Radio.switchRxCh(300);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(mSerialDebug)
|
||||
DPRINTLN(F("Error while retrieving data: last frame missing: Request Retransmit"));
|
||||
if(0x00 != mLastPacketId)
|
||||
mSys->Radio.sendCmdPacket(iv->radioId.u64, 0x15, mLastPacketId, true);
|
||||
else
|
||||
mSys->Radio.sendTimePacket(iv->radioId.u64, mPayload[iv->id].ts);
|
||||
}
|
||||
mSys->Radio.switchRxCh(300);
|
||||
}
|
||||
}
|
||||
else {
|
||||
|
@ -423,32 +479,41 @@ void app::showSetup(void) {
|
|||
|
||||
String inv;
|
||||
uint64_t invSerial;
|
||||
char invName[MAX_NAME_LENGTH + 1] = {0};
|
||||
char name[MAX_NAME_LENGTH + 1] = {0};
|
||||
uint8_t invType;
|
||||
uint16_t modPwr[4];
|
||||
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) {
|
||||
mEep->read(ADDR_INV_ADDR + (i * 8), &invSerial);
|
||||
mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), invName, MAX_NAME_LENGTH);
|
||||
mEep->read(ADDR_INV_MOD_PWR + (i * 2 * 4), modPwr, 4);
|
||||
mEep->read(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), name, MAX_NAME_LENGTH);
|
||||
mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4);
|
||||
inv += F("<p class=\"subdes\">Inverter ") + String(i) + "</p>";
|
||||
|
||||
inv += F("<label for=\"inv") + String(i) + F("Addr\">Address</label>");
|
||||
inv += F("<input type=\"text\" class=\"text\" name=\"inv") + String(i) + F("Addr\" value=\"");
|
||||
if(0ULL != invSerial)
|
||||
inv += String(invSerial, HEX);
|
||||
inv += F("\"/ maxlength=\"12\">");
|
||||
inv += F("\"/ maxlength=\"12\" onkeyup=\"checkSerial()\">");
|
||||
|
||||
inv += F("<label for=\"inv") + String(i) + F("Name\">Name</label>");
|
||||
inv += F("<input type=\"text\" class=\"text\" name=\"inv") + String(i) + F("Name\" value=\"");
|
||||
inv += String(invName);
|
||||
inv += String(name);
|
||||
inv += F("\"/ maxlength=\"") + String(MAX_NAME_LENGTH) + "\">";
|
||||
|
||||
inv += F("<label for=\"inv") + String(i) + F("ModPwr0\">Max Module Power (Wp)</label>");
|
||||
inv += F("<label for=\"inv") + String(i) + F("ModPwr0\" name=\"lbl") + String(i);
|
||||
inv += F("ModPwr\">Max Module Power (Wp)</label>");
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
inv += F("<input type=\"text\" class=\"text sh\" name=\"inv") + String(i) + F("ModPwr") + String(j) + F("\" value=\"");
|
||||
inv += String(modPwr[j]);
|
||||
inv += F("\"/ maxlength=\"4\">");
|
||||
}
|
||||
inv += F("<br/><label for=\"inv") + String(i) + F("ModName0\" name=\"lbl") + String(i);
|
||||
inv += F("ModName\">Module Name</label>");
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
mEep->read(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, name, MAX_NAME_LENGTH);
|
||||
inv += F("<input type=\"text\" class=\"text sh\" name=\"inv") + String(i) + F("ModName") + String(j) + F("\" value=\"");
|
||||
inv += String(name);
|
||||
inv += F("\"/ maxlength=\"") + String(MAX_NAME_LENGTH) + "\">";
|
||||
}
|
||||
}
|
||||
html.replace(F("{INVERTERS}"), String(inv));
|
||||
|
||||
|
@ -484,13 +549,12 @@ void app::showSetup(void) {
|
|||
|
||||
|
||||
if(mSettingsValid) {
|
||||
mEep->read(ADDR_INV_INTERVAL, &interval);
|
||||
html.replace(F("{INV_INTVL}"), String(interval));
|
||||
html.replace(F("{INV_INTVL}"), String(mSendInterval));
|
||||
html.replace(F("{INV_RETRIES}"), String(mMaxRetransPerPyld));
|
||||
|
||||
uint8_t tmp;
|
||||
mEep->read(ADDR_SER_INTERVAL, &interval);
|
||||
mEep->read(ADDR_SER_ENABLE, &tmp);
|
||||
html.replace(F("{SER_INTVL}"), String(interval));
|
||||
html.replace(F("{SER_INTVL}"), String(mSerialInterval));
|
||||
html.replace(F("{SER_VAL_CB}"), (tmp == 0x01) ? "checked" : "");
|
||||
mEep->read(ADDR_SER_DEBUG, &tmp);
|
||||
html.replace(F("{SER_DBG_CB}"), (tmp == 0x01) ? "checked" : "");
|
||||
|
@ -498,33 +562,16 @@ void app::showSetup(void) {
|
|||
uint8_t mqttAddr[MQTT_ADDR_LEN] = {0};
|
||||
uint16_t mqttPort;
|
||||
mEep->read(ADDR_MQTT_ADDR, mqttAddr, MQTT_ADDR_LEN);
|
||||
mEep->read(ADDR_MQTT_INTERVAL, &interval);
|
||||
mEep->read(ADDR_MQTT_PORT, &mqttPort);
|
||||
|
||||
char addr[16] = {0};
|
||||
sprintf(addr, "%d.%d.%d.%d", mqttAddr[0], mqttAddr[1], mqttAddr[2], mqttAddr[3]);
|
||||
html.replace(F("{MQTT_ADDR}"), String(addr));
|
||||
html.replace(F("{MQTT_PORT}"), String(mqttPort));
|
||||
html.replace(F("{MQTT_PORT}"), String(mMqtt.getPort()));
|
||||
html.replace(F("{MQTT_USER}"), String(mMqtt.getUser()));
|
||||
html.replace(F("{MQTT_PWD}"), String(mMqtt.getPwd()));
|
||||
html.replace(F("{MQTT_TOPIC}"), String(mMqtt.getTopic()));
|
||||
html.replace(F("{MQTT_INTVL}"), String(interval));
|
||||
}
|
||||
else {
|
||||
html.replace(F("{INV_INTVL}"), "5");
|
||||
|
||||
html.replace(F("{SER_VAL_CB}"), "checked");
|
||||
html.replace(F("{SER_DBG_CB}"), "");
|
||||
html.replace(F("{SER_INTVL}"), "10");
|
||||
|
||||
html.replace(F("{MQTT_ADDR}"), "");
|
||||
html.replace(F("{MQTT_PORT}"), "1883");
|
||||
html.replace(F("{MQTT_USER}"), "");
|
||||
html.replace(F("{MQTT_PWD}"), "");
|
||||
html.replace(F("{MQTT_TOPIC}"), "inverter");
|
||||
html.replace(F("{MQTT_INTVL}"), "10");
|
||||
|
||||
html.replace(F("{SER_INTVL}"), "10");
|
||||
html.replace(F("{MQTT_INTVL}"), String(mMqttInterval));
|
||||
}
|
||||
|
||||
mWeb->send(200, F("text/html"), html);
|
||||
|
@ -584,7 +631,7 @@ void app::showStatistics(void) {
|
|||
content += F("INFO: reboot your ESP to apply all your configuration changes!\n");
|
||||
|
||||
if(!mSettingsValid)
|
||||
content += F("INFO: your settings are invalid, please switch to <a href=\"/setup\">setup</a> to correct this.\n");
|
||||
content += F("INFO: your settings are invalid, please switch to <a href=\"/setup\">Setup</a> to correct this.\n");
|
||||
|
||||
content += F("MQTT: ");
|
||||
if(!mMqtt.isConnected())
|
||||
|
@ -609,7 +656,7 @@ void app::showHoymiles(void) {
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
void app::showLiveData(void) {
|
||||
DPRINTLN(F("app::showLiveData"));
|
||||
//DPRINTLN(F("app::showLiveData"));
|
||||
String modHtml;
|
||||
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
|
||||
Inverter<> *iv = mSys->getInverterByPos(id);
|
||||
|
@ -640,7 +687,12 @@ void app::showLiveData(void) {
|
|||
modHtml += "</div>";
|
||||
|
||||
for(uint8_t ch = 1; ch <= modNum; ch ++) {
|
||||
modHtml += F("<div class=\"ch\"><span class=\"head\">CHANNEL ") + String(ch) + F("</span>");
|
||||
modHtml += F("<div class=\"ch\"><span class=\"head\">");
|
||||
if(iv->chName[ch-1][0] == 0)
|
||||
modHtml += F("CHANNEL ") + String(ch);
|
||||
else
|
||||
modHtml += String(iv->chName[ch-1]);
|
||||
modHtml += F("</span>");
|
||||
for(uint8_t j = 0; j < 6; j++) {
|
||||
switch(j) {
|
||||
default: pos = (iv->getPosByChFld(ch, FLD_UDC)); break;
|
||||
|
@ -705,15 +757,20 @@ void app::saveValues(bool webSend = true) {
|
|||
mWeb->arg("inv" + String(i) + "Name").toCharArray(buf, 20);
|
||||
mEep->write(ADDR_INV_NAME + (i * MAX_NAME_LENGTH), buf, MAX_NAME_LENGTH);
|
||||
|
||||
// max module power
|
||||
// max channel power / name
|
||||
for(uint8_t j = 0; j < 4; j++) {
|
||||
uint16_t pwr = mWeb->arg("inv" + String(i) + "ModPwr" + String(j)).toInt();
|
||||
mEep->write(ADDR_INV_MOD_PWR + (i * 2 * 4) + (j*2), pwr);
|
||||
mEep->write(ADDR_INV_CH_PWR + (i * 2 * 4) + (j*2), pwr);
|
||||
memset(buf, 0, 20);
|
||||
mWeb->arg("inv" + String(i) + "ModName" + String(j)).toCharArray(buf, 20);
|
||||
mEep->write(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, buf, MAX_NAME_LENGTH);
|
||||
}
|
||||
}
|
||||
|
||||
interval = mWeb->arg("invInterval").toInt();
|
||||
mEep->write(ADDR_INV_INTERVAL, interval);
|
||||
i = mWeb->arg("invRetry").toInt();
|
||||
mEep->write(ADDR_INV_MAX_RTRY, i);
|
||||
|
||||
|
||||
// pinout
|
||||
|
@ -743,14 +800,14 @@ void app::saveValues(bool webSend = true) {
|
|||
mWeb->arg("mqttUser").toCharArray(mqttUser, MQTT_USER_LEN);
|
||||
mWeb->arg("mqttPwd").toCharArray(mqttPwd, MQTT_PWD_LEN);
|
||||
mWeb->arg("mqttTopic").toCharArray(mqttTopic, MQTT_TOPIC_LEN);
|
||||
interval = mWeb->arg("mqttIntvl").toInt();
|
||||
//interval = mWeb->arg("mqttIntvl").toInt();
|
||||
mqttPort = mWeb->arg("mqttPort").toInt();
|
||||
mEep->write(ADDR_MQTT_ADDR, mqttAddr, MQTT_ADDR_LEN);
|
||||
mEep->write(ADDR_MQTT_PORT, mqttPort);
|
||||
mEep->write(ADDR_MQTT_USER, mqttUser, MQTT_USER_LEN);
|
||||
mEep->write(ADDR_MQTT_PWD, mqttPwd, MQTT_PWD_LEN);
|
||||
mEep->write(ADDR_MQTT_TOPIC, mqttTopic, MQTT_TOPIC_LEN);
|
||||
mEep->write(ADDR_MQTT_INTERVAL, interval);
|
||||
//mEep->write(ADDR_MQTT_INTERVAL, interval);
|
||||
|
||||
|
||||
// serial console
|
||||
|
@ -766,6 +823,7 @@ void app::saveValues(bool webSend = true) {
|
|||
mSys->Radio.mSerialDebug = mSerialDebug;
|
||||
|
||||
updateCrc();
|
||||
mEep->commit();
|
||||
if((mWeb->arg("reboot") == "on"))
|
||||
showReboot();
|
||||
else {
|
||||
|
@ -776,6 +834,7 @@ void app::saveValues(bool webSend = true) {
|
|||
}
|
||||
else {
|
||||
updateCrc();
|
||||
mEep->commit();
|
||||
mWeb->send(200, F("text/html"), F("<!doctype html><html><head><title>Error</title><meta http-equiv=\"refresh\" content=\"3; URL=/setup\"></head><body>"
|
||||
"<p>Error while saving</p></body></html>"));
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ typedef struct {
|
|||
uint8_t len[MAX_PAYLOAD_ENTRIES];
|
||||
bool complete;
|
||||
uint8_t maxPackId;
|
||||
uint8_t retransmits;
|
||||
bool requested;
|
||||
} invPayload_t;
|
||||
|
||||
|
||||
|
@ -84,11 +86,13 @@ class app : public Main {
|
|||
|
||||
uint16_t mSendTicker;
|
||||
uint16_t mSendInterval;
|
||||
uint8_t mSendLastIvId;
|
||||
|
||||
invPayload_t mPayload[MAX_NUM_INVERTERS];
|
||||
uint32_t mRxFailed;
|
||||
uint32_t mRxSuccess;
|
||||
uint8_t mLastPacketId;
|
||||
uint8_t mMaxRetransPerPyld;
|
||||
|
||||
// timer
|
||||
uint32_t mTicker;
|
||||
|
|
|
@ -41,6 +41,9 @@
|
|||
// maximum total payload buffers (must be greater than the number of received frame fragments)
|
||||
#define MAX_PAYLOAD_ENTRIES 4
|
||||
|
||||
// maximum requests for retransmits per payload (per inverter)
|
||||
#define DEF_MAX_RETRANS_PER_PYLD 5
|
||||
|
||||
// number of seconds since last successful response, before inverter is marked inactive
|
||||
#define INACT_THRES_SEC 300
|
||||
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
//-------------------------------------
|
||||
#define VERSION_MAJOR 0
|
||||
#define VERSION_MINOR 4
|
||||
#define VERSION_PATCH 15
|
||||
#define VERSION_PATCH 16
|
||||
|
||||
|
||||
//-------------------------------------
|
||||
|
@ -34,10 +34,12 @@ typedef struct {
|
|||
#define DEVNAME_LEN 16
|
||||
#define CRC_LEN 2 // uint16_t
|
||||
|
||||
#define INV_ADDR_LEN MAX_NUM_INVERTERS * 8 // uint64_t
|
||||
#define INV_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH // char[]
|
||||
#define INV_CH_MOD_PWR_LEN MAX_NUM_INVERTERS * 2 * 4 // uint16_t (4 channels)
|
||||
#define INV_INTERVAL_LEN 2 // uint16_t
|
||||
#define INV_ADDR_LEN MAX_NUM_INVERTERS * 8 // uint64_t
|
||||
#define INV_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH // char[]
|
||||
#define INV_CH_CH_PWR_LEN MAX_NUM_INVERTERS * 2 * 4 // uint16_t (4 channels)
|
||||
#define INV_CH_CH_NAME_LEN MAX_NUM_INVERTERS * MAX_NAME_LENGTH * 4 // (4 channels)
|
||||
#define INV_INTERVAL_LEN 2 // uint16_t
|
||||
#define INV_MAX_RTRY_LEN 1 // uint8_t
|
||||
|
||||
#define PINOUT_LEN 3 // 3 pins: CS, CE, IRQ
|
||||
|
||||
|
@ -68,10 +70,12 @@ typedef struct {
|
|||
|
||||
#define ADDR_INV_ADDR ADDR_RF24_AMP_PWR + RF24_AMP_PWR_LEN
|
||||
#define ADDR_INV_NAME ADDR_INV_ADDR + INV_ADDR_LEN
|
||||
#define ADDR_INV_MOD_PWR ADDR_INV_NAME + INV_NAME_LEN
|
||||
#define ADDR_INV_INTERVAL ADDR_INV_MOD_PWR + INV_CH_MOD_PWR_LEN
|
||||
#define ADDR_INV_CH_PWR ADDR_INV_NAME + INV_NAME_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_MAX_RTRY ADDR_INV_INTERVAL + INV_INTERVAL_LEN
|
||||
|
||||
#define ADDR_MQTT_ADDR ADDR_INV_INTERVAL + INV_INTERVAL_LEN
|
||||
#define ADDR_MQTT_ADDR ADDR_INV_MAX_RTRY + INV_MAX_RTRY_LEN
|
||||
#define ADDR_MQTT_USER ADDR_MQTT_ADDR + MQTT_ADDR_LEN
|
||||
#define ADDR_MQTT_PWD ADDR_MQTT_USER + MQTT_USER_LEN
|
||||
#define ADDR_MQTT_TOPIC ADDR_MQTT_PWD + MQTT_PWD_LEN
|
||||
|
@ -83,7 +87,7 @@ typedef struct {
|
|||
#define ADDR_SER_INTERVAL ADDR_SER_DEBUG + SER_DEBUG_LEN
|
||||
#define ADDR_NEXT ADDR_SER_INTERVAL + SER_INTERVAL_LEN
|
||||
|
||||
#define ADDR_SETTINGS_CRC 400
|
||||
#define ADDR_SETTINGS_CRC 950
|
||||
|
||||
#if(ADDR_SETTINGS_CRC <= ADDR_NEXT)
|
||||
#error address overlap!
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
class eep {
|
||||
public:
|
||||
eep() {
|
||||
EEPROM.begin(500);
|
||||
EEPROM.begin(1000);
|
||||
}
|
||||
~eep() {
|
||||
EEPROM.end();
|
||||
|
@ -81,14 +81,12 @@ class eep {
|
|||
for(uint8_t i = 0; i < length; i ++) {
|
||||
EEPROM.write(addr++, str[i]);
|
||||
}
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void write(uint32_t addr, uint8_t data[], uint16_t length) {
|
||||
for(uint16_t i = 0; i < length; i ++) {
|
||||
EEPROM.write(addr++, data[i]);
|
||||
}
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void write(uint32_t addr, float value) {
|
||||
|
@ -96,24 +94,20 @@ class eep {
|
|||
for(uint8_t i = 0; i < 4; i ++) {
|
||||
EEPROM.write(addr++, p[i]);
|
||||
}
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void write(uint32_t addr, bool value) {
|
||||
uint8_t intVal = (value) ? 0x01 : 0x00;
|
||||
EEPROM.write(addr++, intVal);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void write(uint32_t addr, uint8_t value) {
|
||||
EEPROM.write(addr++, value);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void write(uint32_t addr, uint16_t value) {
|
||||
EEPROM.write(addr++, (value >> 8) & 0xff);
|
||||
EEPROM.write(addr++, (value ) & 0xff);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
|
||||
|
@ -129,7 +123,6 @@ class eep {
|
|||
EEPROM.write(addr++, (value >> 16) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 8) & 0xff);
|
||||
EEPROM.write(addr++, (value ) & 0xff);
|
||||
EEPROM.commit();
|
||||
}
|
||||
|
||||
void write(uint64_t addr, uint64_t value) {
|
||||
|
@ -141,6 +134,9 @@ class eep {
|
|||
EEPROM.write(addr++, (value >> 16) & 0xff);
|
||||
EEPROM.write(addr++, (value >> 8) & 0xff);
|
||||
EEPROM.write(addr++, (value ) & 0xff);
|
||||
}
|
||||
|
||||
void commit(void) {
|
||||
EEPROM.commit();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -71,6 +71,7 @@ class Inverter {
|
|||
uint32_t ts; // timestamp of last received payload
|
||||
RECORDTYPE *record; // pointer for values
|
||||
uint16_t chMaxPwr[4]; // maximum power of the modules (Wp)
|
||||
char chName[4][MAX_NAME_LENGTH]; // human readable name for channel
|
||||
|
||||
Inverter() {
|
||||
ts = 0;
|
||||
|
@ -86,6 +87,7 @@ class Inverter {
|
|||
toRadioId();
|
||||
record = new RECORDTYPE[listLen];
|
||||
memset(name, 0, MAX_NAME_LENGTH);
|
||||
memset(chName, 0, MAX_NAME_LENGTH * 4);
|
||||
memset(record, 0, sizeof(RECORDTYPE) * listLen);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __SETUP_HTML_H__
|
||||
#define __SETUP_HTML_H__
|
||||
const char setup_html[] PROGMEM = "<!doctype html><html><head><title>Setup - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"></head><body><h1>Setup</h1><div id=\"setup\" class=\"content\"><div id=\"content\"><p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information. </p><form method=\"post\" action=\"{IP}/save\"><p class=\"des\">WiFi</p><label for=\"ssid\">SSID</label><input type=\"text\" class=\"text\" name=\"ssid\" value=\"{SSID}\"/><label for=\"pwd\">Password</label><input type=\"password\" class=\"text\" name=\"pwd\" value=\"{PWD}\"/><p class=\"des\">Device Host Name</p><label for=\"device\">Device Name</label><input type=\"text\" class=\"text\" name=\"device\" value=\"{DEVICE}\"/><a class=\"erase\" href=\"/erase\">ERASE SETTINGS (not WiFi)</a><p class=\"des\">Inverter</p>{INVERTERS}<br/><p class=\"subdes\">General</p><label for=\"invInterval\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"invInterval\" value=\"{INV_INTVL}\"/><p class=\"des\">Pinout (Wemos)</p>{PINOUT}<p class=\"des\">Radio (NRF24L01+)</p><label for=\"rf24Power\">Amplifier Power Level</label><select name=\"rf24Power\">{RF24}</select><p class=\"des\">MQTT</p><label for=\"mqttAddr\">Broker / Server IP</label><input type=\"text\" class=\"text\" name=\"mqttAddr\" value=\"{MQTT_ADDR}\"/><label for=\"mqttPort\">Port</label><input type=\"text\" class=\"text\" name=\"mqttPort\" value=\"{MQTT_PORT}\"/><label for=\"mqttUser\">Username (optional)</label><input type=\"text\" class=\"text\" name=\"mqttUser\" value=\"{MQTT_USER}\"/><label for=\"mqttPwd\">Password (optional)</label><input type=\"text\" class=\"text\" name=\"mqttPwd\" value=\"{MQTT_PWD}\"/><label for=\"mqttTopic\">Topic</label><input type=\"text\" class=\"text\" name=\"mqttTopic\" value=\"{MQTT_TOPIC}\"/><label for=\"mqttIntvl\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"mqttIntvl\" value=\"{MQTT_INTVL}\"/><p class=\"des\">Serial Console</p><label for=\"serEn\">print inverter data</label><input type=\"checkbox\" class=\"cb\" name=\"serEn\" {SER_VAL_CB}/><br/><label for=\"serDbg\">print RF24 debug</label><input type=\"checkbox\" class=\"cb\" name=\"serDbg\" {SER_DBG_CB}/><br/><label for=\"serIntvl\">Interval (s)</label><input type=\"text\" class=\"text\" name=\"serIntvl\" value=\"{SER_INTVL}\"/><p class=\"des\"> </p><label for=\"reboot\">Reboot device after successful save</label><input type=\"checkbox\" class=\"cb\" name=\"reboot\"/><input type=\"submit\" value=\"save\" class=\"btn\" /></form></div></div><div id=\"footer\"><p class=\"left\"><a href=\"{IP}/\">Home</a></p><p class=\"left\"><a href=\"{IP}/update\">Update Firmware</a></p><p class=\"right\">AHOY - {VERSION}</p><p class=\"right\"><a href=\"{IP}/factory\">Factory Reset</a></p><p class=\"right\"><a href=\"{IP}/reboot\">Reboot</a></p></div></body></html>";
|
||||
const char setup_html[] PROGMEM = "<!doctype html><html><head><title>Setup - {DEVICE}</title><link rel=\"stylesheet\" type=\"text/css\" href=\"style.css\"/><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><script type=\"text/javascript\">function toggle(name, hide) {var elm = document.getElementsByName(name)[0];if(hide) {if(!elm.classList.contains(\"hide\")) elm.classList.add(\"hide\");}else elm.classList.remove('hide');}function load() {document.querySelectorAll('input[name^=\"inv\"][name$=\"Addr\"]').forEach(elm =>{elm.addEventListener(\"keyup\", (e) =>{serial = elm.value.substring(0,4);iv = elm.name.substring(3,4);max = 0;for(i=0;i<4;i++) {toggle(\"inv\"+iv+\"ModPwr\"+i, true);toggle(\"inv\"+iv+\"ModName\"+i, true);}toggle(\"lbl\"+iv+\"ModPwr\", true);toggle(\"lbl\"+iv+\"ModName\", true);if(serial == \"1161\") max = 4;else if(serial == \"1141\") max = 2;else if(serial == \"1121\") max = 1;for(i=0;i<max;i++) {toggle(\"inv\"+iv+\"ModPwr\"+i, false);toggle(\"inv\"+iv+\"ModName\"+i, false);}if(max != 0) {toggle(\"lbl\"+iv+\"ModPwr\", false);toggle(\"lbl\"+iv+\"ModName\", false);}});evt = document.createEvent(\"HTMLEvents\");evt.initEvent(\"keyup\", false, true);elm.dispatchEvent(evt);});}</script></head><body onload=\"load()\"><h1>Setup</h1><div id=\"setup\" class=\"content\"><div id=\"content\"><p>Enter the credentials to your prefered WiFi station. After rebooting the device tries to connect with this information. </p><form method=\"post\" action=\"{IP}/save\"><p class=\"des\">WiFi</p><label for=\"ssid\">SSID</label><input type=\"text\" class=\"text\" name=\"ssid\" value=\"{SSID}\"/><label for=\"pwd\">Password</label><input type=\"password\" class=\"text\" name=\"pwd\" value=\"{PWD}\"/><p class=\"des\">Device Host Name</p><label for=\"device\">Device Name</label><input type=\"text\" class=\"text\" name=\"device\" value=\"{DEVICE}\"/><a class=\"erase\" href=\"/erase\">ERASE SETTINGS (not WiFi)</a><p class=\"des\">Inverter</p>{INVERTERS}<br/><p class=\"subdes\">General</p><label for=\"invInterval\">Interval [s]</label><input type=\"text\" class=\"text\" name=\"invInterval\" value=\"{INV_INTVL}\"/><label for=\"invRetry\">Max retries per Payload</label><input type=\"text\" class=\"text\" name=\"invRetry\" value=\"{INV_RETRIES}\"/><p class=\"des\">Pinout (Wemos)</p>{PINOUT}<p class=\"des\">Radio (NRF24L01+)</p><label for=\"rf24Power\">Amplifier Power Level</label><select name=\"rf24Power\">{RF24}</select><p class=\"des\">MQTT</p><label for=\"mqttAddr\">Broker / Server IP</label><input type=\"text\" class=\"text\" name=\"mqttAddr\" value=\"{MQTT_ADDR}\"/><label for=\"mqttPort\">Port</label><input type=\"text\" class=\"text\" name=\"mqttPort\" value=\"{MQTT_PORT}\"/><label for=\"mqttUser\">Username (optional)</label><input type=\"text\" class=\"text\" name=\"mqttUser\" value=\"{MQTT_USER}\"/><label for=\"mqttPwd\">Password (optional)</label><input type=\"text\" class=\"text\" name=\"mqttPwd\" value=\"{MQTT_PWD}\"/><label for=\"mqttTopic\">Topic</label><input type=\"text\" class=\"text\" name=\"mqttTopic\" value=\"{MQTT_TOPIC}\"/><label for=\"mqttIntvl\">Interval [s] (read-only)</label><input type=\"text\" class=\"text\" name=\"mqttIntvl\" value=\"{MQTT_INTVL}\" readonly/><p class=\"des\">Serial Console</p><label for=\"serEn\">print inverter data</label><input type=\"checkbox\" class=\"cb\" name=\"serEn\" {SER_VAL_CB}/><br/><label for=\"serDbg\">print RF24 debug</label><input type=\"checkbox\" class=\"cb\" name=\"serDbg\" {SER_DBG_CB}/><br/><label for=\"serIntvl\">Interval [s]</label><input type=\"text\" class=\"text\" name=\"serIntvl\" value=\"{SER_INTVL}\"/><p class=\"des\"> </p><label for=\"reboot\">Reboot device after successful save</label><input type=\"checkbox\" class=\"cb\" name=\"reboot\" checked/><input type=\"submit\" value=\"save\" class=\"btn\" /></form></div></div><div id=\"footer\"><p class=\"left\"><a href=\"{IP}/\">Home</a></p><p class=\"left\"><a href=\"{IP}/update\">Update Firmware</a></p><p class=\"right\">AHOY - {VERSION}</p><p class=\"right\"><a href=\"{IP}/factory\">Factory Reset</a></p><p class=\"right\"><a href=\"{IP}/reboot\">Reboot</a></p></div></body></html>";
|
||||
#endif /*__SETUP_HTML_H__*/
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#ifndef __STYLE_CSS_H__
|
||||
#define __STYLE_CSS_H__
|
||||
const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}.des {margin-top:35px;font-size:13pt;color:#006ec0;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.sh {max-width:100px !important;margin-right:10px;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:10px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:15px;padding-bottom:20px;overflow:auto;}div.ch {width:220px;min-height:350px;background-color:#006ec0;display:inline-block;margin:0 10px 15px 10px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:220px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:24px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:960px;margin-bottom:40px;}div.ts {font-size:13px;background-color:#ddd;border-top:7px solid #999;padding:7px;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}@media(max-width:500px) {div.ch .unit, div.ch-iv .unit {font-size:18px;}div.ch {width:170px;min-height:100px;}.subgrp {width:180px;}}";
|
||||
const char style_css[] PROGMEM = "h1 {margin:0;padding:20pt;font-size:22pt;color:#fff;background-color:#006ec0;display:block;text-transform:uppercase;}html, body {font-family:Arial;margin:0;padding:0;}p {text-align:justify;font-size:13pt;}.des {margin-top:35px;font-size:13pt;color:#006ec0;}.subdes {font-size:12pt;color:#006ec0;margin-left:7px;}.subsubdes {font-size:12pt;color:#006ec0;margin:0 0 7px 12px;}.hide {display:none;}a:link, a:visited {text-decoration:none;font-size:13pt;color:#006ec0;}a:hover, a:focus {color:#f00;}a.erase {background-color:#006ec0;color:#fff;padding:7px;display:inline-block;margin-top:30px;float:right;}#content {padding:15px 15px 60px 15px;}#footer {position:fixed;bottom:0px;height:45px;background-color:#006ec0;width:100%;border-top:5px solid #fff;}#footer p, #footer a {color:#fff;padding:0 7px 0 7px;font-size:10pt !important;}div.content {background-color:#fff;padding-bottom:65px;overflow:auto;}input, select {padding:7px;font-size:13pt;}input.text, select {width:70%;box-sizing:border-box;margin-bottom:10px;border:1px solid #ccc;}input.sh {max-width:150px !important;margin-right:10px;}input.btn {background-color:#006ec0;color:#fff;border:0px;float:right;margin:10px 0 30px;text-transform:uppercase;}input.cb {margin-bottom:20px;}label {width:20%;display:inline-block;font-size:12pt;padding-right:10px;margin-left:15px;}.left {float:left;}.right {float:right;}div.ch-iv {width:100%;background-color:#32b004;display:inline-block;margin-bottom:15px;padding-bottom:20px;overflow:auto;}div.ch {width:220px;min-height:350px;background-color:#006ec0;display:inline-block;margin:0 10px 15px 10px;overflow:auto;padding-bottom:20px;}div.ch .value, div.ch .info, div.ch .head, div.ch-iv .value, div.ch-iv .info, div.ch-iv .head {color:#fff;display:block;width:100%;text-align:center;}.subgrp {float:left;width:220px;}div.ch .unit, div.ch-iv .unit {font-size:19px;margin-left:10px;}div.ch .value, div.ch-iv .value {margin-top:20px;font-size:24px;}div.ch .info, div.ch-iv .info {margin-top:3px;font-size:10px;}div.ch .head {background-color:#003c80;padding:10px 0 10px 0;}div.ch-iv .head {background-color:#1c6800;padding:10px 0 10px 0;}div.iv {max-width:960px;margin-bottom:40px;}div.ts {font-size:13px;background-color:#ddd;border-top:7px solid #999;padding:7px;}#note {margin:50px 10px 10px 10px;padding-top:10px;width:100%;border-top:1px solid #bbb;}@media(max-width:500px) {div.ch .unit, div.ch-iv .unit {font-size:18px;}div.ch {width:170px;min-height:100px;}.subgrp {width:180px;}}";
|
||||
#endif /*__STYLE_CSS_H__*/
|
||||
|
|
|
@ -4,8 +4,51 @@
|
|||
<title>Setup - {DEVICE}</title>
|
||||
<link rel="stylesheet" type="text/css" href="style.css"/>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script type="text/javascript">
|
||||
function toggle(name, hide) {
|
||||
var elm = document.getElementsByName(name)[0];
|
||||
if(hide) {
|
||||
if(!elm.classList.contains("hide"))
|
||||
elm.classList.add("hide");
|
||||
}
|
||||
else
|
||||
elm.classList.remove('hide');
|
||||
}
|
||||
|
||||
function load() {
|
||||
document.querySelectorAll('input[name^="inv"][name$="Addr"]').forEach(elm => {
|
||||
elm.addEventListener("keyup", (e) => {
|
||||
serial = elm.value.substring(0,4);
|
||||
iv = elm.name.substring(3,4);
|
||||
max = 0;
|
||||
for(i=0;i<4;i++) {
|
||||
toggle("inv"+iv+"ModPwr"+i, true);
|
||||
toggle("inv"+iv+"ModName"+i, true);
|
||||
}
|
||||
toggle("lbl"+iv+"ModPwr", true);
|
||||
toggle("lbl"+iv+"ModName", true);
|
||||
|
||||
if(serial == "1161") max = 4;
|
||||
else if(serial == "1141") max = 2;
|
||||
else if(serial == "1121") max = 1;
|
||||
|
||||
for(i=0;i<max;i++) {
|
||||
toggle("inv"+iv+"ModPwr"+i, false);
|
||||
toggle("inv"+iv+"ModName"+i, false);
|
||||
}
|
||||
if(max != 0) {
|
||||
toggle("lbl"+iv+"ModPwr", false);
|
||||
toggle("lbl"+iv+"ModName", false);
|
||||
}
|
||||
});
|
||||
evt = document.createEvent("HTMLEvents");
|
||||
evt.initEvent("keyup", false, true);
|
||||
elm.dispatchEvent(evt);
|
||||
});
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<body onload="load()">
|
||||
<h1>Setup</h1>
|
||||
<div id="setup" class="content">
|
||||
<div id="content">
|
||||
|
@ -28,8 +71,10 @@
|
|||
<p class="des">Inverter</p>
|
||||
{INVERTERS}<br/>
|
||||
<p class="subdes">General</p>
|
||||
<label for="invInterval">Interval (s)</label>
|
||||
<label for="invInterval">Interval [s]</label>
|
||||
<input type="text" class="text" name="invInterval" value="{INV_INTVL}"/>
|
||||
<label for="invRetry">Max retries per Payload</label>
|
||||
<input type="text" class="text" name="invRetry" value="{INV_RETRIES}"/>
|
||||
|
||||
<p class="des">Pinout (Wemos)</p>
|
||||
{PINOUT}
|
||||
|
@ -49,20 +94,20 @@
|
|||
<input type="text" class="text" name="mqttPwd" value="{MQTT_PWD}"/>
|
||||
<label for="mqttTopic">Topic</label>
|
||||
<input type="text" class="text" name="mqttTopic" value="{MQTT_TOPIC}"/>
|
||||
<label for="mqttIntvl">Interval (s)</label>
|
||||
<input type="text" class="text" name="mqttIntvl" value="{MQTT_INTVL}"/>
|
||||
<label for="mqttIntvl">Interval [s] (read-only)</label>
|
||||
<input type="text" class="text" name="mqttIntvl" value="{MQTT_INTVL}" readonly/>
|
||||
|
||||
<p class="des">Serial Console</p>
|
||||
<label for="serEn">print inverter data</label>
|
||||
<input type="checkbox" class="cb" name="serEn" {SER_VAL_CB}/><br/>
|
||||
<label for="serDbg">print RF24 debug</label>
|
||||
<input type="checkbox" class="cb" name="serDbg" {SER_DBG_CB}/><br/>
|
||||
<label for="serIntvl">Interval (s)</label>
|
||||
<label for="serIntvl">Interval [s]</label>
|
||||
<input type="text" class="text" name="serIntvl" value="{SER_INTVL}"/>
|
||||
|
||||
<p class="des"> </p>
|
||||
<label for="reboot">Reboot device after successful save</label>
|
||||
<input type="checkbox" class="cb" name="reboot"/>
|
||||
<input type="checkbox" class="cb" name="reboot" checked/>
|
||||
<input type="submit" value="save" class="btn" />
|
||||
</form>
|
||||
</div>
|
||||
|
|
|
@ -31,6 +31,15 @@ p {
|
|||
margin-left: 7px;
|
||||
}
|
||||
|
||||
.subsubdes {
|
||||
font-size:12pt;
|
||||
color:#006ec0;
|
||||
margin: 0 0 7px 12px;
|
||||
}
|
||||
|
||||
.hide {
|
||||
display: none;
|
||||
}
|
||||
|
||||
a:link, a:visited {
|
||||
text-decoration: none;
|
||||
|
@ -89,7 +98,7 @@ input.text, select {
|
|||
}
|
||||
|
||||
input.sh {
|
||||
max-width: 100px !important;
|
||||
max-width: 150px !important;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
|
@ -111,7 +120,7 @@ label {
|
|||
display: inline-block;
|
||||
font-size: 12pt;
|
||||
padding-right: 10px;
|
||||
margin-left: 10px;
|
||||
margin-left: 15px;
|
||||
}
|
||||
|
||||
.left {
|
||||
|
|
|
@ -267,6 +267,7 @@ void Main::saveValues(bool webSend = true) {
|
|||
memset(mDeviceName, 0, DEVNAME_LEN);
|
||||
mWeb->arg("device").toCharArray(mDeviceName, DEVNAME_LEN);
|
||||
mEep->write(ADDR_DEVNAME, mDeviceName, DEVNAME_LEN);
|
||||
mEep->commit();
|
||||
|
||||
|
||||
updateCrc();
|
||||
|
@ -288,6 +289,7 @@ void Main::updateCrc(void) {
|
|||
crc = buildEEpCrc(ADDR_START, ADDR_WIFI_CRC);
|
||||
//Serial.println("new CRC: " + String(crc, HEX));
|
||||
mEep->write(ADDR_WIFI_CRC, crc);
|
||||
mEep->commit();
|
||||
}
|
||||
|
||||
|
||||
|
@ -435,7 +437,10 @@ void Main::sendNTPpacket(IPAddress& address) {
|
|||
String Main::getDateTimeStr(time_t t) {
|
||||
//DPRINTLN(F("Main::getDateTimeStr"));
|
||||
char str[20] = {0};
|
||||
sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d", year(t), month(t), day(t), hour(t), minute(t), second(t));
|
||||
if(0 == t)
|
||||
sprintf(str, "n/a");
|
||||
else
|
||||
sprintf(str, "%04d-%02d-%02d %02d:%02d:%02d", year(t), month(t), day(t), hour(t), minute(t), second(t));
|
||||
return String(str);
|
||||
}
|
||||
|
||||
|
|
|
@ -42,13 +42,22 @@ class Main {
|
|||
|
||||
inline uint16_t buildEEpCrc(uint32_t start, uint32_t length) {
|
||||
DPRINTLN(F("main.h:buildEEpCrc"));
|
||||
uint8_t buf[length];
|
||||
mEep->read(start, buf, length);
|
||||
return crc16(buf, length);
|
||||
uint8_t buf[32];
|
||||
uint16_t crc = 0xffff;
|
||||
uint8_t len;
|
||||
|
||||
while(length > 0) {
|
||||
len = (length < 32) ? length : 32;
|
||||
mEep->read(start, buf, len);
|
||||
crc = crc16(buf, len, crc);
|
||||
start += len;
|
||||
length -= len;
|
||||
}
|
||||
return crc;
|
||||
}
|
||||
|
||||
bool checkEEpCrc(uint32_t start, uint32_t length, uint32_t crcPos) {
|
||||
DPRINTLN(F("main.h:checkEEpCrc"));
|
||||
//DPRINTLN(F("main.h:checkEEpCrc"));
|
||||
uint16_t crcRd, crcCheck;
|
||||
crcCheck = buildEEpCrc(start, length);
|
||||
mEep->read(crcPos, &crcRd);
|
||||
|
@ -57,7 +66,7 @@ class Main {
|
|||
}
|
||||
|
||||
void eraseSettings(bool all = false) {
|
||||
DPRINTLN(F("main.h:eraseSettings"));
|
||||
//DPRINTLN(F("main.h:eraseSettings"));
|
||||
uint8_t buf[64] = {0};
|
||||
uint16_t addr = (all) ? ADDR_START : ADDR_START_SETTINGS;
|
||||
uint16_t end;
|
||||
|
@ -69,6 +78,7 @@ class Main {
|
|||
mEep->write(addr, buf, (end-addr));
|
||||
addr = end;
|
||||
} while(addr < (ADDR_SETTINGS_CRC + 2));
|
||||
mEep->commit();
|
||||
}
|
||||
|
||||
inline bool checkTicker(uint32_t *ticker, uint32_t interval) {
|
||||
|
|
|
@ -25,6 +25,7 @@ class mqtt {
|
|||
mAddressSet = true;
|
||||
mClient->setServer(broker, port);
|
||||
|
||||
mPort = port;
|
||||
snprintf(mUser, MQTT_USER_LEN, "%s", user);
|
||||
snprintf(mPwd, MQTT_PWD_LEN, "%s", pwd);
|
||||
snprintf(mTopic, MQTT_TOPIC_LEN, "%s", topic);
|
||||
|
@ -65,6 +66,10 @@ class mqtt {
|
|||
return mTopic;
|
||||
}
|
||||
|
||||
uint16_t getPort(void) {
|
||||
return mPort;
|
||||
}
|
||||
|
||||
void loop() {
|
||||
//DPRINT(F("m"));
|
||||
//if(!mClient->connected())
|
||||
|
@ -88,6 +93,7 @@ class mqtt {
|
|||
PubSubClient *mClient;
|
||||
|
||||
bool mAddressSet;
|
||||
uint16_t mPort;
|
||||
char mUser[MQTT_USER_LEN];
|
||||
char mPwd[MQTT_PWD_LEN];
|
||||
char mTopic[MQTT_TOPIC_LEN];
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue