diff --git a/.github/workflows/compile_development.yml b/.github/workflows/compile_development.yml index 59460d5c..ffde2d21 100644 --- a/.github/workflows/compile_development.yml +++ b/.github/workflows/compile_development.yml @@ -47,7 +47,7 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus + run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment opendtufusionv1-release - name: Rename Binary files id: rename-binary-files diff --git a/.github/workflows/compile_release.yml b/.github/workflows/compile_release.yml index bd7cef5a..84ad5111 100644 --- a/.github/workflows/compile_release.yml +++ b/.github/workflows/compile_release.yml @@ -51,7 +51,7 @@ jobs: run: python convert.py - name: Run PlatformIO - run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus + run: pio run -d src --environment esp8266-release --environment esp8266-release-prometheus --environment esp8285-release --environment esp32-wroom32-release --environment esp32-wroom32-release-prometheus --environment opendtufusionv1-release - name: Rename Binary files id: rename-binary-files diff --git a/.gitignore b/.gitignore index d6a35860..2ee4b679 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ src/web/html/tmp/* *.db *.suo *.ipch +src/output.map diff --git a/scripts/getVersion.py b/scripts/getVersion.py index 77c5816b..0ebe1ec2 100644 --- a/scripts/getVersion.py +++ b/scripts/getVersion.py @@ -78,6 +78,11 @@ def readVersion(path, infile): dst = path + "firmware/" + versionout os.rename(src, dst) + versionout = version[:-1] + "_" + sha + "_esp32s3.bin" + src = path + ".pio/build/opendtufusionv1-release/firmware.bin" + dst = path + "firmware/" + versionout + os.rename(src, dst) + # other ESP32 bin files src = path + ".pio/build/esp32-wroom32-release/" dst = path + "firmware/" diff --git a/src/.vscode/settings.json b/src/.vscode/settings.json index c0becfd1..58a2c3c7 100644 --- a/src/.vscode/settings.json +++ b/src/.vscode/settings.json @@ -4,20 +4,16 @@ "workbench.colorCustomizations": { "editorLineNumber.foreground": "#00ff00" }, - "editor.wordWrap": "off", - "files.eol" : "\n", - "files.trimTrailingWhitespace" : true, - + "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}", "files.associations": { @@ -86,4 +82,5 @@ "thread": "cpp" }, "cmake.configureOnOpen": false, + "editor.formatOnSave": false, } \ No newline at end of file diff --git a/src/CHANGES.md b/src/CHANGES.md index e9f3ea32..a9ff80a3 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -2,6 +2,16 @@ (starting from release version `0.5.66`) +## 0.5.109 +* reduced heap fragmentation by optimizing MqTT #768 +* ePaper: centered text thx @knickohr + +## 0.5.108 +* merge: PR SPI pins configureable (ESP32) #807, #806 +* merge: PR MI serial outputs #809 +* fix: no MQTT `total` sensor for autodiscover if only one inverter was found #805 +* fix: MQTT `total` renamed to `device_name` + `_TOTOL` for better visibility #805 + ## 0.5.107 * fix: show save message * fix: removed serial newline for `enqueueCmd` diff --git a/src/app.cpp b/src/app.cpp index 60f4a64a..2a9189d3 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -29,9 +29,8 @@ void app::setup() { else DBGPRINTLN(F("false")); - mSys.setup(); if(mConfig->nrf.enabled) { - mNrfRadio.setup(mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs); + mNrfRadio.setup(mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); mNrfRadio.enableDebug(); } #if defined(ESP32) diff --git a/src/config/config.h b/src/config/config.h index 5bb085f4..ac28c1a2 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -44,13 +44,25 @@ // default pinout (GPIO Number) #if defined(ESP32) + // this is the default ESP32 (son-S) pinout on the WROOM modules for VSPI, + // for the ESP32-S3 there is no sane 'default', as it has full flexibility + // to map its two HW SPIs anywhere and PCBs differ materially, + // so it has to be selected in the Web UI #define DEF_CS_PIN 5 #define DEF_CE_PIN 4 #define DEF_IRQ_PIN 16 + #define DEF_MISO_PIN 19 + #define DEF_MOSI_PIN 23 + #define DEF_SCLK_PIN 18 #else #define DEF_CS_PIN 15 #define DEF_CE_PIN 2 #define DEF_IRQ_PIN 0 + // these are given to relay the correct values via API + // they cannot actually be moved for ESP82xx models + #define DEF_MISO_PIN 12 + #define DEF_MOSI_PIN 13 + #define DEF_SCLK_PIN 14 #endif // default NRF24 power, possible values (0 - 3) diff --git a/src/config/config_override_example.h b/src/config/config_override_example.h index ed976ceb..e7c06b77 100644 --- a/src/config/config_override_example.h +++ b/src/config/config_override_example.h @@ -17,14 +17,19 @@ #undef FB_WIFI_PWD #define FB_WIFI_PWD "MY_WIFI_KEY" -// ESP32 default pinout -#undef DEF_RF24_CS_PIN -#define DEF_RF24_CS_PIN 5 -#undef DEF_RF24_CE_PIN -#define DEF_RF24_CE_PIN 4 -#undef DEF_RF24_IRQ_PIN -#define DEF_RF24_IRQ_PIN 16 - +// ESP32-S3 example pinout +#undef DEF_CS_PIN +#define DEF_CS_PIN 37 +#undef DEF_CE_PIN +#define DEF_CE_PIN 38 +#undef DEF_IRQ_PIN +#define DEF_IRQ_PIN 47 +#undef DEF_MISO_PIN +#define DEF_MISO_PIN 48 +#undef DEF_MOSI_PIN +#define DEF_MOSI_PIN 35 +#undef DEF_SCLK_PIN +#define DEF_SCLK_PIN 36 // Offset for midnight Ticker Example: 1 second before midnight (local time) #undef MIDNIGHTTICKER_OFFSET diff --git a/src/config/settings.h b/src/config/settings.h index 52a24a27..ff6934c3 100644 --- a/src/config/settings.h +++ b/src/config/settings.h @@ -74,6 +74,9 @@ typedef struct { uint8_t pinCs; uint8_t pinCe; uint8_t pinIrq; + uint8_t pinMiso; + uint8_t pinMosi; + uint8_t pinSclk; uint8_t amplifierPower; } cfgNrf24_t; @@ -359,6 +362,10 @@ class settings { mCfg.nrf.pinCs = DEF_CS_PIN; mCfg.nrf.pinCe = DEF_CE_PIN; mCfg.nrf.pinIrq = DEF_IRQ_PIN; + mCfg.nrf.pinMiso = DEF_MISO_PIN; + mCfg.nrf.pinMosi = DEF_MOSI_PIN; + mCfg.nrf.pinSclk = DEF_SCLK_PIN; + mCfg.nrf.amplifierPower = DEF_AMPLIFIERPOWER & 0x03; mCfg.nrf.enabled = true; @@ -447,6 +454,9 @@ class settings { obj[F("cs")] = mCfg.nrf.pinCs; obj[F("ce")] = mCfg.nrf.pinCe; obj[F("irq")] = mCfg.nrf.pinIrq; + obj[F("sclk")] = mCfg.nrf.pinSclk; + obj[F("mosi")] = mCfg.nrf.pinMosi; + obj[F("miso")] = mCfg.nrf.pinMiso; obj[F("pwr")] = mCfg.nrf.amplifierPower; obj[F("en")] = (bool) mCfg.nrf.enabled; } else { @@ -455,12 +465,18 @@ class settings { mCfg.nrf.pinCs = obj[F("cs")]; mCfg.nrf.pinCe = obj[F("ce")]; mCfg.nrf.pinIrq = obj[F("irq")]; + mCfg.nrf.pinSclk = obj[F("sclk")]; + mCfg.nrf.pinMosi = obj[F("mosi")]; + mCfg.nrf.pinMiso = obj[F("miso")]; mCfg.nrf.amplifierPower = obj[F("pwr")]; mCfg.nrf.enabled = (bool) obj[F("en")]; if((obj[F("cs")] == obj[F("ce")])) { - mCfg.nrf.pinCs = DEF_CS_PIN; - mCfg.nrf.pinCe = DEF_CE_PIN; - mCfg.nrf.pinIrq = DEF_IRQ_PIN; + mCfg.nrf.pinCs = DEF_CS_PIN; + mCfg.nrf.pinCe = DEF_CE_PIN; + mCfg.nrf.pinIrq = DEF_IRQ_PIN; + mCfg.nrf.pinSclk = DEF_SCLK_PIN; + mCfg.nrf.pinMosi = DEF_MOSI_PIN; + mCfg.nrf.pinMiso = DEF_MISO_PIN; } } } diff --git a/src/defines.h b/src/defines.h index 05cbd23b..c9fe6aa1 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 5 -#define VERSION_PATCH 107 +#define VERSION_PATCH 109 //------------------------------------- typedef struct { diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 01eb5700..35435b3b 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -305,7 +305,7 @@ class Inverter { if (getPosByChFld(0, FLD_ACT_ACTIVE_PWR_LIMIT, rec) == pos){ actPowerLimit = rec->record[pos]; DPRINT(DBG_DEBUG, F("Inverter actual power limit: ")); - DBGPRINTLN(String(actPowerLimit, 1)); + DPRINTLN(DBG_DEBUG, String(actPowerLimit, 1)); } } else if (rec->assign == AlarmDataAssignment) { diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index dda8acb5..58a38623 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -170,7 +170,7 @@ class HmPayload { DPRINTLN(DBG_DEBUG, F("fragment number zero received and ignored")); } else { DPRINT(DBG_DEBUG, F("PID: 0x")); - DBGHEXLN(*pid); + DPRINTLN(DBG_DEBUG, String(*pid, HEX)); if ((*pid & 0x7F) < MAX_PAYLOAD_ENTRIES) { memcpy(mPayload[iv->id].data[(*pid & 0x7F) - 1], &p->packet[10], p->len - 11); mPayload[iv->id].len[(*pid & 0x7F) - 1] = p->len - 11; @@ -287,7 +287,7 @@ class HmPayload { DPRINT(DBG_INFO, F("procPyld: txid: 0x")); DBGHEXLN(mPayload[iv->id].txId); DPRINT(DBG_DEBUG, F("procPyld: max: ")); - DBGPRINTLN(String(mPayload[iv->id].maxPackId)); + DPRINTLN(DBG_DEBUG, String(mPayload[iv->id].maxPackId)); record_t<> *rec = iv->getRecordStruct(mPayload[iv->id].txCmd); // choose the parser mPayload[iv->id].complete = true; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 38dcfc30..2b78e0a9 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -10,6 +10,7 @@ #include #include "../utils/crc.h" #include "../config/config.h" +#include "SPI.h" #define SPI_SPEED 1000000 @@ -26,7 +27,7 @@ const char* const rf24AmpPowerNames[] = {"MIN", "LOW", "HIGH", "MAX"}; //----------------------------------------------------------------------------- // HM Radio class //----------------------------------------------------------------------------- -template +template class HmRadio { public: HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { @@ -57,7 +58,7 @@ class HmRadio { } ~HmRadio() {} - void setup(uint8_t ampPwr = RF24_PA_LOW, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN) { + void setup(uint8_t ampPwr = RF24_PA_LOW, uint8_t irq = IRQ_PIN, uint8_t ce = CE_PIN, uint8_t cs = CS_PIN, uint8_t sclk = SCLK_PIN, uint8_t mosi = MOSI_PIN, uint8_t miso = MISO_PIN) { DPRINTLN(DBG_VERBOSE, F("hmRadio.h:setup")); pinMode(irq, INPUT_PULLUP); @@ -79,7 +80,19 @@ class HmRadio { // change the byte order of the DTU serial number and append the required 0x01 at the end DTU_RADIO_ID = ((uint64_t)(((dtuSn >> 24) & 0xFF) | ((dtuSn >> 8) & 0xFF00) | ((dtuSn << 8) & 0xFF0000) | ((dtuSn << 24) & 0xFF000000)) << 8) | 0x01; - mNrf24.begin(ce, cs); + #ifdef ESP32 + #if CONFIG_IDF_TARGET_ESP32C3 || CONFIG_IDF_TARGET_ESP32S3 + mSpi = new SPIClass(FSPI); + #else + mSpi = new SPIClass(VSPI); + #endif + mSpi->begin(sclk, miso, mosi, cs); + #else + //the old ESP82xx cannot freely place their SPI pins + mSpi = new SPIClass(); + mSpi->begin(); + #endif + mNrf24.begin(mSpi, ce, cs); mNrf24.setRetries(3, 15); // 3*250us + 250us and 15 loops -> 15ms mNrf24.setChannel(mRfChLst[mRxChIdx]); @@ -320,6 +333,7 @@ class HmRadio { uint8_t mTxChIdx; uint8_t mRxChIdx; + SPIClass* mSpi; RF24 mNrf24; uint8_t mTxBuf[MAX_RF_PAYLOAD_SIZE]; }; diff --git a/src/platformio.ini b/src/platformio.ini index 38e67c95..4e2e92fd 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -133,3 +133,13 @@ monitor_filters = ;default ; Remove typical terminal control codes from input time ; Add timestamp with milliseconds for each new line log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory + +[env:opendtufusionv1-release] +platform = espressif32 +board = esp32-s3-devkitc-1 +build_flags = -D RELEASE -std=gnu++14 +build_unflags = -std=gnu++11 +monitor_filters = + ;default ; Remove typical terminal control codes from input + time ; Add timestamp with milliseconds for each new line + ;log2file ; Log data to a file “platformio-device-monitor-*.log” located in the current working directory diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index a2254b8d..99d35ed8 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -146,28 +146,28 @@ void DisplayEPaper::actualPowerPaged(float _totalPower, float _totalYieldDay, fl _display->setFont(&FreeSans12pt7b); y = _display->height() / 2; - _display->setCursor(0, y); + _display->setCursor(5, y); _display->print("today:"); snprintf(_fmtText, _display->width(), "%.0f", _totalYieldDay); _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); x = ((_display->width() - tbw) / 2) - tbx; _display->setCursor(x, y); _display->print(_fmtText); - _display->setCursor(_display->width() - 33, y); + _display->setCursor(_display->width() - 38, y); _display->println("Wh"); y = y + tbh + 7; - _display->setCursor(0, y); + _display->setCursor(5, y); _display->print("total:"); snprintf(_fmtText, _display->width(), "%.1f", _totalYieldTotal); _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); x = ((_display->width() - tbw) / 2) - tbx; _display->setCursor(x, y); _display->print(_fmtText); - _display->setCursor(_display->width() - 45, y); + _display->setCursor(_display->width() - 50, y); _display->println("kWh"); - _display->setCursor(0, _display->height() - (mHeadFootPadding + 10)); + _display->setCursor(10, _display->height() - (mHeadFootPadding + 10)); snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", _isprod); _display->println(_fmtText); diff --git a/src/publisher/pubMqtt.h b/src/publisher/pubMqtt.h index a529d1fc..7629f96a 100644 --- a/src/publisher/pubMqtt.h +++ b/src/publisher/pubMqtt.h @@ -38,6 +38,7 @@ typedef struct { bool running; uint8_t lastIvId; uint8_t sub; + uint8_t foundIvCnt; } discovery_t; template @@ -117,9 +118,8 @@ class PubMqtt { } void tickerMinute() { - char val[12]; - snprintf(val, 12, "%ld", millis() / 1000); - publish(subtopics[MQTT_UPTIME], val); + snprintf(mVal, 40, "%ld", millis() / 1000); + publish(subtopics[MQTT_UPTIME], mVal); publish(subtopics[MQTT_RSSI], String(WiFi.RSSI()).c_str()); publish(subtopics[MQTT_FREE_HEAP], String(ESP.getFreeHeap()).c_str()); #ifndef ESP32 @@ -151,12 +151,10 @@ class PubMqtt { } void tickerMidnight() { - char topic[7 + MQTT_TOPIC_LEN], val[4]; - // set Total YieldDay to zero - snprintf(topic, 32 + MAX_NAME_LENGTH, "total/%s", fields[FLD_YD]); - snprintf(val, 2, "0"); - publish(topic, val, true); + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "total/%s", fields[FLD_YD]); + snprintf(mVal, 2, "0"); + publish(mSubTopic, mVal, true); } void payloadEventListener(uint8_t cmd) { @@ -176,7 +174,6 @@ class PubMqtt { if(!mClient.connected()) return; - memset(mTopic, 0, MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1); if(addTopic){ snprintf(mTopic, MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1, "%s/%s", mCfgMqtt->topic, subTopic); } else { @@ -224,14 +221,13 @@ class PubMqtt { mDiscovery.running = true; mDiscovery.lastIvId = 0; mDiscovery.sub = 0; + mDiscovery.foundIvCnt = 0; } void setPowerLimitAck(Inverter<> *iv) { if (NULL != iv) { - char topic[7 + MQTT_TOPIC_LEN]; - - snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); - publish(topic, "true", true); + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/%s", iv->config->name, subtopics[MQTT_ACK_PWR_LMT]); + publish(mSubTopic, "true", true); } } @@ -245,12 +241,11 @@ class PubMqtt { tickerMinute(); publish(mLwtTopic, mqttStr[MQTT_STR_LWT_CONN], true, false); - char sub[20]; for(uint8_t i = 0; i < MAX_NUM_INVERTERS; i++) { - snprintf(sub, 20, "ctrl/limit/%d", i); - subscribe(sub); - snprintf(sub, 20, "ctrl/restart/%d", i); - subscribe(sub); + snprintf(mVal, 20, "ctrl/limit/%d", i); + subscribe(mVal); + snprintf(mVal, 20, "ctrl/restart/%d", i); + subscribe(mVal); } subscribe(subscr[MQTT_SUBS_SET_TIME]); } @@ -350,14 +345,16 @@ class PubMqtt { uint8_t fldTotal[4] = {FLD_PAC, FLD_YT, FLD_YD, FLD_PDC}; const char* unitTotal[4] = {"W", "kWh", "Wh", "W"}; - String node_mac = WiFi.macAddress().substring(12,14)+ WiFi.macAddress().substring(15,17); - String node_id = "AHOY_DTU_" + node_mac; + String node_id = String(mDevName) + "_TOTAL"; bool total = (mDiscovery.lastIvId == MAX_NUM_INVERTERS); Inverter<> *iv = mSys->getInverterByPos(mDiscovery.lastIvId); - record_t<> *rec; - if (NULL != iv) + record_t<> *rec = NULL; + if (NULL != iv) { rec = iv->getRecordStruct(RealTimeRunData_Debug); + if(0 == mDiscovery.sub) + mDiscovery.foundIvCnt++; + } if ((NULL != iv) || total) { if (!total) { @@ -412,7 +409,7 @@ class PubMqtt { if (!total) snprintf(topic, 64, "%s/sensor/%s/ch%d_%s/config", MQTT_DISCOVERY_PREFIX, iv->config->name, rec->assign[mDiscovery.sub].ch, iv->getFieldName(mDiscovery.sub, rec)); else // total values - snprintf(topic, 64, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(),fields[fldTotal[mDiscovery.sub]]); + snprintf(topic, 64, "%s/sensor/%s/total_%s/config", MQTT_DISCOVERY_PREFIX, node_id.c_str(), fields[fldTotal[mDiscovery.sub]]); size_t size = measureJson(doc2) + 1; memset(buf, 0, size); serializeJson(doc2, buf, size); @@ -420,18 +417,25 @@ class PubMqtt { if(++mDiscovery.sub == ((!total) ? (rec->length) : 4)) { mDiscovery.sub = 0; - if(++mDiscovery.lastIvId == (MAX_NUM_INVERTERS + 1)) - mDiscovery.running = false; + checkDiscoveryEnd(); } } else { mDiscovery.sub = 0; - if(++mDiscovery.lastIvId == (MAX_NUM_INVERTERS + 1)) - mDiscovery.running = false; + checkDiscoveryEnd(); } yield(); } + void checkDiscoveryEnd(void) { + if(++mDiscovery.lastIvId == MAX_NUM_INVERTERS) { + // check if only one inverter was found, then don't create 'total' sensor + if(mDiscovery.foundIvCnt == 1) + mDiscovery.running = false; + } else if(mDiscovery.lastIvId == (MAX_NUM_INVERTERS + 1)) + mDiscovery.running = false; + } + const char *getFieldDeviceClass(uint8_t fieldId) { uint8_t pos = 0; for (; pos < DEVICE_CLS_ASSIGN_LIST_LEN; pos++) { @@ -455,7 +459,6 @@ class PubMqtt { bool allAvail = true; // shows if all enabled inverters are available bool anyAvail = false; // shows if at least one enabled inverter is available bool changed = false; - char topic[7 + MQTT_TOPIC_LEN], val[40]; Inverter<> *iv; record_t<> *rec; @@ -485,19 +488,19 @@ class PubMqtt { mLastIvState[id] = status; changed = true; - snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/available", iv->config->name); - snprintf(val, 40, "%d", status); - publish(topic, val, true); + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/available", iv->config->name); + snprintf(mVal, 40, "%d", status); + publish(mSubTopic, mVal, true); - snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/last_success", iv->config->name); - snprintf(val, 40, "%d", iv->getLastTs(rec)); - publish(topic, val, true); + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/last_success", iv->config->name); + snprintf(mVal, 40, "%d", iv->getLastTs(rec)); + publish(mSubTopic, mVal, true); } } if(changed) { - snprintf(val, 32, "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); - publish("status", val, true); + snprintf(mVal, 32, "%d", ((allAvail) ? MQTT_STATUS_ONLINE : ((anyAvail) ? MQTT_STATUS_PARTIAL : MQTT_STATUS_OFFLINE))); + publish("status", mVal, true); } return anyAvail; @@ -517,7 +520,6 @@ class PubMqtt { } void sendData(Inverter<> *iv, uint8_t curInfoCmd) { - char topic[7 + MQTT_TOPIC_LEN], val[40]; record_t<> *rec = iv->getRecordStruct(curInfoCmd); if (iv->getLastTs(rec) > 0) { @@ -534,9 +536,9 @@ class PubMqtt { } } - snprintf(topic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); - snprintf(val, 40, "%g", ah::round3(iv->getValue(i, rec))); - publish(topic, val, retained); + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "%s/ch%d/%s", iv->config->name, rec->assign[i].ch, fields[rec->assign[i].fieldId]); + snprintf(mVal, 40, "%g", ah::round3(iv->getValue(i, rec))); + publish(mSubTopic, mVal, retained); yield(); } @@ -551,7 +553,6 @@ class PubMqtt { if(mSendList.empty()) return; - char topic[7 + MQTT_TOPIC_LEN], val[40]; float total[4]; bool RTRDataHasBeenSent = false; @@ -623,9 +624,9 @@ class PubMqtt { retained = false; break; } - snprintf(topic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]); - snprintf(val, 40, "%g", ah::round3(total[i])); - publish(topic, val, retained); + snprintf(mSubTopic, 32 + MAX_NAME_LENGTH, "total/%s", fields[fieldId]); + snprintf(mVal, 40, "%g", ah::round3(total[i])); + publish(mSubTopic, mVal, retained); } RTRDataHasBeenSent = true; yield(); @@ -658,9 +659,10 @@ class PubMqtt { char mLwtTopic[MQTT_TOPIC_LEN+5]; const char *mDevName, *mVersion; char mClientId[24]; // number of chars is limited to 23 up to v3.1 of MQTT - // global buffer for mqtt topic. Used when publishing mqtt messages. + // global buffer for mqtt topic. Used when publishing mqtt messages. char mTopic[MQTT_TOPIC_LEN + 32 + MAX_NAME_LENGTH + 1]; - + char mSubTopic[32 + MAX_NAME_LENGTH + 1]; + char mVal[40]; discovery_t mDiscovery; }; diff --git a/src/web/RestApi.h b/src/web/RestApi.h index 1c9a624d..ee64315b 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -387,6 +387,9 @@ class RestApi { obj[F("cs")] = mConfig->nrf.pinCs; obj[F("ce")] = mConfig->nrf.pinCe; obj[F("irq")] = mConfig->nrf.pinIrq; + obj[F("sclk")] = mConfig->nrf.pinSclk; + obj[F("mosi")] = mConfig->nrf.pinMosi; + obj[F("miso")] = mConfig->nrf.pinMiso; obj[F("led0")] = mConfig->led.led0; obj[F("led1")] = mConfig->led.led1; } diff --git a/src/web/html/setup.html b/src/web/html/setup.html index 13de33e6..7d910c91 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -367,6 +367,54 @@ [36, "VP (GPIO36)"], [39, "VN (GPIO39)"] ]; + var esp32s3pins = [ + [255, "off / default"], + [0, "GPIO0 (DONT USE - BOOT)"], + [1, "GPIO1"], + [2, "GPIO2"], + [3, "GPIO3"], + [4, "GPIO4"], + [5, "GPIO5"], + [6, "GPIO6"], + [7, "GPIO7"], + [8, "GPIO8"], + [9, "GPIO9"], + [10, "GPIO10"], + [11, "GPIO11"], + [12, "GPIO12"], + [13, "GPIO13"], + [14, "GPIO14"], + [15, "GPIO15"], + [16, "GPIO16"], + [17, "GPIO17"], + [18, "GPIO18"], + [19, "GPIO19 (DONT USE - USB-)"], + [20, "GPIO20 (DONT USE - USB+)"], + [21, "GPIO21"], + [26, "GPIO26 (PSRAM - not available)"], + [27, "GPIO27 (FLASH - not available)"], + [28, "GPIO28 (FLASH - not available)"], + [29, "GPIO29 (FLASH - not available)"], + [30, "GPIO30 (FLASH - not available)"], + [31, "GPIO31 (FLASH - not available)"], + [32, "GPIO32 (FLASH - not available)"], + [33, "GPIO33 (not exposed on WROOM modules)"], + [34, "GPIO34 (not exposed on WROOM modules)"], + [35, "GPIO35"], + [36, "GPIO36"], + [37, "GPIO37"], + [38, "GPIO38"], + [39, "GPIO39"], + [40, "GPIO40"], + [41, "GPIO41"], + [42, "GPIO42"], + [43, "GPIO43"], + [44, "GPIO44"], + [45, "GPIO45 (DONT USE - STRAPPING PIN)"], + [46, "GPIO46 (DONT USE - STRAPPING PIN)"], + [47, "GPIO47"], + [48, "GPIO48"], + ]; const re = /11[2,4,6][1,2,4].*/; @@ -613,7 +661,7 @@ } } - function parsePinout(obj, type) { + function parsePinout(obj, type, system) { var e = document.getElementById("pinout"); pins = [['led0', 'pinLed0'], ['led1', 'pinLed1']]; for(p of pins) { @@ -621,7 +669,7 @@ ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), ml("div", {class: "col-12 col-sm-9"}, - sel(p[1], ("ESP8266" == type) ? esp8266pins : esp32pins, obj[p[0]]) + sel(p[1], ("ESP8266" == type) ? esp8266pins : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj[p[0]]) ) ]) ); @@ -630,13 +678,17 @@ function parseNrfRadio(obj, type) { var e = document.getElementById("rf24"); - pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq']]; + if ("ESP8266" == type) { + pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq']]; + } else { + pins = [['cs', 'pinCs'], ['ce', 'pinCe'], ['irq', 'pinIrq'], ['sclk', 'pinSclk'], ['mosi', 'pinMosi'], ['miso', 'pinMiso']]; + } for(p of pins) { e.append( ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), ml("div", {class: "col-12 col-sm-9"}, - sel(p[1], ("ESP8266" == type) ? esp8266pins : esp32pins, obj[p[0]]) + sel(p[1], ("ESP8266" == type) ? esp8266pins : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj[p[0]]) ) ]) ); @@ -673,7 +725,7 @@ ml("div", {class: "row mb-3"}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), ml("div", {class: "col-12 col-sm-9"}, - sel(p[1], ("ESP8266" == type) ? esp8266pins : esp32pins, obj[p[0]]) + sel(p[1], ("ESP8266" == type) ? esp8266pins : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj[p[0]]) ) ]) ); @@ -686,7 +738,7 @@ document.getElementsByName("serIntvl")[0].value = obj["interval"]; } - function parseDisplay(obj, type) { + function parseDisplay(obj, type, system) { for(var i of ["disp_pwr", "disp_pxshift"]) document.getElementsByName(i)[0].checked = obj[i]; @@ -699,7 +751,7 @@ ml("div", {class: "row mb-3", id: "row_" + p[1]}, [ ml("div", {class: "col-12 col-sm-3 my-2"}, p[0].toUpperCase()), ml("div", {class: "col-12 col-sm-9"}, - sel(p[1], ("ESP8266" == type) ? esp8266pins : esp32pins, obj[p[1]]) + sel(p[1], ("ESP8266" == type) ? esp8266pins : ("ESP32-S3" == system["chip_model"]) ? esp32s3pins : esp32pins, obj[p[1]]) ) ]) ); @@ -764,12 +816,12 @@ parseMqtt(root["mqtt"]); parseNtp(root["ntp"]); parseSun(root["sun"]); - parsePinout(root["pinout"], root["system"]["esp_type"]); + parsePinout(root["pinout"], root["system"]["esp_type"], root["system"]); parseNrfRadio(root["radioNrf"], root["system"]["esp_type"]); if(root["generic"]["esp_type"] == "ESP32") parseCmtRadio(root["radioCmt"], root["system"]["esp_type"]); parseSerial(root["serial"]); - parseDisplay(root["display"], root["system"]["esp_type"]); + parseDisplay(root["display"], root["system"]["esp_type"], root["system"]); getAjax("/api/inverter/list", parseIv); } } diff --git a/src/web/web.h b/src/web/web.h index ce988c34..e7dc5331 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -33,7 +33,7 @@ #define WEB_SERIAL_BUF_SIZE 2048 -const char* const pinArgNames[] = {"pinCs", "pinCe", "pinIrq", "pinLed0", "pinLed1", "pinCsb", "pinFcsb", "pinGpio3"}; +const char* const pinArgNames[] = {"pinCs", "pinCe", "pinIrq", "pinSclk", "pinMosi", "pinMiso", "pinLed0", "pinLed1", "pinCsb", "pinFcsb", "pinGpio3"}; template class Web { @@ -521,17 +521,20 @@ class Web { // pinout uint8_t pin; - for(uint8_t i = 0; i < 8; i ++) { + for (uint8_t i = 0; i < 11; i++) { pin = request->arg(String(pinArgNames[i])).toInt(); switch(i) { - case 0: mConfig->nrf.pinCs = ((pin != 0xff) ? pin : DEF_CS_PIN); break; - case 1: mConfig->nrf.pinCe = ((pin != 0xff) ? pin : DEF_CE_PIN); break; - case 2: mConfig->nrf.pinIrq = ((pin != 0xff) ? pin : DEF_IRQ_PIN); break; - case 3: mConfig->led.led0 = pin; break; - case 4: mConfig->led.led1 = pin; break; - case 5: mConfig->cmt.pinCsb = pin; break; - case 6: mConfig->cmt.pinFcsb = pin; break; - case 7: mConfig->cmt.pinIrq = pin; break; + case 0: mConfig->nrf.pinCs = ((pin != 0xff) ? pin : DEF_CS_PIN); break; + case 1: mConfig->nrf.pinCe = ((pin != 0xff) ? pin : DEF_CE_PIN); break; + case 2: mConfig->nrf.pinIrq = ((pin != 0xff) ? pin : DEF_IRQ_PIN); break; + case 3: mConfig->nrf.pinSclk = ((pin != 0xff) ? pin : DEF_SCLK_PIN); break; + case 4: mConfig->nrf.pinMosi = ((pin != 0xff) ? pin : DEF_MOSI_PIN); break; + case 5: mConfig->nrf.pinMiso = ((pin != 0xff) ? pin : DEF_MISO_PIN); break; + case 6: mConfig->led.led0 = pin; break; + case 7: mConfig->led.led1 = pin; break; + case 8: mConfig->cmt.pinCsb = pin; break; + case 9: mConfig->cmt.pinFcsb = pin; break; + case 10: mConfig->cmt.pinIrq = pin; break; } }