Browse Source

Merge branch 'development02' of https://github.com/grindylow/ahoy into development02

pull/204/head
DanielR92 3 years ago
parent
commit
d8eb45a766
  1. 2
      .github/workflows/compile_esp8266.yml
  2. 7
      tools/esp8266/README.md
  3. 46
      tools/esp8266/app.cpp
  4. 3
      tools/esp8266/defines.h
  5. 12
      tools/esp8266/hmDefines.h
  6. 269
      tools/esp8266/hmInverter.h
  7. 3
      tools/esp8266/hmRadio.h
  8. 6
      tools/esp8266/mqtt.h
  9. 6
      tools/esp8266/scripts/getVersion.py
  10. 51
      tools/esp8266/web.cpp

2
.github/workflows/compile_esp8266.yml

@ -39,7 +39,7 @@ jobs:
working-directory: tools/esp8266/html working-directory: tools/esp8266/html
run: python convert.py run: python convert.py
- name: Run PlatformIO - name: Run PlatformIO
run: pio run -d tools/esp8266 --environment esp8266-release run: pio run -d tools/esp8266 --environment esp8266-release --environment esp32-wroom32-release
- name: rename-binary-files - name: rename-binary-files
id: rename-binary-files id: rename-binary-files
working-directory: tools/esp8266/scripts working-directory: tools/esp8266/scripts

7
tools/esp8266/README.md

