Browse Source

Merge pull request #361 from DanielR92/dev03

app.cpp make nicer readable and shorten if statements
pull/373/head
Lukas Pusch 2 years ago
committed by GitHub
parent
commit
2af55cb685
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 23
      tools/esp8266/.vscode/settings.json
  2. 458
      tools/esp8266/app.cpp
  3. 2
      tools/esp8266/platformio.ini
  4. 6
      tools/rpi/hoymiles/__main__.py

23
tools/esp8266/.vscode/settings.json

@ -0,0 +1,23 @@
// Place your settings in this file to overwrite default and user settings.
{
// identify that settings is loaded
"workbench.colorCustomizations": {
"editorLineNumber.foreground": "#00ff00"
},
"editor.wordWrap": "off",
"files.eol" : "\n",
"files.trimTrailingWhitespace" : true,
"diffEditor.ignoreTrimWhitespace": true,
"files.autoSave": "afterDelay",
"editor.tabSize": 4,
"editor.insertSpaces": true,
// `editor.tabSize` and `editor.insertSpaces` will be detected based on the file contents.
// Set to false to keep the values you've explicitly set, above.
"editor.detectIndentation": false,
// https://clang.llvm.org/docs/ClangFormatStyleOptions.html
"C_Cpp.clang_format_fallbackStyle": "{ BasedOnStyle: Google, IndentWidth: 4, ColumnLimit: 0}",
}

458
tools/esp8266/app.cpp

