From b12a161165c0a8c1b17dc8fb0c44acf009592d58 Mon Sep 17 00:00:00 2001 From: oberfritze Date: Sat, 21 Oct 2023 12:09:19 +0200 Subject: [PATCH] LittleFS hndls opt; no nrf gap tx <-> rx; new libs --- src/CHANGES.md | 12 ++-- src/app.cpp | 109 +++++++++++++++++++++++++------- src/app.h | 19 ++++-- src/appInterface.h | 3 +- src/hm/hmInverter.h | 1 + src/hm/hmPayload.h | 24 +++---- src/hm/hmRadio.h | 10 ++- src/hm/hmSystem.h | 32 ++++------ src/hm/miPayload.h | 24 +++---- src/main.cpp | 1 - src/platformio.ini | 18 ++++-- src/plugins/SML_OBIS_Parser.cpp | 14 ++-- src/web/RestApi.h | 20 +++--- src/web/web.h | 7 +- 14 files changed, 189 insertions(+), 105 deletions(-) diff --git a/src/CHANGES.md b/src/CHANGES.md index 52048f8c..ae54d727 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,21 +1,23 @@ -Changelog for ahoy-all-in-one compared to 0.6.9 of the main project +Changelog for ahoy-all-in-one compared to 0.6.9 of the main project (contains some changes from 0.7.0 and 0.7.23 to update to latest nrf24 radio lib) - configurable read SML/OBIS from UART (stream parser with min resources needed); Connections 9600,8,n,1, GND-GND, VCC-3V3, TX-TX, RX-RX - prepared to show chart of grid power and total solar ac power for current days daylight period (6 a.m. to 8 p.m.) +- save grid power and solar ac power during daylight in 10min append intervalls via LittleFS (to keep values during reset); special file handling to avoid useless garbage collections; files will be deleted at midnight - show current grid power - show max solar ac/dc power - improved radio retransmit (complete retransmit if nothing was received, but only when inverter ought to be active) for the hm series) - Heuristic for choosing the best send channel (of 5 possible) helps reducing retransmits -- optimized receiving handler for HM Inverters with 1 DC input (reduced frequency hopping and reduced answer timeout) +- optimized receiving handler for HM Inverters with 1 DC input (reduced frequency hopping, reduced answer timeout and no main thread activities between sending cmd and setting up radio for answer from inverter) - shortcut radio traces a little bit +- Testfunctions to test performance of append to file with LittleFS (commented out) DRAWBACKS: -- ESP8266: MQTT Source is commented out (except 1 var which is used for other purpose as well) -- ESP8266: only up to 2 Inverters are supported (was: 10), for ESP32: 16 +- ESP8266: MQTT function is defined out (except 1 var which is used for other purpose as well) +- ESP8266: only up to 2 Inverters are supported (parent project: 4), for ESP32: 16 - RX/TX of UART0 is used for serial interface to IR sensor. Of course you cannot operate a display that uses RX/TX pins of UART0, simultaneously. And unplug serial connection bevor updating via USB (see also below) - Due to a non-matching licence model of the charting lib certain parts of visualization.html are commented out. See comments there. - reduced platforms: only 8266 and ESP32 S3 (opendtufusionv1) currently -But: Currently there is enough heap available for stable operation on a ESP8266 plattform (WEMOS D1 R1). So adjust the number of inverters and enable MQTT to your needs and see if the AHOY-DTU is still stable in operation with your hw plattform. +Currently there is enough heap available for stable operation on a ESP8266 plattform (WEMOS D1 R1). So adjust the number of inverters and/or enable MQTT to your needs and see if the AHOY-DTU is still stable in operation with your hw plattform. To update firmware via USB, unplug serial connection to IR sensor first. Surprisingly during normal operation it seems that one can use a fully connected USB cable (for power supply). But I'm not sure if this works for all hardware plattforms. diff --git a/src/app.cpp b/src/app.cpp index daaad790..9b074af5 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -44,8 +44,9 @@ void app::setup() { else DBGPRINTLN(F("false")); - mSys.enableDebug(); - mSys.setup(&mTimestamp, mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); + mSys.setup(&mTimestamp); + 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(AP_ONLY) mInnerLoopCb = std::bind(&app::loopStandard, this); @@ -60,11 +61,11 @@ void app::setup() { mSys.addInverters(&mConfig->inst); - mPayload.setup(this, &mSys, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp); + mPayload.setup(this, &mSys, &mNrfRadio, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp); mPayload.enableSerialDebug(mConfig->serial.debug); mPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1)); - mMiPayload.setup(this, &mSys, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp); + mMiPayload.setup(this, &mSys, &mNrfRadio, &mStat, mConfig->nrf.maxRetransPerPyld, &mTimestamp); mMiPayload.enableSerialDebug(mConfig->serial.debug); mMiPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1)); @@ -73,7 +74,7 @@ void app::setup() { // DBGPRINTLN(String(ESP.getHeapFragmentation())); // DBGPRINTLN(String(ESP.getMaxFreeBlockSize())); - if (!mSys.Radio.isChipConnected()) + if (!mNrfRadio.isChipConnected()) DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); // when WiFi is in client mode, then enable mqtt broker @@ -91,7 +92,7 @@ void app::setup() { mWeb.setup(this, &mSys, mConfig); mWeb.setProtection(strlen(mConfig->sys.adminPwd) != 0); - mApi.setup(this, &mSys, mWeb.getWebSrvPtr(), mConfig); + mApi.setup(this, &mSys, &mNrfRadio, mWeb.getWebSrvPtr(), mConfig); // Plugins if (mConfig->plugin.display.type != 0) @@ -118,20 +119,19 @@ void app::loop(void) { //----------------------------------------------------------------------------- void app::loopStandard(void) { - ah::Scheduler::loop(); + if (!mNrfRadio.isTxPending ()) { + ah::Scheduler::loop(); + } - if (mSys.Radio.loop()) { - while (!mSys.Radio.mBufCtrl.empty()) { - packet_t *p = &mSys.Radio.mBufCtrl.front(); + if (mNrfRadio.loop()) { + while (!mNrfRadio.mBufCtrl.empty()) { + packet_t *p = &mNrfRadio.mBufCtrl.front(); if (mConfig->serial.debug) { #ifdef undef - DPRINT(DBG_INFO, F("RX ")); - DBGPRINT(String(p->len)); - DBGPRINT(F("B Ch")); - DBGPRINT(String(p->ch)); - DBGPRINT(F(" | ")); - mSys.Radio.dumpBuf(p->packet, p->len); + DPRINT(DBG_INFO, "RX (Ch " + String (p->ch) + "), " + + String (p->len) + " Bytes, "); + mNrfRadio.dumpBuf(p->packet, p->len); #else DPRINTLN(DBG_INFO, "RX (Ch " + String (p->ch) + "), " + String (p->len) + " Bytes"); @@ -147,7 +147,7 @@ void app::loopStandard(void) { else mMiPayload.add(iv, p); } - mSys.Radio.mBufCtrl.pop(); + mNrfRadio.mBufCtrl.pop(); yield(); } mPayload.process(true); @@ -157,16 +157,77 @@ void app::loopStandard(void) { mMiPayload.loop(); #ifdef AHOY_MQTT_SUPPORT - if (mMqttEnabled) { + if (!mNrfRadio.isTxPending () && mMqttEnabled) { mMqtt.loop(); } #endif #ifdef AHOY_SML_OBIS_SUPPORT - if (mConfig->sml_obis.ir_connected) { + if (!mNrfRadio.isTxPending () && mConfig->sml_obis.ir_connected) { sml_loop (); } #endif + +#ifdef undef +#define LITTLEFS_TEST_FILE_SIZE 1024 + 64 + 12 + // testing!!! + uint32_t cur_uptime; + static uint32_t last_uptime; + static size_t test_size; + static File test_file_1, test_file_2; + + if (((cur_uptime = getUptime()) > 30) && (last_uptime != cur_uptime) && (test_size < (LITTLEFS_TEST_FILE_SIZE))) { + FSInfo info; + uint32_t start_millis; + + if (!last_uptime) { + if ((test_file_1 = LittleFS.open ("/hist/test_1.bin", "r"))) { + DPRINTLN (DBG_INFO, "Old File 1, size " + String (test_file_1.size())); + test_file_1.close(); + test_file_1 = (File)NULL; + } + if ((test_file_2 = LittleFS.open ("/hist/test_2.bin", "r"))) { + DPRINTLN (DBG_INFO, "Old File 2, size " + String (test_file_2.size())); + test_file_2.close(); + test_file_2 = (File)NULL; + } + LittleFS.remove ("/hist/test_1.bin"); + LittleFS.remove ("/hist/test_2.bin"); + //test_file_1 = LittleFS.open ("/hist/test_1.bin", "a"); + //test_file_2 = LittleFS.open ("/hist/test_2.bin", "a"); + } + +#ifdef undef + last_uptime = cur_uptime; + + start_millis = millis(); + if (test_file_1) { + test_file_1.write ("ABCD"); + test_size = test_file_1.size (); + test_file_1.flush (); + } + if (test_file_2) { + test_file_2.write ("EFGH"); + test_file_2.flush (); + } + LittleFS.info (info); + DPRINTLN (DBG_INFO, "FS Info, total " + String (info.totalBytes) + + ", used " + String (info.usedBytes) + + ", size " + String (test_size) + + ", time " + String (millis() - start_millis)); +#endif + } else if (test_size >= LITTLEFS_TEST_FILE_SIZE) { + if (test_file_1) { + test_file_1.close (); + test_file_1 = (File)NULL; + } + if (test_file_2) { + test_file_2.close (); + test_file_2 = (File)NULL; + } + } +#endif + } //----------------------------------------------------------------------------- @@ -386,15 +447,15 @@ void app::tickMidnight(void) { //----------------------------------------------------------------------------- void app::tickSend(void) { - if (!mSys.Radio.isChipConnected()) { + if (!mNrfRadio.isChipConnected()) { DPRINTLN(DBG_WARN, F("NRF24 not connected!")); return; } if (mIVCommunicationOn && mTimestamp) { - if (!mSys.Radio.mBufCtrl.empty()) { + if (!mNrfRadio.mBufCtrl.empty()) { if (mConfig->serial.debug) { DPRINT(DBG_DEBUG, F("recbuf not empty! #")); - DBGPRINTLN(String(mSys.Radio.mBufCtrl.size())); + DBGPRINTLN(String(mNrfRadio.mBufCtrl.size())); } } @@ -533,7 +594,7 @@ void app::show_history (String path) } else { DPRINTLN (DBG_INFO, "file " + String((char *)file.name()) + ", Size: " + String (file.size())); - check_hist_file (file); // closes file + // check_hist_file (file); // closes file } } dir.close(); @@ -545,7 +606,7 @@ void app::show_history (String path) } else { DPRINTLN (DBG_INFO, "file " + dir.fileName() + ", Size: " + String (dir.fileSize())); - check_hist_file (dir.openFile ("r")); + // check_hist_file (dir.openFile ("r")); } } #endif diff --git a/src/app.h b/src/app.h index 99c1e01a..b9c50a82 100644 --- a/src/app.h +++ b/src/app.h @@ -8,14 +8,13 @@ #include #include -#include -#include #include "appInterface.h" #include "config/settings.h" #include "defines.h" -#include "hm/hmPayload.h" #include "hm/hmSystem.h" +#include "hm/hmRadio.h" +#include "hm/hmPayload.h" #include "hm/miPayload.h" #include "publisher/pubMqtt.h" #include "publisher/pubSerial.h" @@ -33,10 +32,10 @@ #define ACOS(x) (degrees(acos(x))) typedef HmSystem HmSystemType; -typedef HmPayload PayloadType; -typedef MiPayload MiPayloadType; +typedef HmPayload> PayloadType; +typedef MiPayload> MiPayloadType; typedef Web WebType; -typedef RestApi RestApiType; +typedef RestApi> RestApiType; #ifdef AHOY_MQTT_SUPPORT typedef PubMqtt PubMqttType; #endif @@ -59,7 +58,7 @@ class app : public IApp, public ah::Scheduler { void regularTickers(void); void handleIntr(void) { - mSys.Radio.handleIntr(); + mNrfRadio.handleIntr(); } uint32_t getUptime() { @@ -171,6 +170,11 @@ class app : public IApp, public ah::Scheduler { return mWeb.isProtected(request); } + void getNrfRadioCounters(uint32_t *sendCnt, uint32_t *retransmits) { + *sendCnt = mNrfRadio.mSendCnt; + *retransmits = mNrfRadio.mRetransmits; + } + uint8_t getIrqPin(void) { return mConfig->nrf.pinIrq; } @@ -207,6 +211,7 @@ class app : public IApp, public ah::Scheduler { void show_history (String path); HmSystemType mSys; + HmRadio<> mNrfRadio; private: typedef std::function innerLoopCb; diff --git a/src/appInterface.h b/src/appInterface.h index d62d57f2..2c8ed293 100644 --- a/src/appInterface.h +++ b/src/appInterface.h @@ -51,8 +51,9 @@ class IApp { virtual uint32_t getMqttRxCnt() = 0; virtual uint32_t getMqttTxCnt() = 0; #endif - virtual bool getProtection(AsyncWebServerRequest *request) = 0; + + virtual void getNrfRadioCounters (uint32_t *sendCnt, uint32_t *retransmits) = 0; }; #endif /*__IAPP_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index 5cf54194..6eabd863 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -787,6 +787,7 @@ class Inverter { { // design: every day a new start alarmCode = 0; + alarmMesIndex = 0; recordMeas.ts = 0; recordInfo.ts = 0; recordConfig.ts = 0; diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index c9c15bfd..9b522d00 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -33,14 +33,15 @@ typedef std::function payloadListenerType; typedef std::function alarmListenerType; -template +template class HmPayload { public: HmPayload() {} - void setup(IApp *app, HMSYSTEM *sys, statistics_t *stat, uint8_t maxRetransmits, uint32_t *timestamp) { + void setup(IApp *app, HMSYSTEM *sys, HMRADIO *radio, statistics_t *stat, uint8_t maxRetransmits, uint32_t *timestamp) { mApp = app; mSys = sys; + mRadio = radio; mStat = stat; mMaxRetrans = maxRetransmits; mTimestamp = timestamp; @@ -158,7 +159,7 @@ class HmPayload { DBGPRINTLN(String(iv->powerLimit[0])); } iv->mDtuTxCnt++; - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->getType(), + mRadio->sendControlPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, false); mPayload[iv->id].txCmd = iv->devControlCmd; //iv->clearCmdQueue(); @@ -169,7 +170,7 @@ class HmPayload { DBGPRINT(F("prepareDevInformCmd 0x")); DBGHEXLN(cmd); iv->mDtuTxCnt++; - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), + mRadio->prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false); mPayload[iv->id].txCmd = cmd; } @@ -255,7 +256,7 @@ class HmPayload { crcPass = build(iv->id, &pyldComplete, &Fragments); // evaluate quality of send channel with rcv params - if (retransmit && mPayload[iv->id].requested && (mPayload[iv->id].retransmits < mMaxRetrans)) { + if (retransmit && mPayload[iv->id].requested && (mPayload[iv->id].retransmits <= mMaxRetrans)) { iv->evalTxChanQuality (crcPass, mPayload[iv->id].retransmits, Fragments, mPayload[iv->id].lastFragments); DPRINT_IVID(DBG_INFO, iv->id); @@ -271,26 +272,26 @@ class HmPayload { if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { // This is required to prevent retransmissions without answer. DPRINTLN(DBG_INFO, F("Prevent retransmit on Restart / CleanState_LockAndAlarm...")); - mPayload[iv->id].retransmits = mMaxRetrans; + mPayload[iv->id].retransmits = mMaxRetrans + 1; } else if(iv->devControlCmd == ActivePowerContr) { DPRINT_IVID(DBG_INFO, iv->id); DPRINTLN(DBG_INFO, F("retransmit power limit")); iv->mDtuTxCnt++; - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->getType(), + mRadio->sendControlPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, true); } else { if(false == mPayload[iv->id].gotFragment) { DPRINT_IVID(DBG_WARN, iv->id); if (mPayload[iv->id].rxTmo) { DBGPRINTLN(F("nothing received")); - mPayload[iv->id].retransmits = mMaxRetrans; + mPayload[iv->id].retransmits = mMaxRetrans + 1; } else { DBGPRINTLN(F("nothing received: complete retransmit")); mPayload[iv->id].txCmd = iv->getQueuedCmd(); DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); iv->mDtuTxCnt++; - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), + mRadio->prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } } else { @@ -301,7 +302,7 @@ class HmPayload { DBGPRINT(String(i + 1)); DBGPRINTLN(F(" missing: Request Retransmit")); iv->mDtuTxCnt++; - mSys->Radio.sendCmdPacket(iv->radioId.u64, iv->getType(), + mRadio->sendCmdPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex (), TX_REQ_INFO, (SINGLE_FRAME + i), true); break; // only request retransmit one frame per loop } @@ -323,7 +324,7 @@ class HmPayload { DBGPRINT(F("prepareDevInformCmd 0x")); DBGHEXLN(mPayload[iv->id].txCmd); iv->mDtuTxCnt++; - mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), + mRadio->prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex (), mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); } else if (false == mPayload[iv->id].gotFragment) { // only if there is no sign of life @@ -485,6 +486,7 @@ class HmPayload { IApp *mApp; HMSYSTEM *mSys; + HMRADIO *mRadio; statistics_t *mStat; uint8_t mMaxRetrans; uint32_t *mTimestamp; diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index d1c093c2..345beecf 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -12,7 +12,7 @@ #include "../config/config.h" #include "SPI.h" -// #define AHOY_RADIO_TX_PENDING_LOOP +#define AHOY_RADIO_TX_PENDING_LOOP #define SPI_SPEED 1000000 @@ -314,6 +314,14 @@ class HmRadio { return mNrf24.isPVariant(); } + bool isTxPending (void) { +#ifdef AHOY_RADIO_TX_PENDING_LOOP + return mTxPending; +#else + return false; +#endif + } + std::queue mBufCtrl; uint32_t mSendCnt; diff --git a/src/hm/hmSystem.h b/src/hm/hmSystem.h index 551d4c7c..347455a3 100644 --- a/src/hm/hmSystem.h +++ b/src/hm/hmSystem.h @@ -7,8 +7,6 @@ #define __HM_SYSTEM_H__ #include "hmInverter.h" -#include "hmRadio.h" -#include "../config/settings.h" #define AC_POWER_PATH AHOY_HIST_PATH "/ac_power" #define AC_FORMAT_FILE_NAME "%02u_%02u_%04u.bin" @@ -16,19 +14,11 @@ template > class HmSystem { public: - HmRadio<> Radio; - HmSystem() {} - void setup() { - mNumInv = 0; - Radio.setup(); - } - - void setup(uint32_t *timestamp, uint8_t ampPwr, uint8_t irqPin, uint8_t cePin, uint8_t csPin, uint8_t sclkPin, uint8_t mosiPin, uint8_t misoPin) { + void setup(uint32_t *timestamp) { mTimestamp = timestamp; mNumInv = 0; - Radio.setup(ampPwr, irqPin, cePin, csPin, sclkPin, mosiPin, misoPin); } void addInverters(cfgInst_t *config) { @@ -129,10 +119,6 @@ class HmSystem { return MAX_NUM_INVERTERS; } - void enableDebug() { - Radio.enableDebug(); - } - //----------------------------------------------------------------------------- void cleanup_history () { @@ -155,6 +141,10 @@ class HmSystem { #endif char cur_file_name[sizeof (AC_FORMAT_FILE_NAME)]; + if (mAcPowerFile) { + mAcPowerFile.close (); + mAcPowerFile = (File)NULL; + } time_today = gTimezone.toLocal (time_today); snprintf (cur_file_name, sizeof (cur_file_name), AC_FORMAT_FILE_NAME, day(time_today), month(time_today), year(time_today)); @@ -176,7 +166,7 @@ class HmSystem { file.close (); if (path) { - DPRINTLN (DBG_INFO, "Remove file " + String (name) + + DPRINTLN (DBG_INFO, "Remove file " + String (fullName) + ", Size: " + String (ac_power_dir.size())); LittleFS.remove (path); free (path); @@ -191,7 +181,7 @@ class HmSystem { ac_power_dir = LittleFS.openDir (AC_POWER_PATH); while (ac_power_dir.next()) { if (ac_power_dir.fileName() != cur_file_name) { - DPRINTLN (DBG_INFO, "Remove file " + ac_power_dir.fileName() + + DPRINTLN (DBG_INFO, "Remove file " AC_POWER_PATH "/" + ac_power_dir.fileName() + ", Size: " + String (ac_power_dir.fileSize())); LittleFS.remove (AC_POWER_PATH "/" + ac_power_dir.fileName()); } @@ -298,24 +288,23 @@ class HmSystem { /* calc sum of all inverter averages for last interval */ /* and cleanup all counts and sums */ uint16_t pac_average = get_pac_average(true); - File file; char file_name[sizeof (AC_POWER_PATH) + sizeof (AC_FORMAT_FILE_NAME)]; snprintf (file_name, sizeof (file_name), AC_POWER_PATH "/" AC_FORMAT_FILE_NAME, day (time_today), month (time_today), year (time_today)); // append last average - if ((file = LittleFS.open (file_name, "a"))) { + if (mAcPowerFile || (mAcPowerFile = LittleFS.open (file_name, "a"))) { unsigned char buf[4]; buf[0] = cur_pac_index & 0xff; buf[1] = cur_pac_index >> 8; buf[2] = pac_average & 0xff; buf[3] = pac_average >> 8; - if (file.write (buf, sizeof (buf)) != sizeof (buf)) { + if (mAcPowerFile.write (buf, sizeof (buf)) != sizeof (buf)) { DPRINTLN (DBG_WARN, "handle_pac, failed_to_write"); } else { DPRINTLN (DBG_DEBUG, "handle_pac, write to " + String(file_name)); + mAcPowerFile.flush (); } - file.close (); } else { DPRINTLN (DBG_WARN, "handle_pac, failed to open"); } @@ -339,6 +328,7 @@ class HmSystem { uint8_t mNumInv; uint32_t *mTimestamp; uint16_t cur_pac_index; + File mAcPowerFile; }; diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index 371e3076..6a5282aa 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -38,14 +38,15 @@ typedef struct { typedef std::function miPayloadListenerType; -template +template class MiPayload { public: MiPayload() {} - void setup(IApp *app, HMSYSTEM *sys, statistics_t *stat, uint8_t maxRetransmits, uint32_t *timestamp) { + void setup(IApp *app, HMSYSTEM *sys, HMRADIO *radio, statistics_t *stat, uint8_t maxRetransmits, uint32_t *timestamp) { mApp = app; mSys = sys; + mRadio = radio; mStat = stat; mMaxRetrans = maxRetransmits; mTimestamp = timestamp; @@ -126,7 +127,7 @@ class MiPayload { DBGPRINT(F(" power limit ")); DBGPRINTLN(String(iv->powerLimit[0])); } - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->getType(), + mRadio->sendControlPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, false, false); mPayload[iv->id].txCmd = iv->devControlCmd; mPayload[iv->id].limitrequested = true; @@ -151,11 +152,11 @@ class MiPayload { if (cmd == 0x01 || cmd == SystemConfigPara ) { //0x1 and 0x05 for HM-types cmd = 0x0f; // for MI, these seem to make part of the Polling the device software and hardware version number command cmd2 = cmd == SystemConfigPara ? 0x01 : 0x00; //perhaps we can only try to get second frame? - mSys->Radio.sendCmdPacket(iv->radioId.u64, iv->getType(), + mRadio->sendCmdPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), cmd, cmd2, false, false); } else { - //mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); - mSys->Radio.sendCmdPacket(iv->radioId.u64, iv->getType(), + //mRadio->prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); + mRadio->sendCmdPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), cmd, cmd2, false, false); }; @@ -360,7 +361,7 @@ const byteAssign_t InfoAssignment[] = { DPRINT(DBG_INFO, F("Payload (")); DBGPRINT(String(payloadLen)); DBGPRINT("): "); - mSys->Radio.dumpBuf(payload, payloadLen); + mRadio->dumpBuf(payload, payloadLen); } if (NULL == rec) { @@ -454,7 +455,7 @@ const byteAssign_t InfoAssignment[] = { } else if(iv->devControlCmd == ActivePowerContr) { DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("retransmit power limit")); - mSys->Radio.sendControlPacket(iv->radioId.u64, iv->getType(), + mRadio->sendControlPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, true, false); } else { uint8_t cmd = mPayload[iv->id].txCmd; @@ -466,7 +467,7 @@ const byteAssign_t InfoAssignment[] = { mPayload[iv->id].retransmits = mMaxRetrans; } else if ( cmd == 0x0f ) { //hard/firmware request - mSys->Radio.sendCmdPacket(iv->radioId.u64, iv->getType(), + mRadio->sendCmdPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), 0x0f, 0x00, true, false); //iv->setQueuedCmdFinished(); //cmd = iv->getQueuedCmd(); @@ -504,7 +505,7 @@ const byteAssign_t InfoAssignment[] = { } DBGPRINT(F(" 0x")); DBGHEXLN(cmd); - mSys->Radio.sendCmdPacket(iv->radioId.u64, iv->getType(), + mRadio->sendCmdPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), cmd, cmd, true, false); //mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType, iv->getNextTxChanIndex(), cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd); yield(); @@ -523,7 +524,7 @@ const byteAssign_t InfoAssignment[] = { DBGPRINT(F("prepareDevInformCmd 0x")); DBGHEXLN(mPayload[iv->id].txCmd); //mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true); - mSys->Radio.sendCmdPacket(iv->radioId.u64, iv->getType(), + mRadio->sendCmdPacket(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), mPayload[iv->id].txCmd, mPayload[iv->id].txCmd, false, false); } } @@ -858,6 +859,7 @@ const byteAssign_t InfoAssignment[] = { IApp *mApp; HMSYSTEM *mSys; + HMRADIO *mRadio; statistics_t *mStat; uint8_t mMaxRetrans; uint32_t *mTimestamp; diff --git a/src/main.cpp b/src/main.cpp index af10abce..b23d1495 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -5,7 +5,6 @@ #include "utils/dbg.h" #include "app.h" -#include "config/config.h" app myApp; diff --git a/src/platformio.ini b/src/platformio.ini index c011a448..0f9785c6 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -22,29 +22,33 @@ extra_scripts = pre:web/html/convert.py lib_deps = https://github.com/yubox-node-org/ESPAsyncWebServer - nrf24/RF24@1.4.5 + nrf24/RF24@1.4.7 paulstoffregen/Time @ ^1.6.1 - https://github.com/bertmelis/espMqttClient#v1.4.2 - bblanchon/ArduinoJson @ ^6.21.2 + https://github.com/bertmelis/espMqttClient#v1.4.4 + bblanchon/ArduinoJson @ ^6.21.3 https://github.com/JChristensen/Timezone @ ^1.2.4 olikraus/U8g2 @ ^2.34.17 - zinggjm/GxEPD2 @ ^1.5.0 + zinggjm/GxEPD2 @ ^1.5.2 [env:esp8266-release] platform = espressif8266 board = esp12e board_build.f_cpu = 80000000L -build_flags = -D RELEASE +build_flags = + -D RELEASE + -std=gnu++17 + -DEMC_MIN_FREE_MEMORY=4096 + ;-Wl,-Map,output.map monitor_filters = esp8266_exception_decoder [env:opendtufusionv1-release] -platform = espressif32@>=6.1.0 +platform = espressif32@6.1.0 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin upload_speed = 115200 debug_tool = esp-builtin debug_speed = 12000 -build_flags = -D RELEASE -std=gnu++14 +build_flags = -D RELEASE -std=gnu++17 build_unflags = -std=gnu++11 monitor_filters = ;default ; Remove typical terminal control codes from input diff --git a/src/plugins/SML_OBIS_Parser.cpp b/src/plugins/SML_OBIS_Parser.cpp index 7041b762..63968d7f 100644 --- a/src/plugins/SML_OBIS_Parser.cpp +++ b/src/plugins/SML_OBIS_Parser.cpp @@ -105,6 +105,7 @@ static uint32_t *obis_timestamp; static int obis_yield_in_all_scale, obis_yield_out_all_scale; static uint64_t obis_yield_in_all_value, obis_yield_out_all_value; static bool sml_trace_obis = false; +static File mGridPowerFile; static IApp *mApp; const unsigned char version_seq[] = { SML_VERSION1_CHAR, SML_VERSION1_CHAR, SML_VERSION1_CHAR, SML_VERSION1_CHAR }; @@ -316,6 +317,10 @@ void sml_cleanup_history () #endif char cur_file_name[sizeof (SML_OBIS_FORMAT_FILE_NAME)]; + if (mGridPowerFile) { + mGridPowerFile.close(); + mGridPowerFile = (File)NULL; + } time_today = gTimezone.toLocal (time_today); snprintf (cur_file_name, sizeof (cur_file_name), SML_OBIS_FORMAT_FILE_NAME, day(time_today), month (time_today), year (time_today)); @@ -352,7 +357,7 @@ void sml_cleanup_history () while (grid_power_dir.next()) { if (grid_power_dir.fileName() != cur_file_name) { - DPRINTLN (DBG_INFO, "Remove file " + grid_power_dir.fileName() + + DPRINTLN (DBG_INFO, "Remove file " SML_OBIS_GRID_POWER_PATH "/" + grid_power_dir.fileName() + ", Size: " + String (grid_power_dir.fileSize())); LittleFS.remove (SML_OBIS_GRID_POWER_PATH "/" + grid_power_dir.fileName()); } @@ -586,24 +591,23 @@ void sml_handle_obis_pac (int16_t pac) /* calc average for last interval */ if (obis_cur_pac_cnt) { int16_t pac_average = sml_get_obis_pac_average(); - File file; char file_name[sizeof (SML_OBIS_GRID_POWER_PATH) + sizeof (SML_OBIS_FORMAT_FILE_NAME)]; snprintf (file_name, sizeof (file_name), SML_OBIS_GRID_POWER_PATH "/" SML_OBIS_FORMAT_FILE_NAME, day(time_today), month(time_today), year(time_today)); // append last average - if ((file = LittleFS.open (file_name, "a"))) { + if (mGridPowerFile || (mGridPowerFile = LittleFS.open (file_name, "a"))) { unsigned char buf[4]; buf[0] = obis_cur_pac_index & 0xff; buf[1] = obis_cur_pac_index >> 8; buf[2] = pac_average & 0xff; buf[3] = pac_average >> 8; - if (file.write (buf, sizeof (buf)) != sizeof (buf)) { + if (mGridPowerFile.write (buf, sizeof (buf)) != sizeof (buf)) { DPRINTLN (DBG_WARN, "sml_handle_obis_pac, failed_to_write"); } else { DPRINTLN (DBG_DEBUG, "sml_handle_obis_pac, write to " + String(file_name)); + mGridPowerFile.flush(); } - file.close (); } else { DPRINTLN (DBG_WARN, "sml_handle_obis_pac, failed to open"); } diff --git a/src/web/RestApi.h b/src/web/RestApi.h index af663b20..000a6127 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -28,7 +28,7 @@ const uint8_t acList[] = {FLD_UAC, FLD_IAC, FLD_PAC, FLD_F, FLD_PF, FLD_T, FLD_YT, FLD_YD, FLD_PDC, FLD_EFF, FLD_Q, FLD_MP}; const uint8_t dcList[] = {FLD_UDC, FLD_IDC, FLD_PDC, FLD_YD, FLD_YT, FLD_IRR, FLD_MP}; -template +template class RestApi { public: RestApi() { @@ -39,10 +39,11 @@ class RestApi { nr = 0; } - void setup(IApp *app, HMSYSTEM *sys, AsyncWebServer *srv, settings_t *config) { + void setup(IApp *app, HMSYSTEM *sys, HMRADIO *radio, AsyncWebServer *srv, settings_t *config) { mApp = app; mSrv = srv; mSys = sys; + mRadio = radio; mConfig = config; mSrv->on("/api", HTTP_GET, std::bind(&RestApi::onApi, this, std::placeholders::_1)); mSrv->on("/api", HTTP_POST, std::bind(&RestApi::onApiPost, this, std::placeholders::_1)).onBody( @@ -463,8 +464,8 @@ class RestApi { obj[F("rx_fail")] = stat->rxFail; obj[F("rx_fail_answer")] = stat->rxFailNoAnser; obj[F("frame_cnt")] = stat->frmCnt; - obj[F("tx_cnt")] = mSys->Radio.mSendCnt; - obj[F("retransmits")] = mSys->Radio.mRetransmits; + obj[F("tx_cnt")] = mRadio->mSendCnt; + obj[F("retransmits")] = mRadio->mRetransmits; } void getInverterList(JsonObject obj) { @@ -583,9 +584,9 @@ class RestApi { void getRadio(JsonObject obj) { obj[F("power_level")] = mConfig->nrf.amplifierPower; - obj[F("isconnected")] = mSys->Radio.isChipConnected(); - obj[F("DataRate")] = mSys->Radio.getDataRate(); - obj[F("isPVariant")] = mSys->Radio.isPVariant(); + obj[F("isconnected")] = mRadio->isChipConnected(); + obj[F("DataRate")] = mRadio->getDataRate(); + obj[F("isPVariant")] = mRadio->isPVariant(); } void getSerial(JsonObject obj) { @@ -647,9 +648,9 @@ class RestApi { } JsonArray warn = obj.createNestedArray(F("warnings")); - if(!mSys->Radio.isChipConnected()) + if(!mRadio->isChipConnected()) warn.add(F("your NRF24 module can't be reached, check the wiring and pinout")); - else if(!mSys->Radio.isPVariant()) + else if(!mRadio->isPVariant()) warn.add(F("your NRF24 module isn't a plus version(+), maybe incompatible")); if(!mApp->getSettingsValid()) warn.add(F("your settings are invalid")); @@ -807,6 +808,7 @@ class RestApi { IApp *mApp; HMSYSTEM *mSys; + HMRADIO *mRadio; AsyncWebServer *mSrv; settings_t *mConfig; diff --git a/src/web/web.h b/src/web/web.h index 5ac3c27e..61c720ef 100644 --- a/src/web/web.h +++ b/src/web/web.h @@ -575,7 +575,7 @@ class Web { mConfig->serial.debug = (request->arg("serDbg") == "on"); mConfig->serial.showIv = (request->arg("serEn") == "on"); // Needed to log TX buffers to serial console - mSys->Radio.mSerialDebug = mConfig->serial.debug; + //mSys->Radio.mSerialDebug = mConfig->serial.debug; } #ifdef AHOY_SML_OBIS_SUPPORT @@ -676,11 +676,14 @@ class Web { // NRF Statistics stat = mApp->getStatistics(); + uint32_t nrfSendCnt, nrfRetransmits; + mApp->nrfGetRadioCounters (nrfSendCnt, nrfRetransmits); metrics += radioStatistic(F("rx_success"), stat->rxSuccess); metrics += radioStatistic(F("rx_fail"), stat->rxFail); metrics += radioStatistic(F("rx_fail_answer"), stat->rxFailNoAnser); metrics += radioStatistic(F("frame_cnt"), stat->frmCnt); - metrics += radioStatistic(F("tx_cnt"), mSys->Radio.mSendCnt); + metrics += radioStatistic(F("tx_cnt"), *nrfSendCnt); + metrics += radioStatistic(F("tx_retransmits"), *nrfRetransmits); len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str()); // Start Inverter loop