@ -55,6 +55,8 @@ This code can be compiled using Visual Studio Code and **PlatformIO** Addon. The
X. configure your WiFi settings, save, repower X. configure your WiFi settings, save, repower
Y. check your router or serial console for the IP address of the module. You can try ping the configured device name as well. Y. check your router or serial console for the IP address of the module. You can try ping the configured device name as well.
! ATTENTION: If you update from a very low version to the newest, please make sure to wipe all flash data!
## pages ## pages
| page | output | | page | output |
| ---- | ------ | | ---- | ------ |
@ -80,10 +82,13 @@ The webinterface has the following abilities:
The serial console will print the converted values which were read out of the inverter(s) The serial console will print the converted values which were read out of the inverter(s)
### MQTT command to set the DTU without webinterface
[Read here](https://github.com/grindylow/ahoy/blob/development02/tools/esp8266/User_Manual.md)
## Todo's [See this post](https://github.com/grindylow/ahoy/issues/142) ## Todo's [See this post](https://github.com/grindylow/ahoy/issues/142)
- [ ] Wechsel zu AsyncWebServer und ElegantOTA für Stabilität - [ ] Wechsel zu AsyncWebServer und ElegantOTA für Stabilität
- [ ] klarer Scheduler / Task manager, der ggf. den Receive Task priorisieren kann - [x] klarer Scheduler / Task manager, der ggf. den Receive Task priorisieren kann
- [x] Device Info Kommandos (Firmware Version, etc.) über das Dashboard anzeigen [Device Information ( `0x15` `REQ_ARW_DAT_ALL` ) SubCmd Kommandos #145](https://github.com/grindylow/ahoy/issues/145) - [x] Device Info Kommandos (Firmware Version, etc.) über das Dashboard anzeigen [Device Information ( `0x15` `REQ_ARW_DAT_ALL` ) SubCmd Kommandos #145](https://github.com/grindylow/ahoy/issues/145)
- [ ] AlarmData & AlarmUpdate Parsen und auf eigener Seite darstellen - [ ] AlarmData & AlarmUpdate Parsen und auf eigener Seite darstellen

46
tools/esp8266/app.cpp

@ -164,6 +164,7 @@ void app::loop(void) {
if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff) && mMqttActive) { if((++mMqttTicker >= mMqttInterval) && (mMqttInterval != 0xffff) && mMqttActive) {
mMqttTicker = 0; mMqttTicker = 0;
mMqtt.isConnected(true); // really needed? See comment from HorstG-57 #176 mMqtt.isConnected(true); // really needed? See comment from HorstG-57 #176
/*
char topic[30], val[10]; char topic[30], val[10];
for(uint8_t id = 0; id < mSys->getNumInverters(); id++) { for(uint8_t id = 0; id < mSys->getNumInverters(); id++) {
Inverter<> *iv = mSys->getInverterByPos(id); Inverter<> *iv = mSys->getInverterByPos(id);
@ -178,6 +179,8 @@ void app::loop(void) {
} }
} }
} }
*/
char val[10];
snprintf(val, 10, "%ld", millis()/1000); snprintf(val, 10, "%ld", millis()/1000);
#ifndef __MQTT_NO_DISCOVERCONFIG__ #ifndef __MQTT_NO_DISCOVERCONFIG__
@ -243,6 +246,10 @@ void app::loop(void) {
if(!mPayload[iv->id].complete) { if(!mPayload[iv->id].complete) {
mRxFailed++; mRxFailed++;
iv->setQueuedCmdFinished(); // command failed
if(mConfig.serialDebug) {
DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout"));
}
if(mConfig.serialDebug) { if(mConfig.serialDebug) {
DPRINT(DBG_INFO, F("Inverter #") + String(iv->id) + " "); DPRINT(DBG_INFO, F("Inverter #") + String(iv->id) + " ");
DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload[iv->id].retransmits) + ")"); DPRINTLN(DBG_INFO, F("no Payload received! (retransmits: ") + String(mPayload[iv->id].retransmits) + ")");
@ -371,10 +378,33 @@ void app::processPayload(bool retransmit) {
} }
iv->doCalculations(); // cmd value decides which parser is used to decode payload iv->doCalculations(); // cmd value decides which parser is used to decode payload
iv->setQueuedCmdFinished();
// MQTT send out
if(mMqttActive) {
char topic[30], val[10];
for (uint8_t id = 0; id < mSys->getNumInverters(); id++)
{
Inverter<> *iv = mSys->getInverterByPos(id);
if (NULL != iv)
{
if (iv->isAvailable(mTimestamp))
{
for (uint8_t i = 0; i < iv->listLen; i++)
{
snprintf(topic, 30, "%s/ch%d/%s", iv->name, iv->assign[i].ch, fields[iv->assign[i].fieldId]);
snprintf(val, 10, "%.3f", iv->getValue(i));
mMqtt.sendMsg(topic, val);
yield();
}
}
}
}
}
#ifdef __MQTT_AFTER_RX__ #ifdef __MQTT_AFTER_RX__
doMQTT = true; doMQTT = true;
#endif #endif
iv->setQueuedCmdFinished();
} }
} }
yield(); yield();
@ -555,18 +585,12 @@ String app::getLiveData(void)
modHtml += F("<div class=\"iv\">" modHtml += F("<div class=\"iv\">"
"<div class=\"ch-iv\"><span class=\"head\">") + "<div class=\"ch-iv\"><span class=\"head\">") +
String(iv->name) + F(" Limit ") + String(iv->actPowerLimit); String(iv->name) + F(" Limit ") + String(iv->actPowerLimit)
if (true) + F("% | last Alarm: ") + iv->lastAlarmMsg + F("</span>");
{ // live Power Limit from inverter is always in %
modHtml += F(" %</span>");
}
else
{
modHtml += F(" W</span>");
}
uint8_t list[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PCT, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_PRA, FLD_ALARM_MES_ID}; uint8_t list[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PCT, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_PRA, FLD_ALARM_MES_ID};
for (uint8_t fld = 0; fld < 12; fld++) for (uint8_t fld = 0; fld < 11; fld++)
{ {
pos = (iv->getPosByChFld(CH0, list[fld])); pos = (iv->getPosByChFld(CH0, list[fld]));
if (0xff != pos) if (0xff != pos)

3
tools/esp8266/defines.h

@ -13,7 +13,7 @@
//------------------------------------- //-------------------------------------
#define VERSION_MAJOR 0 #define VERSION_MAJOR 0
#define VERSION_MINOR 5 #define VERSION_MINOR 5
#define VERSION_PATCH 15 #define VERSION_PATCH 16
//------------------------------------- //-------------------------------------
@ -104,6 +104,7 @@ typedef enum { // ToDo: to be verified by field tests
#define MQTT_PORT_LEN 2 // uint16_t #define MQTT_PORT_LEN 2 // uint16_t
#define MQTT_DISCOVERY_PREFIX "homeassistant" #define MQTT_DISCOVERY_PREFIX "homeassistant"
#define MQTT_MAX_PACKET_SIZE 384 #define MQTT_MAX_PACKET_SIZE 384
#define MQTT_RECONNECT_DELAY 5000
#define SER_ENABLE_LEN 1 // uint8_t #define SER_ENABLE_LEN 1 // uint8_t
#define SER_DEBUG_LEN 1 // uint8_t #define SER_DEBUG_LEN 1 // uint8_t

12
tools/esp8266/hmDefines.h

@ -23,9 +23,13 @@ const char* const units[] = {"V", "A", "W", "Wh", "kWh", "Hz", "°C", "%","VAr",
// field types // field types
enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT,
FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_T, FLD_PCT, FLD_EFF, FLD_IRR, FLD_PRA,FLD_ALARM_MES_ID,FLD_FW_VERSION,FLD_FW_BUILD_YEAR,FLD_FW_BUILD_MONTH_DAY,FLD_HW_ID,FLD_ACT_PWR_LIMIT}; FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_T, FLD_PCT, FLD_EFF,
FLD_IRR, FLD_PRA,FLD_ALARM_MES_ID,FLD_FW_VERSION,FLD_FW_BUILD_YEAR,
FLD_FW_BUILD_MONTH_DAY,FLD_HW_ID,FLD_ACT_PWR_LIMIT,FLD_LAST_ALARM_CODE};
const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal", const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal",
"U_AC", "I_AC", "P_AC", "Freq", "Temp", "Pct", "Efficiency", "Irradiation","P_ACr","ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","HWPartId","PowerLimit"}; "U_AC", "I_AC", "P_AC", "Freq", "Temp", "Pct", "Efficiency", "Irradiation","P_ACr",
"ALARM_MES_ID","FWVersion","FWBuildYear","FWBuildMonthDay","HWPartId","PowerLimit","LastAlarmCode"};
// mqtt discovery device classes // mqtt discovery device classes
enum {DEVICE_CLS_NONE = 0, DEVICE_CLS_CURRENT, DEVICE_CLS_ENERGY, DEVICE_CLS_PWR, DEVICE_CLS_VOLTAGE, DEVICE_CLS_FREQ, DEVICE_CLS_TEMP}; enum {DEVICE_CLS_NONE = 0, DEVICE_CLS_CURRENT, DEVICE_CLS_ENERGY, DEVICE_CLS_PWR, DEVICE_CLS_VOLTAGE, DEVICE_CLS_FREQ, DEVICE_CLS_TEMP};
@ -97,6 +101,10 @@ const byteAssign_t SystemConfigParaAssignment[] = {
}; };
#define HMSYSTEM_LIST_LEN (sizeof(SystemConfigParaAssignment) / sizeof(byteAssign_t)) #define HMSYSTEM_LIST_LEN (sizeof(SystemConfigParaAssignment) / sizeof(byteAssign_t))
const byteAssign_t AlarmDataAssignment[] = {
{ FLD_LAST_ALARM_CODE, UNIT_NONE, CH0, 0, 2, 1 }
};
#define HMALARMDATA_LIST_LEN (sizeof(AlarmDataAssignment) / sizeof(byteAssign_t))