@ -4,13 +4,13 @@
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
#if defined(ESP32) && defined(F) #if defined(ESP32) && defined(F)
#undef F #undef F
#define F(sl) (sl) #define F(sl) (sl)
#endif #endif
#include "app.h" #include "app.h"
#include <ArduinoJson.h>
#include <ArduinoJson.h>
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
app::app() { app::app() {
@ -27,20 +27,19 @@ app::app() {
mShouldReboot = false; mShouldReboot = false;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::setup(uint32_t timeout) { void app::setup(uint32_t timeout) {
DPRINTLN(DBG_VERBOSE, F("app::setup")); DPRINTLN(DBG_VERBOSE, F("app::setup"));
mWifiSettingsValid = checkEEpCrc(ADDR_START, ADDR_WIFI_CRC, ADDR_WIFI_CRC); mWifiSettingsValid = checkEEpCrc(ADDR_START, ADDR_WIFI_CRC, ADDR_WIFI_CRC);
mSettingsValid = checkEEpCrc(ADDR_START_SETTINGS, ((ADDR_NEXT)-(ADDR_START_SETTINGS)), ADDR_SETTINGS_CRC); mSettingsValid = checkEEpCrc(ADDR_START_SETTINGS, ((ADDR_NEXT) - (ADDR_START_SETTINGS)), ADDR_SETTINGS_CRC);
loadEEpconfig(); loadEEpconfig();
mWifi->setup(timeout, mWifiSettingsValid); mWifi->setup(timeout, mWifiSettingsValid);
#ifndef AP_ONLY #ifndef AP_ONLY
setupMqtt(); setupMqtt();
#endif #endif
mSys->setup(mConfig.amplifierPower, mConfig.pinIrq, mConfig.pinCe, mConfig.pinCs); mSys->setup(mConfig.amplifierPower, mConfig.pinIrq, mConfig.pinCe, mConfig.pinCs);
mWebInst = new web(this, &mSysConfig, &mConfig, &mStat, mVersion); mWebInst = new web(this, &mSysConfig, &mConfig, &mStat, mVersion);
@ -54,70 +53,71 @@ void app::loop(void) {
bool apActive = mWifi->loop(); bool apActive = mWifi->loop();
mWebInst->loop(); mWebInst->loop();
if(millis() - mPrevMillis >= 1000) { if (millis() - mPrevMillis >= 1000) {
mPrevMillis += 1000; mPrevMillis += 1000;
mUptimeSecs++; mUptimeSecs++;
if(0 != mUtcTimestamp) if (0 != mUtcTimestamp)
mUtcTimestamp++; mUtcTimestamp++;
} }
if(checkTicker(&mNtpRefreshTicker, mNtpRefreshInterval)) { if (checkTicker(&mNtpRefreshTicker, mNtpRefreshInterval)) {
if(!apActive) if (!apActive)
mUpdateNtp = true; mUpdateNtp = true;
} }
if(mUpdateNtp) { if (mUpdateNtp) {
mUpdateNtp = false; mUpdateNtp = false;
mUtcTimestamp = mWifi->getNtpTime(); mUtcTimestamp = mWifi->getNtpTime();
DPRINTLN(DBG_INFO, F("[NTP]: ") + getDateTimeStr(mUtcTimestamp) + F(" UTC")); DPRINTLN(DBG_INFO, F("[NTP]: ") + getDateTimeStr(mUtcTimestamp) + F(" UTC"));
} }
if(mFlagSendDiscoveryConfig) { if (mFlagSendDiscoveryConfig) {
mFlagSendDiscoveryConfig = false; mFlagSendDiscoveryConfig = false;
sendMqttDiscoveryConfig(); sendMqttDiscoveryConfig();
} }
if(mShouldReboot) { if (mShouldReboot) {
DPRINTLN(DBG_INFO, F("Rebooting...")); DPRINTLN(DBG_INFO, F("Rebooting..."));
ESP.restart(); ESP.restart();
} }
mSys->Radio.loop(); mSys->Radio.loop();
yield(); yield();
if(checkTicker(&mRxTicker, 5)) { if (checkTicker(&mRxTicker, 5)) {
bool rxRdy = mSys->Radio.switchRxCh(); bool rxRdy = mSys->Radio.switchRxCh();
if(!mSys->BufCtrl.empty()) { if (!mSys->BufCtrl.empty()) {
uint8_t len; uint8_t len;
packet_t *p = mSys->BufCtrl.getBack(); packet_t *p = mSys->BufCtrl.getBack();
if(mSys->Radio.checkPaketCrc(p->packet, &len, p->rxCh)) { if (mSys->Radio.checkPaketCrc(p->packet, &len, p->rxCh)) {
// process buffer only on first occurrence // process buffer only on first occurrence
if(mConfig.serialDebug) { if (mConfig.serialDebug) {
DPRINT(DBG_INFO, "RX " + String(len) + "B Ch" + String(p->rxCh) + " | "); DPRINT(DBG_INFO, "RX " + String(len) + "B Ch" + String(p->rxCh) + " | ");
mSys->Radio.dumpBuf(NULL, p->packet, len); mSys->Radio.dumpBuf(NULL, p->packet, len);
} }
mStat.frmCnt++; mStat.frmCnt++;
if(0 != len) { if (0 != len) {
Inverter<> *iv = mSys->findInverter(&p->packet[1]); Inverter<> *iv = mSys->findInverter(&p->packet[1]);
if((NULL != iv) && (p->packet[0] == (TX_REQ_INFO + 0x80))) { // response from get information command if ((NULL != iv) && (p->packet[0] == (TX_REQ_INFO + ALL_FRAMES))) // response from get information command
{
mPayload[iv->id].txId = p->packet[0]; mPayload[iv->id].txId = p->packet[0];
DPRINTLN(DBG_DEBUG, F("Response from info request received")); DPRINTLN(DBG_DEBUG, F("Response from info request received"));
uint8_t *pid = &p->packet[9]; uint8_t *pid = &p->packet[9];
if (*pid == 0x00) if (*pid == 0x00) {
DPRINT(DBG_DEBUG, "fragment number zero received and ignored"); DPRINT(DBG_DEBUG, F("fragment number zero received and ignored"));
else { } else {
DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX)); DPRINTLN(DBG_DEBUG, "PID: 0x" + String(*pid, HEX));
if ((*pid & 0x7F) < 5) { if ((*pid & 0x7F) < 5) {
memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], len - 11); memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], len - 11);
mPayload[iv->id].len[(*pid & 0x7F) - 1] = len - 11; mPayload[iv->id].len[(*pid & 0x7F) - 1] = len - 11;
} }
if ((*pid & 0x80) == 0x80) { if ((*pid & ALL_FRAMES) == ALL_FRAMES) {
// Last packet // Last packet
if ((*pid & 0x7f) > mPayload[iv->id].maxPackId) { if ((*pid & 0x7f) > mPayload[iv->id].maxPackId) {
mPayload[iv->id].maxPackId = (*pid & 0x7f); mPayload[iv->id].maxPackId = (*pid & 0x7f);
@ -127,15 +127,16 @@ void app::loop(void) {
} }
} }
} }
if((NULL != iv) && (p->packet[0] == (TX_REQ_DEVCONTROL + 0x80))) { // response from dev control command if ((NULL != iv) && (p->packet[0] == (TX_REQ_DEVCONTROL + ALL_FRAMES))) // response from dev control command
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"));
mPayload[iv->id].txId = p->packet[0];
iv->devControlRequest = false; iv->devControlRequest = false;
if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) { if ((p->packet[12] == ActivePowerContr) && (p->packet[13] == 0x00)) {
if (p->packet[10] == 0x00 && p->packet[11] == 0x00) String msg = (p->packet[10] == 0x00 && p->packet[11] == 0x00) ? "" : "NOT ";
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 ") + msg + F("accepted power limit set point ") + String(iv->powerLimit[0]) + F(" with PowerLimitControl ") + String(iv->powerLimit[1]));
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]));
} }
iv->devControlCmd = Init; iv->devControlCmd = Init;
} }
@ -145,17 +146,16 @@ void app::loop(void) {
} }
yield(); yield();
if (rxRdy) {
if(rxRdy) {
processPayload(true); processPayload(true);
} }
} }
if(mMqttActive) if (mMqttActive)
mMqtt.loop(); mMqtt.loop();
if(checkTicker(&mTicker, 1000)) { if (checkTicker(&mTicker, 1000)) {
if(mUtcTimestamp > 946684800 && mConfig.sunLat && mConfig.sunLon && (mUtcTimestamp + mCalculatedTimezoneOffset) / 86400 != (mLatestSunTimestamp + mCalculatedTimezoneOffset) / 86400) { // update on reboot or midnight if (mUtcTimestamp > 946684800 && mConfig.sunLat && mConfig.sunLon && (mUtcTimestamp + mCalculatedTimezoneOffset) / 86400 != (mLatestSunTimestamp + mCalculatedTimezoneOffset) / 86400) { // update on reboot or midnight
if (!mLatestSunTimestamp) { // first call: calculate time zone from longitude to refresh at local midnight if (!mLatestSunTimestamp) { // first call: calculate time zone from longitude to refresh at local midnight
mCalculatedTimezoneOffset = (int8_t)((mConfig.sunLon >= 0 ? mConfig.sunLon + 7.5 : mConfig.sunLon - 7.5) / 15) * 3600; mCalculatedTimezoneOffset = (int8_t)((mConfig.sunLon >= 0 ? mConfig.sunLon + 7.5 : mConfig.sunLon - 7.5) / 15) * 3600;
} }
@ -163,11 +163,11 @@ void app::loop(void) {
mLatestSunTimestamp = mUtcTimestamp; mLatestSunTimestamp = mUtcTimestamp;
} }
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 val[10]; char val[10];
snprintf(val, 10, "%ld", millis()/1000); snprintf(val, 10, "%ld", millis() / 1000);
mMqtt.sendMsg("uptime", val); mMqtt.sendMsg("uptime", val);
@ -190,22 +190,22 @@ void app::loop(void) {
#ifdef __MQTT_TEST__ #ifdef __MQTT_TEST__
// für einfacheren Test mit MQTT, den MQTT abschnitt in 10 Sekunden wieder ausführen // für einfacheren Test mit MQTT, den MQTT abschnitt in 10 Sekunden wieder ausführen
mMqttTicker = mMqttInterval -10; mMqttTicker = mMqttInterval - 10;
#endif #endif
} }
if(mConfig.serialShowIv) { if (mConfig.serialShowIv) {
if(++mSerialTicker >= mConfig.serialInterval) { if (++mSerialTicker >= mConfig.serialInterval) {
mSerialTicker = 0; mSerialTicker = 0;
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);
if(NULL != iv) { if (NULL != iv) {
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
if(iv->isAvailable(mUtcTimestamp, rec)) { if (iv->isAvailable(mUtcTimestamp, rec)) {
DPRINTLN(DBG_INFO, "Inverter: " + String(id)); DPRINTLN(DBG_INFO, "Inverter: " + String(id));
for(uint8_t i = 0; i < rec->length; i++) { for (uint8_t i = 0; i < rec->length; i++) {
if(0.0f != iv->getValue(i, rec)) { if (0.0f != iv->getValue(i, rec)) {
snprintf(topic, 30, "%s/ch%d/%s", iv->name, rec->assign[i].ch, iv->getFieldName(i, rec)); snprintf(topic, 30, "%s/ch%d/%s", iv->name, rec->assign[i].ch, iv->getFieldName(i, rec));
snprintf(val, 10, "%.3f %s", iv->getValue(i, rec), iv->getUnit(i, rec)); snprintf(val, 10, "%.3f %s", iv->getValue(i, rec), iv->getUnit(i, rec));
DPRINTLN(DBG_INFO, String(topic) + ": " + String(val)); DPRINTLN(DBG_INFO, String(topic) + ": " + String(val));
@ -219,41 +219,41 @@ void app::loop(void) {
} }
} }
if(++mSendTicker >= mConfig.sendInterval) { if (++mSendTicker >= mConfig.sendInterval) {
mSendTicker = 0; mSendTicker = 0;
if(mUtcTimestamp > 946684800 && (!mConfig.sunDisNightCom || !mLatestSunTimestamp || (mUtcTimestamp >= mSunrise && mUtcTimestamp <= mSunset))) { // Timestamp is set and (inverter communication only during the day if the option is activated and sunrise/sunset is set) if (mUtcTimestamp > 946684800 && (!mConfig.sunDisNightCom || !mLatestSunTimestamp || (mUtcTimestamp >= mSunrise && mUtcTimestamp <= mSunset))) { // Timestamp is set and (inverter communication only during the day if the option is activated and sunrise/sunset is set)
if(mConfig.serialDebug) if (mConfig.serialDebug)
DPRINTLN(DBG_DEBUG, F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX)); DPRINTLN(DBG_DEBUG, F("Free heap: 0x") + String(ESP.getFreeHeap(), HEX));
if(!mSys->BufCtrl.empty()) { if (!mSys->BufCtrl.empty()) {
if(mConfig.serialDebug) if (mConfig.serialDebug)
DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->BufCtrl.getFill())); DPRINTLN(DBG_DEBUG, F("recbuf not empty! #") + String(mSys->BufCtrl.getFill()));
} }
int8_t maxLoop = MAX_NUM_INVERTERS; int8_t maxLoop = MAX_NUM_INVERTERS;
Inverter<> *iv = mSys->getInverterByPos(mSendLastIvId); Inverter<> *iv = mSys->getInverterByPos(mSendLastIvId);
do { do {
//if(NULL != iv) // if(NULL != iv)
// mPayload[iv->id].requested = false; // mPayload[iv->id].requested = false;
mSendLastIvId = ((MAX_NUM_INVERTERS-1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; mSendLastIvId = ((MAX_NUM_INVERTERS - 1) == mSendLastIvId) ? 0 : mSendLastIvId + 1;
iv = mSys->getInverterByPos(mSendLastIvId); iv = mSys->getInverterByPos(mSendLastIvId);
} while((NULL == iv) && ((maxLoop--) > 0)); } while ((NULL == iv) && ((maxLoop--) > 0));
if(NULL != iv) { if (NULL != iv) {
if(!mPayload[iv->id].complete) if (!mPayload[iv->id].complete)
processPayload(false); processPayload(false);
if(!mPayload[iv->id].complete) { if (!mPayload[iv->id].complete) {
if(0 == mPayload[iv->id].maxPackId) if (0 == mPayload[iv->id].maxPackId)
mStat.rxFailNoAnser++; mStat.rxFailNoAnser++;
else else
mStat.rxFail++; mStat.rxFail++;
iv->setQueuedCmdFinished(); // command failed iv->setQueuedCmdFinished(); // command failed
if(mConfig.serialDebug) if (mConfig.serialDebug)
DPRINTLN(DBG_INFO, F("enqueued cmd failed/timeout")); 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) + ")");
} }
@ -263,109 +263,101 @@ void app::loop(void) {
mPayload[iv->id].requested = true; mPayload[iv->id].requested = true;
yield(); yield();
if(mConfig.serialDebug) { if (mConfig.serialDebug) {
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) {
if(mConfig.serialDebug) if (iv->devControlRequest) {
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);
mPayload[iv->id].txCmd = iv->devControlCmd; mPayload[iv->id].txCmd = iv->devControlCmd;
iv->clearCmdQueue(); iv->clearCmdQueue();
iv->enqueCommand<InfoCommand>(SystemConfigPara); iv->enqueCommand<InfoCommand>(SystemConfigPara);
} } else {
else {
uint8_t cmd = iv->getQueuedCmd(); uint8_t cmd = iv->getQueuedCmd();
mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex); mSys->Radio.sendTimePacket(iv->radioId.u64, cmd, mPayload[iv->id].ts, iv->alarmMesIndex);
mPayload[iv->id].txCmd = cmd; mPayload[iv->id].txCmd = cmd;
mRxTicker = 0; mRxTicker = 0;
} }
} }
} } else if (mConfig.serialDebug)
else if(mConfig.serialDebug)
DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!")); DPRINTLN(DBG_WARN, F("Time not set or it is night time, therefore no communication to the inverter!"));
yield(); yield();
} }
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::handleIntr(void) { void app::handleIntr(void) {
DPRINTLN(DBG_VERBOSE, F("app::handleIntr")); DPRINTLN(DBG_VERBOSE, F("app::handleIntr"));
mSys->Radio.handleIntr(); mSys->Radio.handleIntr();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool app::buildPayload(uint8_t id) { bool app::buildPayload(uint8_t id) {
DPRINTLN(DBG_VERBOSE, F("app::buildPayload")); DPRINTLN(DBG_VERBOSE, F("app::buildPayload"));
uint16_t crc = 0xffff, crcRcv = 0x0000; uint16_t crc = 0xffff, crcRcv = 0x0000;
if(mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES) if (mPayload[id].maxPackId > MAX_PAYLOAD_ENTRIES)
mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES;
for(uint8_t i = 0; i < mPayload[id].maxPackId; i ++) { for (uint8_t i = 0; i < mPayload[id].maxPackId; i++) {
if(mPayload[id].len[i] > 0) { if (mPayload[id].len[i] > 0) {
if(i == (mPayload[id].maxPackId-1)) { if (i == (mPayload[id].maxPackId - 1)) {
crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i] - 2, crc); crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i] - 2, crc);
crcRcv = (mPayload[id].data[i][mPayload[id].len[i] - 2] << 8) crcRcv = (mPayload[id].data[i][mPayload[id].len[i] - 2] << 8) | (mPayload[id].data[i][mPayload[id].len[i] - 1]);
| (mPayload[id].data[i][mPayload[id].len[i] - 1]); } else
}
else
crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i], crc); crc = ah::crc16(mPayload[id].data[i], mPayload[id].len[i], crc);
} }
yield(); yield();
} }
if(crc == crcRcv)
return true;
return false;
}
return (crc == crcRcv) ? true : false;
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::processPayload(bool retransmit) { void app::processPayload(bool retransmit) {
#ifdef __MQTT_AFTER_RX__ #ifdef __MQTT_AFTER_RX__
boolean doMQTT = false; boolean doMQTT = false;
#endif #endif
//DPRINTLN(DBG_INFO, F("processPayload")); // DPRINTLN(DBG_INFO, F("processPayload"));
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);
if(NULL != iv) { if (NULL != iv) {
if((mPayload[iv->id].txId != (TX_REQ_INFO + 0x80)) && (0 != mPayload[iv->id].txId)) { if ((mPayload[iv->id].txId != (TX_REQ_INFO + ALL_FRAMES)) && (0 != mPayload[iv->id].txId)) {
// no processing needed if txId is not 0x95 // no processing needed if txId is not 0x95
//DPRINTLN(DBG_INFO, F("processPayload - set complete, txId: ") + String(mPayload[iv->id].txId, HEX)); // DPRINTLN(DBG_INFO, F("processPayload - set complete, txId: ") + String(mPayload[iv->id].txId, HEX));
mPayload[iv->id].complete = true; mPayload[iv->id].complete = true;
} }
if(!mPayload[iv->id].complete ) { if (!mPayload[iv->id].complete) {
if(!buildPayload(iv->id)) { // payload not complete if (!buildPayload(iv->id)) // payload not complete
if(mPayload[iv->id].requested) { {
if(retransmit) { if (mPayload[iv->id].requested) {
if(iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm ) { if (retransmit) {
if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) {
// This is required to prevent retransmissions without answer. // This is required to prevent retransmissions without answer.
DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm..."));
mPayload[iv->id].retransmits = mConfig.maxRetransPerPyld; mPayload[iv->id].retransmits = mConfig.maxRetransPerPyld;
} else { } else {
if(mPayload[iv->id].retransmits < mConfig.maxRetransPerPyld) { if (mPayload[iv->id].retransmits < mConfig.maxRetransPerPyld) {
mPayload[iv->id].retransmits++; mPayload[iv->id].retransmits++;
if(mPayload[iv->id].maxPackId != 0) { if (mPayload[iv->id].maxPackId != 0) {
for(uint8_t i = 0; i < (mPayload[iv->id].maxPackId-1); i++) { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId - 1); i++) {
if(mPayload[iv->id].len[i] == 0) { if (mPayload[iv->id].len[i] == 0) {
if(mConfig.serialDebug) if (mConfig.serialDebug)
DPRINTLN(DBG_WARN, F("while retrieving data: Frame ") + String(i+1) + F(" missing: Request Retransmit")); DPRINTLN(DBG_WARN, F("while retrieving data: Frame ") + String(i + 1) + F(" missing: Request Retransmit"));
mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME+i), true); mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, (SINGLE_FRAME + i), true);
break; // only retransmit one frame per loop break; // only retransmit one frame per loop
} }
yield(); yield();
} }
} } else {
else { if (mConfig.serialDebug)
if(mConfig.serialDebug)
DPRINTLN(DBG_WARN, F("while retrieving data: last frame missing: Request Retransmit")); DPRINTLN(DBG_WARN, F("while retrieving data: last frame missing: Request Retransmit"));
if(0x00 != mLastPacketId) if (0x00 != mLastPacketId)
mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, mLastPacketId, true); mSys->Radio.sendCmdPacket(iv->radioId.u64, TX_REQ_INFO, mLastPacketId, true);
else { else {
mPayload[iv->id].txCmd = iv->getQueuedCmd(); mPayload[iv->id].txCmd = iv->getQueuedCmd();
@ -377,8 +369,7 @@ void app::processPayload(bool retransmit) {
} }
} }
} }
} } else { // payload complete
else { // payload complete
DPRINTLN(DBG_INFO, F("procPyld: cmd: ") + String(mPayload[iv->id].txCmd)); DPRINTLN(DBG_INFO, F("procPyld: cmd: ") + String(mPayload[iv->id].txCmd));
DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX)); DPRINTLN(DBG_INFO, F("procPyld: txid: 0x") + String(mPayload[iv->id].txId, HEX));
DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId)); DPRINTLN(DBG_DEBUG, F("procPyld: max: ") + String(mPayload[iv->id].maxPackId));
@ -390,33 +381,33 @@ void app::processPayload(bool retransmit) {
memset(payload, 0, 128); memset(payload, 0, 128);
for(uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i ++) { for (uint8_t i = 0; i < (mPayload[iv->id].maxPackId); i++) {
memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i])); memcpy(&payload[payloadLen], mPayload[iv->id].data[i], (mPayload[iv->id].len[i]));
payloadLen += (mPayload[iv->id].len[i]); payloadLen += (mPayload[iv->id].len[i]);
yield(); yield();
} }
payloadLen-=2; payloadLen -= 2;
if(mConfig.serialDebug) { if (mConfig.serialDebug) {
DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): "); DPRINT(DBG_INFO, F("Payload (") + String(payloadLen) + "): ");
mSys->Radio.dumpBuf(NULL, payload, payloadLen); mSys->Radio.dumpBuf(NULL, payload, payloadLen);
} }
if(NULL == rec) if (NULL == rec) {
DPRINTLN(DBG_ERROR, F("record is NULL!")); DPRINTLN(DBG_ERROR, F("record is NULL!"));
else if((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) { } else if ((rec->pyldLen == payloadLen) || (0 == rec->pyldLen)) {
if(mPayload[iv->id].txId == (TX_REQ_INFO + 0x80)) if (mPayload[iv->id].txId == (TX_REQ_INFO + 0x80))
mStat.rxSuccess++; mStat.rxSuccess++;
rec->ts = mPayload[iv->id].ts; rec->ts = mPayload[iv->id].ts;
for(uint8_t i = 0; i < rec->length; i++) { for (uint8_t i = 0; i < rec->length; i++) {
iv->addValue(i, payload, rec); iv->addValue(i, payload, rec);
yield(); yield();
} }
iv->doCalculations(); iv->doCalculations();
// MQTT send out // MQTT send out
if(mMqttActive) { if (mMqttActive) {
record_t<> *recRealtime = iv->getRecordStruct(RealTimeRunData_Debug); record_t<> *recRealtime = iv->getRecordStruct(RealTimeRunData_Debug);
char topic[32 + MAX_NAME_LENGTH], val[32]; char topic[32 + MAX_NAME_LENGTH], val[32];
float total[4]; float total[4];
@ -429,33 +420,42 @@ void app::processPayload(bool retransmit) {
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]);
snprintf(val, 10, "%.3f", iv->getValue(i, rec)); snprintf(val, 10, "%.3f", iv->getValue(i, rec));
mMqtt.sendMsg(topic, val); mMqtt.sendMsg(topic, val);
if(recRealtime == rec) { if (recRealtime == rec) {
if(CH0 == rec->assign[i].ch) { if (CH0 == rec->assign[i].ch) {
switch(rec->assign[i].fieldId) { switch (rec->assign[i].fieldId) {
case FLD_PAC: total[0] += iv->getValue(i, rec); break; case FLD_PAC:
case FLD_YT: total[1] += iv->getValue(i, rec); break; total[0] += iv->getValue(i, rec);
case FLD_YD: total[2] += iv->getValue(i, rec); break; break;
case FLD_PDC: total[3] += iv->getValue(i, rec); break; case FLD_YT:
total[1] += iv->getValue(i, rec);
break;
case FLD_YD:
total[2] += iv->getValue(i, rec);
break;
case FLD_PDC:
total[3] += iv->getValue(i, rec);
break;
} }
} }
} }
if(iv->isProducing(mUtcTimestamp, rec)){ if (iv->isProducing(mUtcTimestamp, rec)) {
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available_text", iv->name); snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available_text", iv->name);
snprintf(val, 32, DEF_MQTT_IV_MESSAGE_INVERTER_AVAIL_AND_PRODUCED); snprintf(val, 32, DEF_MQTT_IV_MESSAGE_INVERTER_AVAIL_AND_PRODUCED);
mMqtt.sendMsg(topic, val); mMqtt.sendMsg(topic, val);
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->name); snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->name);
snprintf(val, 32, "2"); snprintf(val, 32, "2");
mMqtt.sendMsg(topic, val);
} else { } else {
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available_text", iv->name);
snprintf(val, 32, DEF_MQTT_IV_MESSAGE_INVERTER_AVAIL_AND_NOT_PRODUCED); snprintf(val, 32, DEF_MQTT_IV_MESSAGE_INVERTER_AVAIL_AND_NOT_PRODUCED);
mMqtt.sendMsg(topic, val); mMqtt.sendMsg(topic, val);
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->name); snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->name);
snprintf(val, 32, "1"); snprintf(val, 32, "1");
mMqtt.sendMsg(topic, val);
} }
mMqtt.sendMsg(topic, val);
snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/last_success", iv->name); snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/last_success", iv->name);
snprintf(val, 48, "%i", iv->getLastTs(rec) * 1000); snprintf(val, 48, "%i", iv->getLastTs(rec) * 1000);
mMqtt.sendMsg(topic, val); mMqtt.sendMsg(topic, val);
@ -467,15 +467,23 @@ void app::processPayload(bool retransmit) {
} }
// total values (sum of all inverters) // total values (sum of all inverters)
if(recRealtime == rec) { if (recRealtime == rec) {
if(mSys->getNumInverters() > 1) { if (mSys->getNumInverters() > 1) {
uint8_t fieldId = 0; uint8_t fieldId = 0;
for (uint8_t i = 0; i < 4; i++) { for (uint8_t i = 0; i < 4; i++) {
switch(i) { switch (i) {
case 0: fieldId = FLD_PAC; break; case 0:
case 1: fieldId = FLD_YT; break; fieldId = FLD_PAC;
case 2: fieldId = FLD_YD; break; break;
case 3: fieldId = FLD_PDC; break; case 1:
fieldId = FLD_YT;
break;
case 2:
fieldId = FLD_YD;
break;
case 3:
fieldId = FLD_PDC;
break;
} }
snprintf(topic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]); snprintf(topic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]);
snprintf(val, 10, "%.3f", total[i]); snprintf(val, 10, "%.3f", total[i]);
@ -484,8 +492,7 @@ void app::processPayload(bool retransmit) {
} }
} }
} }
} } else {
else {
DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes")); DPRINTLN(DBG_ERROR, F("plausibility check failed, expected ") + String(rec->pyldLen) + F(" bytes"));
mStat.rxFail++; mStat.rxFail++;
} }
@ -507,87 +514,104 @@ void app::processPayload(bool retransmit) {
// dann die den mMqttTicker auf mMqttIntervall -2 setzen, also // dann die den mMqttTicker auf mMqttIntervall -2 setzen, also
// MQTT aussenden in 2 sek aktivieren // MQTT aussenden in 2 sek aktivieren
// dies sollte noch über einen Schalter im Setup aktivier / deaktivierbar gemacht werden // dies sollte noch über einen Schalter im Setup aktivier / deaktivierbar gemacht werden
if( (mMqttInterval != 0xffff) && doMQTT ) { if ((mMqttInterval != 0xffff) && doMQTT) {
++mMqttTicker = mMqttInterval -2; ++mMqttTicker = mMqttInterval - 2;
DPRINT(DBG_DEBUG, F("MQTTticker auf Intervall -2 sec ")) ; DPRINT(DBG_DEBUG, F("MQTTticker auf Intervall -2 sec "));
} }
#endif #endif
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::cbMqtt(char* topic, byte* payload, unsigned int length) { void app::cbMqtt(char *topic, byte *payload, unsigned int length) {
// callback handling on subscribed devcontrol topic // callback handling on subscribed devcontrol topic
DPRINTLN(DBG_INFO, F("app::cbMqtt")); DPRINTLN(DBG_INFO, F("app::cbMqtt"));
// subcribed topics are mTopic + "/devcontrol/#" where # is <inverter_id>/<subcmd in dec> // subcribed topics are mTopic + "/devcontrol/#" where # is <inverter_id>/<subcmd in dec>
// eg. mypvsolar/devcontrol/1/11 with payload "400" --> inverter 1 active power limit 400 Watt // eg. mypvsolar/devcontrol/1/11 with payload "400" --> inverter 1 active power limit 400 Watt
const char *token = strtok(topic, "/"); const char *token = strtok(topic, "/");
while (token != NULL) while (token != NULL) {
{ if (strcmp(token, "devcontrol") == 0) {
if (strcmp(token,"devcontrol")==0){
token = strtok(NULL, "/"); token = strtok(NULL, "/");
uint8_t iv_id = std::stoi(token); uint8_t iv_id = std::stoi(token);
if (iv_id >= 0 && iv_id <= MAX_NUM_INVERTERS){
if (iv_id >= 0 && iv_id <= MAX_NUM_INVERTERS) {
Inverter<> *iv = this->mSys->getInverterByPos(iv_id); Inverter<> *iv = this->mSys->getInverterByPos(iv_id);
if(NULL != iv) { if (NULL != iv) {
if (!iv->devControlRequest) { // still pending if (!iv->devControlRequest) // still pending
{
token = strtok(NULL, "/"); token = strtok(NULL, "/");
switch ( std::stoi(token) ){
case ActivePowerContr: // Active Power Control switch (std::stoi(token)) {
// Active Power Control
case ActivePowerContr:
token = strtok(NULL, "/"); // get ControlMode aka "PowerPF.Desc" in DTU-Pro Code from topic string token = strtok(NULL, "/"); // get ControlMode aka "PowerPF.Desc" in DTU-Pro Code from topic string
if (token == NULL) // default via mqtt ommit the LimitControlMode if (token == NULL) // default via mqtt ommit the LimitControlMode
iv->powerLimit[1] = AbsolutNonPersistent; iv->powerLimit[1] = AbsolutNonPersistent;
else else
iv->powerLimit[1] = std::stoi(token); iv->powerLimit[1] = std::stoi(token);
if (length<=5){ // if (std::stoi((char*)payload) > 0) more error handling powerlimit needed? if (length <= 5) { // if (std::stoi((char*)payload) > 0) more error handling powerlimit needed?
if (iv->powerLimit[1] >= AbsolutNonPersistent && iv->powerLimit[1] <= RelativPersistent){ if (iv->powerLimit[1] >= AbsolutNonPersistent && iv->powerLimit[1] <= RelativPersistent) {
iv->devControlCmd = ActivePowerContr; iv->devControlCmd = ActivePowerContr;
iv->powerLimit[0] = std::stoi(std::string((char*)payload, (unsigned int)length)); // THX to @silversurfer iv->powerLimit[0] = std::stoi(std::string((char *)payload, (unsigned int)length)); // THX to @silversurfer
if (iv->powerLimit[1] & 0x0001) /*if (iv->powerLimit[1] & 0x0001)
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("%") ); DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("%"));
else 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 for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W"));*/
DPRINTLN(DBG_INFO, F("Power limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F((iv->powerLimit[1] & 0x0001) ? "%" : "W"));
} }
iv->devControlRequest = true; iv->devControlRequest = true;
} else { } else {
DPRINTLN(DBG_INFO, F("Invalid mqtt payload recevied: ") + String((char*)payload)); DPRINTLN(DBG_INFO, F("Invalid mqtt payload recevied: ") + String((char *)payload));
} }
break; break;
case TurnOn: // Turn On
// Turn On
case TurnOn:
iv->devControlCmd = TurnOn; iv->devControlCmd = TurnOn;
DPRINTLN(DBG_INFO, F("Turn on inverter ") + String(iv->id) ); DPRINTLN(DBG_INFO, F("Turn on inverter ") + String(iv->id));
iv->devControlRequest = true; iv->devControlRequest = true;
break; break;
case TurnOff: // Turn Off
// Turn Off
case TurnOff:
iv->devControlCmd = TurnOff; iv->devControlCmd = TurnOff;
DPRINTLN(DBG_INFO, F("Turn off inverter ") + String(iv->id) ); DPRINTLN(DBG_INFO, F("Turn off inverter ") + String(iv->id));
iv->devControlRequest = true; iv->devControlRequest = true;
break; break;
case Restart: // Restart
// Restart
case Restart:
iv->devControlCmd = Restart; iv->devControlCmd = Restart;
DPRINTLN(DBG_INFO, F("Restart inverter ") + String(iv->id) ); DPRINTLN(DBG_INFO, F("Restart inverter ") + String(iv->id));
iv->devControlRequest = true; iv->devControlRequest = true;
break; break;
case ReactivePowerContr: // Reactive Power Control
// Reactive Power Control
case ReactivePowerContr:
iv->devControlCmd = ReactivePowerContr; iv->devControlCmd = ReactivePowerContr;
if (true){ // if (std::stoi((char*)payload) > 0) error handling powerlimit needed? if (true) { // if (std::stoi((char*)payload) > 0) error handling powerlimit needed?
iv->devControlCmd = ReactivePowerContr; iv->devControlCmd = ReactivePowerContr;
iv->powerLimit[0] = std::stoi(std::string((char*)payload, (unsigned int)length)); iv->powerLimit[0] = std::stoi(std::string((char *)payload, (unsigned int)length));
iv->powerLimit[1] = 0x0000; // if reactivepower limit is set via external interface --> set it temporay iv->powerLimit[1] = 0x0000; // if reactivepower limit is set via external interface --> set it temporay
DPRINTLN(DBG_DEBUG, F("Reactivepower limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W") ); DPRINTLN(DBG_DEBUG, F("Reactivepower limit for inverter ") + String(iv->id) + F(" set to ") + String(iv->powerLimit[0]) + F("W"));
iv->devControlRequest = true; iv->devControlRequest = true;
} }
break; break;
case PFSet: // Set Power Factor
// Set Power Factor
case PFSet:
// iv->devControlCmd = PFSet; // iv->devControlCmd = PFSet;
// uint16_t power_factor = std::stoi(strtok(NULL, "/")); // uint16_t power_factor = std::stoi(strtok(NULL, "/"));
DPRINTLN(DBG_INFO, F("Set Power Factor not implemented for inverter ") + String(iv->id) ); DPRINTLN(DBG_INFO, F("Set Power Factor not implemented for inverter ") + String(iv->id));
break; break;
case CleanState_LockAndAlarm: // CleanState lock & alarm
// CleanState lock & alarm
case CleanState_LockAndAlarm:
iv->devControlCmd = CleanState_LockAndAlarm; iv->devControlCmd = CleanState_LockAndAlarm;
DPRINTLN(DBG_INFO, F("CleanState lock & alarm for inverter ") + String(iv->id) ); DPRINTLN(DBG_INFO, F("CleanState lock & alarm for inverter ") + String(iv->id));
iv->devControlRequest = true; iv->devControlRequest = true;
break; break;
default: default:
DPRINTLN(DBG_INFO, "Not implemented"); DPRINTLN(DBG_INFO, "Not implemented");
break; break;
@ -602,13 +626,11 @@ void app::cbMqtt(char* topic, byte* payload, unsigned int length) {
DPRINTLN(DBG_INFO, F("app::cbMqtt finished")); DPRINTLN(DBG_INFO, F("app::cbMqtt finished"));
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
bool app::getWifiApActive(void) { bool app::getWifiApActive(void) {
return mWifi->getApActive(); return mWifi->getApActive();
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::scanAvailNetworks(void) { void app::scanAvailNetworks(void) {
mWifi->scanAvailNetworks(); mWifi->scanAvailNetworks();
@ -620,18 +642,17 @@ void app::getAvailNetworks(JsonObject obj) {
mWifi->getAvailNetworks(obj); mWifi->getAvailNetworks(obj);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::sendMqttDiscoveryConfig(void) { void app::sendMqttDiscoveryConfig(void) {
DPRINTLN(DBG_VERBOSE, F("app::sendMqttDiscoveryConfig")); DPRINTLN(DBG_VERBOSE, F("app::sendMqttDiscoveryConfig"));
char stateTopic[64], discoveryTopic[64], buffer[512], name[32], uniq_id[32]; char stateTopic[64], discoveryTopic[64], buffer[512], name[32], uniq_id[32];
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);
if(NULL != iv) { if (NULL != iv) {
record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug); record_t<> *rec = iv->getRecordStruct(RealTimeRunData_Debug);
// TODO: next line makes no sense if discovery config is send manually by button // TODO: next line makes no sense if discovery config is send manually by button
//if(iv->isAvailable(mUtcTimestamp, rec) && mMqttConfigSendState[id] != true) { // if(iv->isAvailable(mUtcTimestamp, rec) && mMqttConfigSendState[id] != true) {
DynamicJsonDocument deviceDoc(128); DynamicJsonDocument deviceDoc(128);
deviceDoc["name"] = iv->name; deviceDoc["name"] = iv->name;
deviceDoc["ids"] = String(iv->serial.u64, HEX); deviceDoc["ids"] = String(iv->serial.u64, HEX);
@ -641,7 +662,7 @@ void app::sendMqttDiscoveryConfig(void) {
JsonObject deviceObj = deviceDoc.as<JsonObject>(); JsonObject deviceObj = deviceDoc.as<JsonObject>();
DynamicJsonDocument doc(384); DynamicJsonDocument doc(384);
for(uint8_t i = 0; i < rec->length; i++) { for (uint8_t i = 0; i < rec->length; i++) {
if (rec->assign[i].ch == CH0) { if (rec->assign[i].ch == CH0) {
snprintf(name, 32, "%s %s", iv->name, iv->getFieldName(i, rec)); snprintf(name, 32, "%s %s", iv->name, iv->getFieldName(i, rec));
} else { } else {
@ -650,8 +671,8 @@ void app::sendMqttDiscoveryConfig(void) {
snprintf(stateTopic, 64, "%s/%s/ch%d/%s", mConfig.mqtt.topic, iv->name, rec->assign[i].ch, iv->getFieldName(i, rec)); snprintf(stateTopic, 64, "%s/%s/ch%d/%s", mConfig.mqtt.topic, iv->name, rec->assign[i].ch, iv->getFieldName(i, rec));
snprintf(discoveryTopic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->name, rec->assign[i].ch, iv->getFieldName(i, rec)); snprintf(discoveryTopic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->name, rec->assign[i].ch, iv->getFieldName(i, rec));
snprintf(uniq_id, 32, "ch%d_%s", rec->assign[i].ch, iv->getFieldName(i, rec)); snprintf(uniq_id, 32, "ch%d_%s", rec->assign[i].ch, iv->getFieldName(i, rec));
const char* devCls = getFieldDeviceClass(rec->assign[i].fieldId); const char *devCls = getFieldDeviceClass(rec->assign[i].fieldId);
const char* stateCls = getFieldStateClass(rec->assign[i].fieldId); const char *stateCls = getFieldStateClass(rec->assign[i].fieldId);
doc["name"] = name; doc["name"] = name;
doc["stat_t"] = stateTopic; doc["stat_t"] = stateTopic;
@ -666,7 +687,7 @@ void app::sendMqttDiscoveryConfig(void) {
serializeJson(doc, buffer); serializeJson(doc, buffer);
mMqtt.sendMsg2(discoveryTopic, buffer, true); mMqtt.sendMsg2(discoveryTopic, buffer, true);
//DPRINTLN(DBG_INFO, F("mqtt sent")); // DPRINTLN(DBG_INFO, F("mqtt sent"));
doc.clear(); doc.clear();
} }
@ -679,29 +700,26 @@ void app::sendMqttDiscoveryConfig(void) {
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
const char* app::getFieldDeviceClass(uint8_t fieldId) { const char *app::getFieldDeviceClass(uint8_t fieldId) {
uint8_t pos = 0; uint8_t pos = 0;
for(; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) { for (; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) {
if(deviceFieldAssignment[pos].fieldId == fieldId) if (deviceFieldAssignment[pos].fieldId == fieldId)
break; break;
} }
return (pos >= DEVICE_CLS_ASSIGN_LIST_LEN) ? NULL : deviceClasses[deviceFieldAssignment[pos].deviceClsId]; return (pos >= DEVICE_CLS_ASSIGN_LIST_LEN) ? NULL : deviceClasses[deviceFieldAssignment[pos].deviceClsId];
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
const char* app::getFieldStateClass(uint8_t fieldId) { const char *app::getFieldStateClass(uint8_t fieldId) {
uint8_t pos = 0; uint8_t pos = 0;
for(; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) { for (; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) {
if(deviceFieldAssignment[pos].fieldId == fieldId) if (deviceFieldAssignment[pos].fieldId == fieldId)
break; break;
} }
return (pos >= DEVICE_CLS_ASSIGN_LIST_LEN) ? NULL : stateClasses[deviceFieldAssignment[pos].stateClsId]; return (pos >= DEVICE_CLS_ASSIGN_LIST_LEN) ? NULL : stateClasses[deviceFieldAssignment[pos].stateClsId];
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::resetSystem(void) { void app::resetSystem(void) {
mUptimeSecs = 0; mUptimeSecs = 0;
@ -733,13 +751,11 @@ void app::resetSystem(void) {
mShowRebootRequest = false; mShowRebootRequest = false;
memset(mPayload, 0, (MAX_NUM_INVERTERS * sizeof(invPayload_t))); memset(mPayload, 0, (MAX_NUM_INVERTERS * sizeof(invPayload_t)));
memset(&mStat, 0, sizeof(statistics_t)); memset(&mStat, 0, sizeof(statistics_t));
mLastPacketId = 0x00; mLastPacketId = 0x00;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::loadDefaultConfig(void) { void app::loadDefaultConfig(void) {
memset(&mSysConfig, 0, sizeof(sysConfig_t)); memset(&mSysConfig, 0, sizeof(sysConfig_t));
@ -752,7 +768,6 @@ void app::loadDefaultConfig(void) {
snprintf(mSysConfig.stationSsid, SSID_LEN, "%s", FB_WIFI_SSID); snprintf(mSysConfig.stationSsid, SSID_LEN, "%s", FB_WIFI_SSID);
snprintf(mSysConfig.stationPwd, PWD_LEN, "%s", FB_WIFI_PWD); snprintf(mSysConfig.stationPwd, PWD_LEN, "%s", FB_WIFI_PWD);
// nrf24 // nrf24
mConfig.sendInterval = SEND_INTERVAL; mConfig.sendInterval = SEND_INTERVAL;
mConfig.maxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD; mConfig.maxRetransPerPyld = DEF_MAX_RETRANS_PER_PYLD;
@ -786,15 +801,14 @@ void app::loadDefaultConfig(void) {
mConfig.disclaimer = false; mConfig.disclaimer = false;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::loadEEpconfig(void) { void app::loadEEpconfig(void) {
DPRINTLN(DBG_VERBOSE, F("app::loadEEpconfig")); DPRINTLN(DBG_VERBOSE, F("app::loadEEpconfig"));
if(mWifiSettingsValid) if (mWifiSettingsValid)
mEep->read(ADDR_CFG_SYS, (uint8_t*) &mSysConfig, CFG_SYS_LEN); mEep->read(ADDR_CFG_SYS, (uint8_t *)&mSysConfig, CFG_SYS_LEN);
if(mSettingsValid) { if (mSettingsValid) {
mEep->read(ADDR_CFG, (uint8_t*) &mConfig, CFG_LEN); mEep->read(ADDR_CFG, (uint8_t *)&mConfig, CFG_LEN);
mSendTicker = mConfig.sendInterval; mSendTicker = mConfig.sendInterval;
mSerialTicker = 0; mSerialTicker = 0;
@ -804,14 +818,14 @@ void app::loadEEpconfig(void) {
char name[MAX_NAME_LENGTH + 1] = {0}; char name[MAX_NAME_LENGTH + 1] = {0};
uint16_t modPwr[4]; uint16_t modPwr[4];
Inverter<> *iv; Inverter<> *iv;
for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i ++) { for (uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) {
mEep->read(ADDR_INV_ADDR + (i * 8), &invSerial); 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_NAME + (i * MAX_NAME_LENGTH), name, MAX_NAME_LENGTH);
mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4); mEep->read(ADDR_INV_CH_PWR + (i * 2 * 4), modPwr, 4);
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
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);
} }
} }
@ -821,29 +835,28 @@ void app::loadEEpconfig(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);
if(NULL != iv) if (NULL != iv)
resetPayload(iv); resetPayload(iv);
} }
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::saveValues(void) { void app::saveValues(void) {
DPRINTLN(DBG_VERBOSE, F("app::saveValues")); DPRINTLN(DBG_VERBOSE, F("app::saveValues"));
mEep->write(ADDR_CFG_SYS, (uint8_t*)&mSysConfig, CFG_SYS_LEN); mEep->write(ADDR_CFG_SYS, (uint8_t *)&mSysConfig, CFG_SYS_LEN);
mEep->write(ADDR_CFG, (uint8_t*)&mConfig, CFG_LEN); mEep->write(ADDR_CFG, (uint8_t *)&mConfig, CFG_LEN);
Inverter<> *iv; Inverter<> *iv;
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_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++) {
mEep->write(ADDR_INV_CH_PWR + (i * 2 * 4) + (j*2), iv->chMaxPwr[j]); mEep->write(ADDR_INV_CH_PWR + (i * 2 * 4) + (j * 2), iv->chMaxPwr[j]);
mEep->write(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, iv->chName[j], MAX_NAME_LENGTH); mEep->write(ADDR_INV_CH_NAME + (i * 4 * MAX_NAME_LENGTH) + j * MAX_NAME_LENGTH, iv->chName[j], MAX_NAME_LENGTH);
} }
} }
@ -854,50 +867,33 @@ void app::saveValues(void) {
mLatestSunTimestamp = 0; mLatestSunTimestamp = 0;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::setupMqtt(void) { void app::setupMqtt(void) {
if(mSettingsValid) { if (mSettingsValid) {
if(mConfig.mqtt.broker[0] > 0) { if (mConfig.mqtt.broker[0] > 0) {
mMqttActive = true; mMqttActive = true;
if(mMqttInterval < MIN_MQTT_INTERVAL) if (mMqttInterval < MIN_MQTT_INTERVAL) mMqttInterval = MIN_MQTT_INTERVAL;
mMqttInterval = MIN_MQTT_INTERVAL; } else {
}
else
mMqttInterval = 0xffff; mMqttInterval = 0xffff;
}
mMqttTicker = 0; mMqttTicker = 0;
mMqtt.setup(&mConfig.mqtt, mSysConfig.deviceName); mMqtt.setup(&mConfig.mqtt, mSysConfig.deviceName);
mMqtt.setCallback(std::bind(&app::cbMqtt, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3)); mMqtt.setCallback(std::bind(&app::cbMqtt, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
if (mMqttActive) {
if(mMqttActive) {
mMqtt.sendMsg("version", mVersion); mMqtt.sendMsg("version", mVersion);
if(mMqtt.isConnected()) { if (mMqtt.isConnected()) {
mMqtt.sendMsg("device", mSysConfig.deviceName); mMqtt.sendMsg("device", mSysConfig.deviceName);
mMqtt.sendMsg("uptime", "0"); mMqtt.sendMsg("uptime", "0");
} }
/*char topic[30];
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();
}
}
}
}*/
} }
} }
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::resetPayload(Inverter<>* iv) { void app::resetPayload(Inverter<> *iv) {
DPRINTLN(DBG_INFO, "resetPayload: id: " + String(iv->id)); DPRINTLN(DBG_INFO, "resetPayload: id: " + String(iv->id));
memset(mPayload[iv->id].len, 0, MAX_PAYLOAD_ENTRIES); memset(mPayload[iv->id].len, 0, MAX_PAYLOAD_ENTRIES);
mPayload[iv->id].txCmd = 0; mPayload[iv->id].txCmd = 0;

2
tools/esp8266/platformio.ini

@ -69,7 +69,6 @@ platform = espressif32
board = lolin_d32 board = lolin_d32
build_flags = -D RELEASE -std=gnu++14 build_flags = -D RELEASE -std=gnu++14
build_unflags = -std=gnu++11 build_unflags = -std=gnu++11
upload_port = /dev/cu.SLAB_USBtoUART
monitor_filters = monitor_filters =
;default ; Remove typical terminal control codes from input ;default ; Remove typical terminal control codes from input
time ; Add timestamp with milliseconds for each new line time ; Add timestamp with milliseconds for each new line
@ -81,7 +80,6 @@ board = lolin_d32
build_flags = -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_OOM -DDEBUG_ESP_PORT=Serial -std=gnu++14 build_flags = -DDEBUG_LEVEL=DBG_DEBUG -DDEBUG_ESP_CORE -DDEBUG_ESP_WIFI -DDEBUG_ESP_HTTP_CLIENT -DDEBUG_ESP_HTTP_SERVER -DDEBUG_ESP_OOM -DDEBUG_ESP_PORT=Serial -std=gnu++14
build_unflags = -std=gnu++11 build_unflags = -std=gnu++11
build_type = debug build_type = debug
upload_port = /dev/cu.SLAB_USBtoUART
monitor_filters = monitor_filters =
;default ; Remove typical terminal control codes from input ;default ; Remove typical terminal control codes from input
time ; Add timestamp with milliseconds for each new line time ; Add timestamp with milliseconds for each new line

6
tools/rpi/hoymiles/__main__.py

@ -322,8 +322,10 @@ if __name__ == '__main__':
print('', end='', flush=True) print('', end='', flush=True)
if loop_interval > 0 and (time.time() - t_loop_start) < loop_interval: time_to_sleep = loop_interval - (time.time() - t_loop_start)
time.sleep(loop_interval - (time.time() - t_loop_start))
if loop_interval > 0 and time_to_sleep > 0:
time.sleep(time_to_sleep)
except KeyboardInterrupt: except KeyboardInterrupt:
sys.exit() sys.exit()

Loading…
Cancel
Save