269
tools/esp8266/hmInverter.h

@ -115,6 +115,7 @@ class Inverter {
RECORDTYPE *record; // pointer for values RECORDTYPE *record; // pointer for values
uint16_t chMaxPwr[4]; // maximum power of the modules (Wp) uint16_t chMaxPwr[4]; // maximum power of the modules (Wp)
char chName[4][MAX_NAME_LENGTH]; // human readable name for channel char chName[4][MAX_NAME_LENGTH]; // human readable name for channel
String lastAlarmMsg;
bool initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null) bool initialized; // needed to check if the inverter was correctly added (ESP32 specific - union types are never null)
Inverter() { Inverter() {
@ -126,6 +127,8 @@ class Inverter {
devControlCmd = 0xff; devControlCmd = 0xff;
initialized = false; initialized = false;
fwVersion = 0; fwVersion = 0;
lastAlarmMsg = "nothing";
alarmMesIndex = 0;
} }
~Inverter() { ~Inverter() {
@ -141,7 +144,8 @@ class Inverter {
void setQueuedCmdFinished(){ void setQueuedCmdFinished(){
if (!_commandQueue.empty()){ if (!_commandQueue.empty()){
_commandQueue.pop(); // Will destroy CommandAbstract Class Object (?) // Will destroy CommandAbstract Class Object (?)
_commandQueue.pop();
} }
} }
@ -150,7 +154,14 @@ class Inverter {
if (_commandQueue.empty()){ if (_commandQueue.empty()){
// Fill with default commands // Fill with default commands
enqueCommand<InfoCommand>(RealTimeRunData_Debug); enqueCommand<InfoCommand>(RealTimeRunData_Debug);
//enqueCommand<InfoCommand>(SystemConfigPara); if (fwVersion == 0)
{ // info needed maybe after "one nigth" (=> DC>0 to DC=0 and to DC>0) or reboot
enqueCommand<InfoCommand>(InverterDevInform_All);
}
if (actPowerLimit == 0xffff)
{ // info needed maybe after "one nigth" (=> DC>0 to DC=0 and to DC>0) or reboot
enqueCommand<InfoCommand>(SystemConfigPara);
}
} }
return _commandQueue.front().get()->getCmd(); return _commandQueue.front().get()->getCmd();
} }
@ -164,8 +175,6 @@ class Inverter {
memset(name, 0, MAX_NAME_LENGTH); memset(name, 0, MAX_NAME_LENGTH);
memset(chName, 0, MAX_NAME_LENGTH * 4); memset(chName, 0, MAX_NAME_LENGTH * 4);
memset(record, 0, sizeof(RECORDTYPE) * listLen); memset(record, 0, sizeof(RECORDTYPE) * listLen);
enqueCommand<InfoCommand>(InverterDevInform_All);
enqueCommand<InfoCommand>(SystemConfigPara);
initialized = true; initialized = true;
} }
@ -206,12 +215,25 @@ class Inverter {
val <<= 8; val <<= 8;
val |= buf[ptr]; val |= buf[ptr];
} while(++ptr != end); } while(++ptr != end);
if ((RECORDTYPE)(div) > 1){
record[pos] = (RECORDTYPE)(val) / (RECORDTYPE)(div); record[pos] = (RECORDTYPE)(val) / (RECORDTYPE)(div);
} }
else {
record[pos] = (RECORDTYPE)(val);
}
}
if (cmd == RealTimeRunData_Debug) { if (cmd == RealTimeRunData_Debug) {
// get last alarm message index and save it in the inverter object // get last alarm message index and save it in the inverter object
if (getPosByChFld(0, FLD_ALARM_MES_ID) == pos){ if (getPosByChFld(0, FLD_ALARM_MES_ID) == pos){
if (alarmMesIndex < record[pos]){
alarmMesIndex = record[pos]; alarmMesIndex = record[pos];
//enqueCommand<InfoCommand>(AlarmUpdate); // What is the function of AlarmUpdate?
enqueCommand<InfoCommand>(AlarmData);
}
else {
alarmMesIndex = record[pos]; // no change
}
} }
} }
if (cmd == InverterDevInform_All) { if (cmd == InverterDevInform_All) {
@ -228,6 +250,11 @@ class Inverter {
DPRINT(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit)); DPRINT(DBG_DEBUG, F("Inverter actual power limit: ") + String(actPowerLimit));
} }
} }
if (cmd == AlarmData){
if (getPosByChFld(0, FLD_LAST_ALARM_CODE) == pos){
lastAlarmMsg = getAlarmStr(record[pos]);
}
}
} }
void power_on() { void power_on() {
@ -275,17 +302,16 @@ class Inverter {
return false; return false;
} }
uint32_t getLastTs(void) { uint32_t getLastTs(void)
{
DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getLastTs")); DPRINTLN(DBG_VERBOSE, F("hmInverter.h:getLastTs"));
return ts; return ts;
} }
void getAssignment() { void getAssignment()
DPRINTLN(DBG_DEBUG, F("hmInverter.h:getAssignment"));
uint8_t cmd = getQueuedCmd();
switch (cmd)
{ {
case RealTimeRunData_Debug: DPRINTLN(DBG_DEBUG, F("hmInverter.h:getAssignment"));
// Default assignment;
if (INV_TYPE_1CH == type) if (INV_TYPE_1CH == type)
{ {
listLen = (uint8_t)(HM1CH_LIST_LEN); listLen = (uint8_t)(HM1CH_LIST_LEN);
@ -310,6 +336,12 @@ class Inverter {
channels = 0; channels = 0;
assign = NULL; assign = NULL;
} }
uint8_t cmd = getQueuedCmd();
switch (cmd)
{
case RealTimeRunData_Debug:
// Do nothing will use default
break; break;
case InverterDevInform_All: case InverterDevInform_All:
listLen = (uint8_t)(HMINFO_LIST_LEN); listLen = (uint8_t)(HMINFO_LIST_LEN);
@ -319,10 +351,227 @@ class Inverter {
listLen = (uint8_t)(HMSYSTEM_LIST_LEN); listLen = (uint8_t)(HMSYSTEM_LIST_LEN);
assign = (byteAssign_t *)SystemConfigParaAssignment; assign = (byteAssign_t *)SystemConfigParaAssignment;
break; break;
case AlarmData:
listLen = (uint8_t)(HMALARMDATA_LIST_LEN);
assign = (byteAssign_t *)AlarmDataAssignment;
break;
default: default:
DPRINTLN(DBG_INFO, "Parser not implemented"); DPRINTLN(DBG_INFO, "Parser not implemented");
} }
} }
String getAlarmStr(u_int16_t alarmCode)
{
switch (alarmCode)
{
case 1:
return String(F("Inverter start"));
break;
case 2:
return String(F("DTU command failed"));
break;
case 121:
return String(F("Over temperature protection"));
break;
case 125:
return String(F("Grid configuration parameter error"));
break;
case 126:
return String(F("Software error code 126"));
break;
case 127:
return String(F("Firmware error"));
break;
case 128:
return String(F("Software error code 128"));
break;
case 129:
return String(F("Software error code 129"));
break;
case 130:
return String(F("Offline"));
break;
case 141:
return String(F("Grid overvoltage"));
break;
case 142:
return String(F("Average grid overvoltage"));
break;
case 143:
return String(F("Grid undervoltage"));
break;
case 144:
return String(F("Grid overfrequency"));
break;
case 145:
return String(F("Grid underfrequency"));
break;
case 146:
return String(F("Rapid grid frequency change"));
break;
case 147:
return String(F("Power grid outage"));
break;
case 148:
return String(F("Grid disconnection"));
break;
case 149:
return String(F("Island detected"));
break;
case 205:
return String(F("Input port 1 & 2 overvoltage"));
break;
case 206:
return String(F("Input port 3 & 4 overvoltage"));
break;
case 207:
return String(F("Input port 1 & 2 undervoltage"));
break;
case 208:
return String(F("Input port 3 & 4 undervoltage"));
break;
case 209:
return String(F("Port 1 no input"));
break;
case 210:
return String(F("Port 2 no input"));
break;
case 211:
return String(F("Port 3 no input"));
break;
case 212:
return String(F("Port 4 no input"));
break;
case 213:
return String(F("PV-1 & PV-2 abnormal wiring"));
break;
case 214:
return String(F("PV-3 & PV-4 abnormal wiring"));
break;
case 215:
return String(F("PV-1 Input overvoltage"));
break;
case 216:
return String(F("PV-1 Input undervoltage"));
break;
case 217:
return String(F("PV-2 Input overvoltage"));
break;
case 218:
return String(F("PV-2 Input undervoltage"));
break;
case 219:
return String(F("PV-3 Input overvoltage"));
break;
case 220:
return String(F("PV-3 Input undervoltage"));
break;
case 221:
return String(F("PV-4 Input overvoltage"));
break;
case 222:
return String(F("PV-4 Input undervoltage"));
break;
case 301:
return String(F("Hardware error code 301"));
break;
case 302:
return String(F("Hardware error code 302"));
break;
case 303:
return String(F("Hardware error code 303"));
break;
case 304:
return String(F("Hardware error code 304"));
break;
case 305:
return String(F("Hardware error code 305"));
break;
case 306:
return String(F("Hardware error code 306"));
break;
case 307:
return String(F("Hardware error code 307"));
break;
case 308:
return String(F("Hardware error code 308"));
break;
case 309:
return String(F("Hardware error code 309"));
break;
case 310:
return String(F("Hardware error code 310"));
break;
case 311:
return String(F("Hardware error code 311"));
break;
case 312:
return String(F("Hardware error code 312"));
break;
case 313:
return String(F("Hardware error code 313"));
break;
case 314:
return String(F("Hardware error code 314"));
break;
case 5041:
return String(F("Error code-04 Port 1"));
break;
case 5042:
return String(F("Error code-04 Port 2"));
break;
case 5043:
return String(F("Error code-04 Port 3"));
break;
case 5044:
return String(F("Error code-04 Port 4"));
break;
case 5051:
return String(F("PV Input 1 Overvoltage/Undervoltage"));
break;
case 5052:
return String(F("PV Input 2 Overvoltage/Undervoltage"));
break;
case 5053:
return String(F("PV Input 3 Overvoltage/Undervoltage"));
break;
case 5054:
return String(F("PV Input 4 Overvoltage/Undervoltage"));
break;
case 5060:
return String(F("Abnormal bias"));
break;
case 5070:
return String(F("Over temperature protection"));
break;
case 5080:
return String(F("Grid Overvoltage/Undervoltage"));
break;
case 5090:
return String(F("Grid Overfrequency/Underfrequency"));
break;
case 5100:
return String(F("Island detected"));
break;
case 5120:
return String(F("EEPROM reading and writing error"));
break;
case 5150:
return String(F("10 min value grid overvoltage"));
break;
case 5200:
return String(F("Firmware error"));
break;
case 8310:
return String(F("Shut down"));
break;
case 9000:
return String(F("Microinverter is suspected of being stolen"));
break;
default:
return String(F("Unknown"));
break;
}
}
private: private:
std::queue<std::shared_ptr<CommandAbstract>> _commandQueue; std::queue<std::shared_ptr<CommandAbstract>> _commandQueue;

3
tools/esp8266/hmRadio.h

@ -192,10 +192,9 @@ class HmRadio {
mTxBuf[10] = cmd; // cid mTxBuf[10] = cmd; // cid
mTxBuf[11] = 0x00; mTxBuf[11] = 0x00;
CP_U32_LittleEndian(&mTxBuf[12], ts); CP_U32_LittleEndian(&mTxBuf[12], ts);
if (cmd == RealTimeRunData_Debug || cmd == AlarmData || cmd == AlarmUpdate ){ if (cmd == RealTimeRunData_Debug || cmd == AlarmData ){
mTxBuf[18] = (alarmMesId >> 8) & 0xff; mTxBuf[18] = (alarmMesId >> 8) & 0xff;
mTxBuf[19] = (alarmMesId ) & 0xff; mTxBuf[19] = (alarmMesId ) & 0xff;
//mTxBuf[19] = 0x05; // ToDo: Shall be the last received Alarm Index Number
} else { } else {
mTxBuf[18] = 0x00; mTxBuf[18] = 0x00;
mTxBuf[19] = 0x00; mTxBuf[19] = 0x00;

6
tools/esp8266/mqtt.h

@ -85,7 +85,8 @@ class mqtt {
#endif #endif
boolean resub = false; boolean resub = false;
if(!mClient->connected()) { if(!mClient->connected() && (millis() - lastReconnect) > MQTT_RECONNECT_DELAY ) {
lastReconnect = millis();
if(strlen(mDevName) > 0) { if(strlen(mDevName) > 0) {
// der Server und der Port müssen neu gesetzt werden, // der Server und der Port müssen neu gesetzt werden,
// da ein MQTT_CONNECTION_LOST -3 die Werte zerstört hat. // da ein MQTT_CONNECTION_LOST -3 die Werte zerstört hat.
@ -95,7 +96,6 @@ class mqtt {
resub = mClient->connect(mDevName, mCfg->user, mCfg->pwd); resub = mClient->connect(mDevName, mCfg->user, mCfg->pwd);
else else
resub = mClient->connect(mDevName); resub = mClient->connect(mDevName);
}
// ein Subscribe ist nur nach einem connect notwendig // ein Subscribe ist nur nach einem connect notwendig
if(resub) { if(resub) {
char topic[MQTT_TOPIC_LEN + 13 ]; // "/devcontrol/#" --> + 6 byte char topic[MQTT_TOPIC_LEN + 13 ]; // "/devcontrol/#" --> + 6 byte
@ -106,6 +106,7 @@ class mqtt {
} }
} }
} }
}
WiFiClient mEspClient; WiFiClient mEspClient;
PubSubClient *mClient; PubSubClient *mClient;
@ -113,6 +114,7 @@ class mqtt {
bool mAddressSet; bool mAddressSet;
mqttConfig_t *mCfg; mqttConfig_t *mCfg;
char mDevName[DEVNAME_LEN]; char mDevName[DEVNAME_LEN];
unsigned long lastReconnect = 0;
}; };
#endif /*__MQTT_H_*/ #endif /*__MQTT_H_*/

6
tools/esp8266/scripts/getVersion.py

@ -24,6 +24,12 @@ def readVersion(path, infile):
src = path + ".pio/build/esp8266-release/firmware.bin" src = path + ".pio/build/esp8266-release/firmware.bin"
dst = path + ".pio/build/out/" + versionout dst = path + ".pio/build/out/" + versionout
os.rename(src, dst) os.rename(src, dst)
versionout = version[:-1] + "_esp32_" + sha + ".bin"
src = path + ".pio/build/esp32-wroom32-release/firmware.bin"
dst = path + ".pio/build/out/" + versionout
os.rename(src, dst)
print("::set-output name=name::" + versionnumber[:-1] ) print("::set-output name=name::" + versionnumber[:-1] )

51
tools/esp8266/web.cpp

@ -16,6 +16,21 @@
#include "html/h/setup_html.h" #include "html/h/setup_html.h"
#include "html/h/visualization_html.h" #include "html/h/visualization_html.h"
const uint16_t pwrLimitOptionValues[] {
AbsolutNonPersistent,
AbsolutPersistent,
RelativNonPersistent,
RelativPersistent
};
const char* const pwrLimitOptions[] {
"absolute in Watt non persistent",
"absolute in Watt persistent",
"relativ in percent non persistent",
"relativ in percent persistent"
};
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
web::web(app *main, sysConfig_t *sysCfg, config_t *config, char version[]) { web::web(app *main, sysConfig_t *sysCfg, config_t *config, char version[]) {
mMain = main; mMain = main;
@ -204,21 +219,16 @@ void web::showSetup(void) {
inv += F("\"/ maxlength=\"") + String(6) + "\">"; inv += F("\"/ maxlength=\"") + String(6) + "\">";
inv += F("<label for=\"inv") + String(i) + F("ActivePowerLimitConType\">Active Power Limit Control Type</label>"); inv += F("<label for=\"inv") + String(i) + F("ActivePowerLimitConType\">Active Power Limit Control Type</label>");
inv += F("<select name=\"inv") + String(i); inv += F("<select name=\"inv") + String(i) + F("PowerLimitControl\">");
// UGLY! But I do not know it a better way for(uint8_t j = 0; j < 4; j++) {
// ToDo: Need Cookies, IndexDB or PWA for that or in general client browser storage inv += F("<option value=\"") + String(pwrLimitOptionValues[j]) + F("\"");
if(NULL != iv) { if(NULL != iv) {
if(iv->powerLimit[1] == AbsolutNonPersistent) if(iv->powerLimit[1] == pwrLimitOptionValues[j])
inv += F("PowerLimitControl\"><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>"); inv += F(" selected");
if(iv->powerLimit[1] == RelativNonPersistent) }
inv += F("PowerLimitControl\"><option value=\"1\">relativ in percent non persistent</option><option value=\"0\">absolute in Watt non persistent</option><option value=\"256\">absolute in Watt persistent</option><option value=\"257\">relativ in percent persistent</option></select>"); inv += F(">") + String(pwrLimitOptions[j]) + F("</option>");
if(iv->powerLimit[1] == AbsolutPersistent) }
inv += F("PowerLimitControl\"><option value=\"256\">absolute in Watt persistent</option><option value=\"1\">relativ in percent non persistent</option><option value=\"0\">absolute in Watt non persistent</option><option value=\"257\">relativ in percent persistent</option></select>"); inv += F("</select>");
if(iv->powerLimit[1] == RelativPersistent)
inv += F("PowerLimitControl\"><option value=\"257\">relativ in percent persistent</option><option value=\"256\">absolute in Watt persistent</option><option value=\"1\">relativ in percent non persistent</option><option value=\"0\">absolute in Watt non persistent</option></select>");
} else
inv += F("PowerLimitControl\"><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>");
// UGLY! But I do not know it a better way --//
inv += F("<label for=\"inv") + String(i) + F("ModPwr0\" name=\"lbl") + String(i); inv += F("<label for=\"inv") + String(i) + F("ModPwr0\" name=\"lbl") + String(i);
inv += F("ModPwr\">Max Module Power (Wp)</label><div class=\"modpwr\">"); inv += F("ModPwr\">Max Module Power (Wp)</label><div class=\"modpwr\">");
@ -460,10 +470,11 @@ void web::showWebApi(void)
if (response["tx_request"] == (uint8_t)TX_REQ_INFO) if (response["tx_request"] == (uint8_t)TX_REQ_INFO)
{ {
// if the AlarmData is requested set the Alarm Index to the requested one // if the AlarmData is requested set the Alarm Index to the requested one
if (cmd == AlarmData){ if (cmd == AlarmData || cmd == AlarmUpdate){
// set the AlarmMesIndex for the request from user input
iv->alarmMesIndex = response["payload"]; iv->alarmMesIndex = response["payload"];
} }
DPRINTLN(DBG_INFO, F("Will make tx-request 0x15 with subcmd ") + String(cmd) + F(" and payload ") + String(response["payload"])); DPRINTLN(DBG_INFO, F("Will make tx-request 0x15 with subcmd ") + String(cmd) + F(" and payload ") + String((uint16_t) response["payload"]));
// process payload from web request corresponding to the cmd // process payload from web request corresponding to the cmd
iv->enqueCommand<InfoCommand>(cmd); iv->enqueCommand<InfoCommand>(cmd);
} }
@ -498,6 +509,14 @@ void web::showWebApi(void)
iv->devControlRequest = true; // queue it in the request loop iv->devControlRequest = true; // queue it in the request loop
} }
} }
if (response["cmd"] == (uint8_t)TurnOff){
iv->devControlCmd = TurnOff;
iv->devControlRequest = true; // queue it in the request loop
}
if (response["cmd"] == (uint8_t)TurnOn){
iv->devControlCmd = TurnOn;
iv->devControlRequest = true; // queue it in the request loop
}
} }
} }
mWeb->send(200, "text/json", "{success:true}"); mWeb->send(200, "text/json", "{success:true}");

Loading…
Cancel
Save