Browse Source

LittleFS hndls opt; no nrf gap tx <-> rx; new libs

pull/1080/head
oberfritze 2 years ago
parent
commit
b12a161165
  1. 12
      src/CHANGES.md
  2. 107
      src/app.cpp
  3. 19
      src/app.h
  4. 3
      src/appInterface.h
  5. 1
      src/hm/hmInverter.h
  6. 24
      src/hm/hmPayload.h
  7. 10
      src/hm/hmRadio.h
  8. 32
      src/hm/hmSystem.h
  9. 24
      src/hm/miPayload.h
  10. 1
      src/main.cpp
  11. 18
      src/platformio.ini
  12. 14
      src/plugins/SML_OBIS_Parser.cpp
  13. 20
      src/web/RestApi.h
  14. 7
      src/web/web.h

12
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 - 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.) - 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 current grid power
- show max solar ac/dc 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) - 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 - 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 - shortcut radio traces a little bit
- Testfunctions to test performance of append to file with LittleFS (commented out)
DRAWBACKS: DRAWBACKS:
- ESP8266: MQTT Source is commented out (except 1 var which is used for other purpose as well) - 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 (was: 10), for ESP32: 16 - 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) - 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. - 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 - 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. 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.

107
src/app.cpp

@ -44,8 +44,9 @@ void app::setup() {
else else
DBGPRINTLN(F("false")); DBGPRINTLN(F("false"));
mSys.enableDebug(); mSys.setup(&mTimestamp);
mSys.setup(&mTimestamp, mConfig->nrf.amplifierPower, mConfig->nrf.pinIrq, mConfig->nrf.pinCe, mConfig->nrf.pinCs, mConfig->nrf.pinSclk, mConfig->nrf.pinMosi, mConfig->nrf.pinMiso); 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) #if defined(AP_ONLY)
mInnerLoopCb = std::bind(&app::loopStandard, this); mInnerLoopCb = std::bind(&app::loopStandard, this);
@ -60,11 +61,11 @@ void app::setup() {
mSys.addInverters(&mConfig->inst); 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.enableSerialDebug(mConfig->serial.debug);
mPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1)); 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.enableSerialDebug(mConfig->serial.debug);
mMiPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1)); mMiPayload.addPayloadListener(std::bind(&app::payloadEventListener, this, std::placeholders::_1));
@ -73,7 +74,7 @@ void app::setup() {
// DBGPRINTLN(String(ESP.getHeapFragmentation())); // DBGPRINTLN(String(ESP.getHeapFragmentation()));
// DBGPRINTLN(String(ESP.getMaxFreeBlockSize())); // 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")); 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 // when WiFi is in client mode, then enable mqtt broker
@ -91,7 +92,7 @@ void app::setup() {
mWeb.setup(this, &mSys, mConfig); mWeb.setup(this, &mSys, mConfig);
mWeb.setProtection(strlen(mConfig->sys.adminPwd) != 0); mWeb.setProtection(strlen(mConfig->sys.adminPwd) != 0);
mApi.setup(this, &mSys, mWeb.getWebSrvPtr(), mConfig); mApi.setup(this, &mSys, &mNrfRadio, mWeb.getWebSrvPtr(), mConfig);
// Plugins // Plugins
if (mConfig->plugin.display.type != 0) if (mConfig->plugin.display.type != 0)
@ -118,20 +119,19 @@ void app::loop(void) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void app::loopStandard(void) { void app::loopStandard(void) {
if (!mNrfRadio.isTxPending ()) {
ah::Scheduler::loop(); ah::Scheduler::loop();
}
if (mSys.Radio.loop()) { if (mNrfRadio.loop()) {
while (!mSys.Radio.mBufCtrl.empty()) { while (!mNrfRadio.mBufCtrl.empty()) {
packet_t *p = &mSys.Radio.mBufCtrl.front(); packet_t *p = &mNrfRadio.mBufCtrl.front();
if (mConfig->serial.debug) { if (mConfig->serial.debug) {
#ifdef undef #ifdef undef
DPRINT(DBG_INFO, F("RX ")); DPRINT(DBG_INFO, "RX (Ch " + String (p->ch) + "), " +
DBGPRINT(String(p->len)); String (p->len) + " Bytes, ");
DBGPRINT(F("B Ch")); mNrfRadio.dumpBuf(p->packet, p->len);
DBGPRINT(String(p->ch));
DBGPRINT(F(" | "));
mSys.Radio.dumpBuf(p->packet, p->len);
#else #else
DPRINTLN(DBG_INFO, "RX (Ch " + String (p->ch) + "), " + DPRINTLN(DBG_INFO, "RX (Ch " + String (p->ch) + "), " +
String (p->len) + " Bytes"); String (p->len) + " Bytes");
@ -147,7 +147,7 @@ void app::loopStandard(void) {
else else
mMiPayload.add(iv, p); mMiPayload.add(iv, p);
} }
mSys.Radio.mBufCtrl.pop(); mNrfRadio.mBufCtrl.pop();
yield(); yield();
} }
mPayload.process(true); mPayload.process(true);
@ -157,16 +157,77 @@ void app::loopStandard(void) {
mMiPayload.loop(); mMiPayload.loop();
#ifdef AHOY_MQTT_SUPPORT #ifdef AHOY_MQTT_SUPPORT
if (mMqttEnabled) { if (!mNrfRadio.isTxPending () && mMqttEnabled) {
mMqtt.loop(); mMqtt.loop();
} }
#endif #endif
#ifdef AHOY_SML_OBIS_SUPPORT #ifdef AHOY_SML_OBIS_SUPPORT
if (mConfig->sml_obis.ir_connected) { if (!mNrfRadio.isTxPending () && mConfig->sml_obis.ir_connected) {
sml_loop (); sml_loop ();
} }
#endif #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) { void app::tickSend(void) {
if (!mSys.Radio.isChipConnected()) { if (!mNrfRadio.isChipConnected()) {
DPRINTLN(DBG_WARN, F("NRF24 not connected!")); DPRINTLN(DBG_WARN, F("NRF24 not connected!"));
return; return;
} }
if (mIVCommunicationOn && mTimestamp) { if (mIVCommunicationOn && mTimestamp) {
if (!mSys.Radio.mBufCtrl.empty()) { if (!mNrfRadio.mBufCtrl.empty()) {
if (mConfig->serial.debug) { if (mConfig->serial.debug) {
DPRINT(DBG_DEBUG, F("recbuf not empty! #")); 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 { } else {
DPRINTLN (DBG_INFO, "file " + String((char *)file.name()) + DPRINTLN (DBG_INFO, "file " + String((char *)file.name()) +
", Size: " + String (file.size())); ", Size: " + String (file.size()));
check_hist_file (file); // closes file // check_hist_file (file); // closes file
} }
} }
dir.close(); dir.close();
@ -545,7 +606,7 @@ void app::show_history (String path)
} else { } else {
DPRINTLN (DBG_INFO, "file " + dir.fileName() + DPRINTLN (DBG_INFO, "file " + dir.fileName() +
", Size: " + String (dir.fileSize())); ", Size: " + String (dir.fileSize()));
check_hist_file (dir.openFile ("r")); // check_hist_file (dir.openFile ("r"));
} }
} }
#endif #endif

19
src/app.h

@ -8,14 +8,13 @@
#include <Arduino.h> #include <Arduino.h>
#include <ArduinoJson.h> #include <ArduinoJson.h>
#include <RF24.h>
#include <RF24_config.h>
#include "appInterface.h" #include "appInterface.h"
#include "config/settings.h" #include "config/settings.h"
#include "defines.h" #include "defines.h"
#include "hm/hmPayload.h"
#include "hm/hmSystem.h" #include "hm/hmSystem.h"
#include "hm/hmRadio.h"
#include "hm/hmPayload.h"
#include "hm/miPayload.h" #include "hm/miPayload.h"
#include "publisher/pubMqtt.h" #include "publisher/pubMqtt.h"
#include "publisher/pubSerial.h" #include "publisher/pubSerial.h"
@ -33,10 +32,10 @@
#define ACOS(x) (degrees(acos(x))) #define ACOS(x) (degrees(acos(x)))
typedef HmSystem<MAX_NUM_INVERTERS> HmSystemType; typedef HmSystem<MAX_NUM_INVERTERS> HmSystemType;
typedef HmPayload<HmSystemType> PayloadType; typedef HmPayload<HmSystemType, HmRadio<>> PayloadType;
typedef MiPayload<HmSystemType> MiPayloadType; typedef MiPayload<HmSystemType, HmRadio<>> MiPayloadType;
typedef Web<HmSystemType> WebType; typedef Web<HmSystemType> WebType;
typedef RestApi<HmSystemType> RestApiType; typedef RestApi<HmSystemType, HmRadio<>> RestApiType;
#ifdef AHOY_MQTT_SUPPORT #ifdef AHOY_MQTT_SUPPORT
typedef PubMqtt<HmSystemType> PubMqttType; typedef PubMqtt<HmSystemType> PubMqttType;
#endif #endif
@ -59,7 +58,7 @@ class app : public IApp, public ah::Scheduler {
void regularTickers(void); void regularTickers(void);
void handleIntr(void) { void handleIntr(void) {
mSys.Radio.handleIntr(); mNrfRadio.handleIntr();
} }
uint32_t getUptime() { uint32_t getUptime() {
@ -171,6 +170,11 @@ class app : public IApp, public ah::Scheduler {
return mWeb.isProtected(request); return mWeb.isProtected(request);
} }
void getNrfRadioCounters(uint32_t *sendCnt, uint32_t *retransmits) {
*sendCnt = mNrfRadio.mSendCnt;
*retransmits = mNrfRadio.mRetransmits;
}
uint8_t getIrqPin(void) { uint8_t getIrqPin(void) {
return mConfig->nrf.pinIrq; return mConfig->nrf.pinIrq;
} }
@ -207,6 +211,7 @@ class app : public IApp, public ah::Scheduler {
void show_history (String path); void show_history (String path);
HmSystemType mSys; HmSystemType mSys;
HmRadio<> mNrfRadio;
private: private:
typedef std::function<void()> innerLoopCb; typedef std::function<void()> innerLoopCb;

3
src/appInterface.h

@ -51,8 +51,9 @@ class IApp {
virtual uint32_t getMqttRxCnt() = 0; virtual uint32_t getMqttRxCnt() = 0;
virtual uint32_t getMqttTxCnt() = 0; virtual uint32_t getMqttTxCnt() = 0;
#endif #endif
virtual bool getProtection(AsyncWebServerRequest *request) = 0; virtual bool getProtection(AsyncWebServerRequest *request) = 0;
virtual void getNrfRadioCounters (uint32_t *sendCnt, uint32_t *retransmits) = 0;
}; };
#endif /*__IAPP_H__*/ #endif /*__IAPP_H__*/

1
src/hm/hmInverter.h

@ -787,6 +787,7 @@ class Inverter {
{ {
// design: every day a new start // design: every day a new start
alarmCode = 0; alarmCode = 0;
alarmMesIndex = 0;
recordMeas.ts = 0; recordMeas.ts = 0;
recordInfo.ts = 0; recordInfo.ts = 0;
recordConfig.ts = 0; recordConfig.ts = 0;

24
src/hm/hmPayload.h

@ -33,14 +33,15 @@ typedef std::function<void(uint8_t)> payloadListenerType;
typedef std::function<void(uint16_t alarmCode, uint32_t start, uint32_t end)> alarmListenerType; typedef std::function<void(uint16_t alarmCode, uint32_t start, uint32_t end)> alarmListenerType;
template<class HMSYSTEM> template<class HMSYSTEM, class HMRADIO>
class HmPayload { class HmPayload {
public: public:
HmPayload() {} 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; mApp = app;
mSys = sys; mSys = sys;
mRadio = radio;
mStat = stat; mStat = stat;
mMaxRetrans = maxRetransmits; mMaxRetrans = maxRetransmits;
mTimestamp = timestamp; mTimestamp = timestamp;
@ -158,7 +159,7 @@ class HmPayload {
DBGPRINTLN(String(iv->powerLimit[0])); DBGPRINTLN(String(iv->powerLimit[0]));
} }
iv->mDtuTxCnt++; iv->mDtuTxCnt++;
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->getType(), mRadio->sendControlPacket(iv->radioId.u64, iv->getType(),
iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, false); iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, false);
mPayload[iv->id].txCmd = iv->devControlCmd; mPayload[iv->id].txCmd = iv->devControlCmd;
//iv->clearCmdQueue(); //iv->clearCmdQueue();
@ -169,7 +170,7 @@ class HmPayload {
DBGPRINT(F("prepareDevInformCmd 0x")); DBGPRINT(F("prepareDevInformCmd 0x"));
DBGHEXLN(cmd); DBGHEXLN(cmd);
iv->mDtuTxCnt++; 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); iv->getNextTxChanIndex(), cmd, mPayload[iv->id].ts, iv->alarmMesIndex, false);
mPayload[iv->id].txCmd = cmd; mPayload[iv->id].txCmd = cmd;
} }
@ -255,7 +256,7 @@ class HmPayload {
crcPass = build(iv->id, &pyldComplete, &Fragments); crcPass = build(iv->id, &pyldComplete, &Fragments);
// evaluate quality of send channel with rcv params // 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, iv->evalTxChanQuality (crcPass, mPayload[iv->id].retransmits,
Fragments, mPayload[iv->id].lastFragments); Fragments, mPayload[iv->id].lastFragments);
DPRINT_IVID(DBG_INFO, iv->id); DPRINT_IVID(DBG_INFO, iv->id);
@ -271,26 +272,26 @@ class HmPayload {
if (iv->devControlCmd == Restart || iv->devControlCmd == CleanState_LockAndAlarm) { 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 = mMaxRetrans; mPayload[iv->id].retransmits = mMaxRetrans + 1;
} else if(iv->devControlCmd == ActivePowerContr) { } else if(iv->devControlCmd == ActivePowerContr) {
DPRINT_IVID(DBG_INFO, iv->id); DPRINT_IVID(DBG_INFO, iv->id);
DPRINTLN(DBG_INFO, F("retransmit power limit")); DPRINTLN(DBG_INFO, F("retransmit power limit"));
iv->mDtuTxCnt++; iv->mDtuTxCnt++;
mSys->Radio.sendControlPacket(iv->radioId.u64, iv->getType(), mRadio->sendControlPacket(iv->radioId.u64, iv->getType(),
iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, true); iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, true);
} else { } else {
if(false == mPayload[iv->id].gotFragment) { if(false == mPayload[iv->id].gotFragment) {
DPRINT_IVID(DBG_WARN, iv->id); DPRINT_IVID(DBG_WARN, iv->id);
if (mPayload[iv->id].rxTmo) { if (mPayload[iv->id].rxTmo) {
DBGPRINTLN(F("nothing received")); DBGPRINTLN(F("nothing received"));
mPayload[iv->id].retransmits = mMaxRetrans; mPayload[iv->id].retransmits = mMaxRetrans + 1;
} else { } else {
DBGPRINTLN(F("nothing received: complete retransmit")); DBGPRINTLN(F("nothing received: complete retransmit"));
mPayload[iv->id].txCmd = iv->getQueuedCmd(); mPayload[iv->id].txCmd = iv->getQueuedCmd();
DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX)); DPRINTLN(DBG_INFO, F("(#") + String(iv->id) + F(") prepareDevInformCmd 0x") + String(mPayload[iv->id].txCmd, HEX));
iv->mDtuTxCnt++; 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); iv->getNextTxChanIndex(), mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true);
} }
} else { } else {
@ -301,7 +302,7 @@ class HmPayload {
DBGPRINT(String(i + 1)); DBGPRINT(String(i + 1));
DBGPRINTLN(F(" missing: Request Retransmit")); DBGPRINTLN(F(" missing: Request Retransmit"));
iv->mDtuTxCnt++; 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); iv->getNextTxChanIndex (), TX_REQ_INFO, (SINGLE_FRAME + i), true);
break; // only request retransmit one frame per loop break; // only request retransmit one frame per loop
} }
@ -323,7 +324,7 @@ class HmPayload {
DBGPRINT(F("prepareDevInformCmd 0x")); DBGPRINT(F("prepareDevInformCmd 0x"));
DBGHEXLN(mPayload[iv->id].txCmd); DBGHEXLN(mPayload[iv->id].txCmd);
iv->mDtuTxCnt++; 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); iv->getNextTxChanIndex (), mPayload[iv->id].txCmd, mPayload[iv->id].ts, iv->alarmMesIndex, true);
} else if (false == mPayload[iv->id].gotFragment) { } else if (false == mPayload[iv->id].gotFragment) {
// only if there is no sign of life // only if there is no sign of life
@ -485,6 +486,7 @@ class HmPayload {
IApp *mApp; IApp *mApp;
HMSYSTEM *mSys; HMSYSTEM *mSys;
HMRADIO *mRadio;
statistics_t *mStat; statistics_t *mStat;
uint8_t mMaxRetrans; uint8_t mMaxRetrans;
uint32_t *mTimestamp; uint32_t *mTimestamp;

10
src/hm/hmRadio.h

@ -12,7 +12,7 @@
#include "../config/config.h" #include "../config/config.h"
#include "SPI.h" #include "SPI.h"
// #define AHOY_RADIO_TX_PENDING_LOOP #define AHOY_RADIO_TX_PENDING_LOOP
#define SPI_SPEED 1000000 #define SPI_SPEED 1000000
@ -314,6 +314,14 @@ class HmRadio {
return mNrf24.isPVariant(); return mNrf24.isPVariant();
} }
bool isTxPending (void) {
#ifdef AHOY_RADIO_TX_PENDING_LOOP
return mTxPending;
#else
return false;
#endif
}
std::queue<packet_t> mBufCtrl; std::queue<packet_t> mBufCtrl;
uint32_t mSendCnt; uint32_t mSendCnt;

32
src/hm/hmSystem.h

@ -7,8 +7,6 @@
#define __HM_SYSTEM_H__ #define __HM_SYSTEM_H__
#include "hmInverter.h" #include "hmInverter.h"
#include "hmRadio.h"
#include "../config/settings.h"
#define AC_POWER_PATH AHOY_HIST_PATH "/ac_power" #define AC_POWER_PATH AHOY_HIST_PATH "/ac_power"
#define AC_FORMAT_FILE_NAME "%02u_%02u_%04u.bin" #define AC_FORMAT_FILE_NAME "%02u_%02u_%04u.bin"
@ -16,19 +14,11 @@
template <uint8_t MAX_INVERTER=3, class INVERTERTYPE=Inverter<float>> template <uint8_t MAX_INVERTER=3, class INVERTERTYPE=Inverter<float>>
class HmSystem { class HmSystem {
public: public:
HmRadio<> Radio;
HmSystem() {} HmSystem() {}
void setup() { void setup(uint32_t *timestamp) {
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) {
mTimestamp = timestamp; mTimestamp = timestamp;
mNumInv = 0; mNumInv = 0;
Radio.setup(ampPwr, irqPin, cePin, csPin, sclkPin, mosiPin, misoPin);
} }
void addInverters(cfgInst_t *config) { void addInverters(cfgInst_t *config) {
@ -129,10 +119,6 @@ class HmSystem {
return MAX_NUM_INVERTERS; return MAX_NUM_INVERTERS;
} }
void enableDebug() {
Radio.enableDebug();
}
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
void cleanup_history () void cleanup_history ()
{ {
@ -155,6 +141,10 @@ class HmSystem {
#endif #endif
char cur_file_name[sizeof (AC_FORMAT_FILE_NAME)]; char cur_file_name[sizeof (AC_FORMAT_FILE_NAME)];
if (mAcPowerFile) {
mAcPowerFile.close ();
mAcPowerFile = (File)NULL;
}
time_today = gTimezone.toLocal (time_today); time_today = gTimezone.toLocal (time_today);
snprintf (cur_file_name, sizeof (cur_file_name), AC_FORMAT_FILE_NAME, snprintf (cur_file_name, sizeof (cur_file_name), AC_FORMAT_FILE_NAME,
day(time_today), month(time_today), year(time_today)); day(time_today), month(time_today), year(time_today));
@ -176,7 +166,7 @@ class HmSystem {
file.close (); file.close ();
if (path) { if (path) {
DPRINTLN (DBG_INFO, "Remove file " + String (name) + DPRINTLN (DBG_INFO, "Remove file " + String (fullName) +
", Size: " + String (ac_power_dir.size())); ", Size: " + String (ac_power_dir.size()));
LittleFS.remove (path); LittleFS.remove (path);
free (path); free (path);
@ -191,7 +181,7 @@ class HmSystem {
ac_power_dir = LittleFS.openDir (AC_POWER_PATH); ac_power_dir = LittleFS.openDir (AC_POWER_PATH);
while (ac_power_dir.next()) { while (ac_power_dir.next()) {
if (ac_power_dir.fileName() != cur_file_name) { 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())); ", Size: " + String (ac_power_dir.fileSize()));
LittleFS.remove (AC_POWER_PATH "/" + ac_power_dir.fileName()); LittleFS.remove (AC_POWER_PATH "/" + ac_power_dir.fileName());
} }
@ -298,24 +288,23 @@ class HmSystem {
/* calc sum of all inverter averages for last interval */ /* calc sum of all inverter averages for last interval */
/* and cleanup all counts and sums */ /* and cleanup all counts and sums */
uint16_t pac_average = get_pac_average(true); uint16_t pac_average = get_pac_average(true);
File file;
char file_name[sizeof (AC_POWER_PATH) + sizeof (AC_FORMAT_FILE_NAME)]; 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, snprintf (file_name, sizeof (file_name), AC_POWER_PATH "/" AC_FORMAT_FILE_NAME,
day (time_today), month (time_today), year (time_today)); day (time_today), month (time_today), year (time_today));
// append last average // append last average
if ((file = LittleFS.open (file_name, "a"))) { if (mAcPowerFile || (mAcPowerFile = LittleFS.open (file_name, "a"))) {
unsigned char buf[4]; unsigned char buf[4];
buf[0] = cur_pac_index & 0xff; buf[0] = cur_pac_index & 0xff;
buf[1] = cur_pac_index >> 8; buf[1] = cur_pac_index >> 8;
buf[2] = pac_average & 0xff; buf[2] = pac_average & 0xff;
buf[3] = pac_average >> 8; 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"); DPRINTLN (DBG_WARN, "handle_pac, failed_to_write");
} else { } else {
DPRINTLN (DBG_DEBUG, "handle_pac, write to " + String(file_name)); DPRINTLN (DBG_DEBUG, "handle_pac, write to " + String(file_name));
mAcPowerFile.flush ();
} }
file.close ();
} else { } else {
DPRINTLN (DBG_WARN, "handle_pac, failed to open"); DPRINTLN (DBG_WARN, "handle_pac, failed to open");
} }
@ -339,6 +328,7 @@ class HmSystem {
uint8_t mNumInv; uint8_t mNumInv;
uint32_t *mTimestamp; uint32_t *mTimestamp;
uint16_t cur_pac_index; uint16_t cur_pac_index;
File mAcPowerFile;
}; };

24
src/hm/miPayload.h

@ -38,14 +38,15 @@ typedef struct {
typedef std::function<void(uint8_t)> miPayloadListenerType; typedef std::function<void(uint8_t)> miPayloadListenerType;
template<class HMSYSTEM> template<class HMSYSTEM, class HMRADIO>
class MiPayload { class MiPayload {
public: public:
MiPayload() {} 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; mApp = app;
mSys = sys; mSys = sys;
mRadio = radio;
mStat = stat; mStat = stat;
mMaxRetrans = maxRetransmits; mMaxRetrans = maxRetransmits;
mTimestamp = timestamp; mTimestamp = timestamp;
@ -126,7 +127,7 @@ class MiPayload {
DBGPRINT(F(" power limit ")); DBGPRINT(F(" power limit "));
DBGPRINTLN(String(iv->powerLimit[0])); 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); iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, false, false);
mPayload[iv->id].txCmd = iv->devControlCmd; mPayload[iv->id].txCmd = iv->devControlCmd;
mPayload[iv->id].limitrequested = true; mPayload[iv->id].limitrequested = true;
@ -151,11 +152,11 @@ class MiPayload {
if (cmd == 0x01 || cmd == SystemConfigPara ) { //0x1 and 0x05 for HM-types 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 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? 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); iv->getNextTxChanIndex(), cmd, cmd2, false, false);
} else { } else {
//mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType(), iv->getNextTxChanIndex(), cmd2, mPayload[iv->id].ts, iv->alarmMesIndex, false, cmd); //mRadio->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->sendCmdPacket(iv->radioId.u64, iv->getType(),
iv->getNextTxChanIndex(), cmd, cmd2, false, false); iv->getNextTxChanIndex(), cmd, cmd2, false, false);
}; };
@ -360,7 +361,7 @@ const byteAssign_t InfoAssignment[] = {
DPRINT(DBG_INFO, F("Payload (")); DPRINT(DBG_INFO, F("Payload ("));
DBGPRINT(String(payloadLen)); DBGPRINT(String(payloadLen));
DBGPRINT("): "); DBGPRINT("): ");
mSys->Radio.dumpBuf(payload, payloadLen); mRadio->dumpBuf(payload, payloadLen);
} }
if (NULL == rec) { if (NULL == rec) {
@ -454,7 +455,7 @@ const byteAssign_t InfoAssignment[] = {
} else if(iv->devControlCmd == ActivePowerContr) { } else if(iv->devControlCmd == ActivePowerContr) {
DPRINT_IVID(DBG_INFO, iv->id); DPRINT_IVID(DBG_INFO, iv->id);
DBGPRINTLN(F("retransmit power limit")); 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); iv->getNextTxChanIndex(), iv->devControlCmd, iv->powerLimit, true, false);
} else { } else {
uint8_t cmd = mPayload[iv->id].txCmd; uint8_t cmd = mPayload[iv->id].txCmd;
@ -466,7 +467,7 @@ const byteAssign_t InfoAssignment[] = {
mPayload[iv->id].retransmits = mMaxRetrans; mPayload[iv->id].retransmits = mMaxRetrans;
} else if ( cmd == 0x0f ) { } else if ( cmd == 0x0f ) {
//hard/firmware request //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->getNextTxChanIndex(), 0x0f, 0x00, true, false);
//iv->setQueuedCmdFinished(); //iv->setQueuedCmdFinished();
//cmd = iv->getQueuedCmd(); //cmd = iv->getQueuedCmd();
@ -504,7 +505,7 @@ const byteAssign_t InfoAssignment[] = {
} }
DBGPRINT(F(" 0x")); DBGPRINT(F(" 0x"));
DBGHEXLN(cmd); DBGHEXLN(cmd);
mSys->Radio.sendCmdPacket(iv->radioId.u64, iv->getType(), mRadio->sendCmdPacket(iv->radioId.u64, iv->getType(),
iv->getNextTxChanIndex(), cmd, cmd, true, false); 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); //mSys->Radio.prepareDevInformCmd(iv->radioId.u64, iv->getType, iv->getNextTxChanIndex(), cmd, mPayload[iv->id].ts, iv->alarmMesIndex, true, cmd);
yield(); yield();
@ -523,7 +524,7 @@ const byteAssign_t InfoAssignment[] = {
DBGPRINT(F("prepareDevInformCmd 0x")); DBGPRINT(F("prepareDevInformCmd 0x"));
DBGHEXLN(mPayload[iv->id].txCmd); 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.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); iv->getNextTxChanIndex(), mPayload[iv->id].txCmd, mPayload[iv->id].txCmd, false, false);
} }
} }
@ -858,6 +859,7 @@ const byteAssign_t InfoAssignment[] = {
IApp *mApp; IApp *mApp;
HMSYSTEM *mSys; HMSYSTEM *mSys;
HMRADIO *mRadio;
statistics_t *mStat; statistics_t *mStat;
uint8_t mMaxRetrans; uint8_t mMaxRetrans;
uint32_t *mTimestamp; uint32_t *mTimestamp;

1
src/main.cpp

@ -5,7 +5,6 @@
#include "utils/dbg.h" #include "utils/dbg.h"
#include "app.h" #include "app.h"
#include "config/config.h"
app myApp; app myApp;

18
src/platformio.ini

@ -22,29 +22,33 @@ extra_scripts =
pre:web/html/convert.py pre:web/html/convert.py
lib_deps = lib_deps =
https://github.com/yubox-node-org/ESPAsyncWebServer https://github.com/yubox-node-org/ESPAsyncWebServer
nrf24/RF24@1.4.5 nrf24/RF24@1.4.7
paulstoffregen/Time @ ^1.6.1 paulstoffregen/Time @ ^1.6.1
https://github.com/bertmelis/espMqttClient#v1.4.2 https://github.com/bertmelis/espMqttClient#v1.4.4
bblanchon/ArduinoJson @ ^6.21.2 bblanchon/ArduinoJson @ ^6.21.3
https://github.com/JChristensen/Timezone @ ^1.2.4 https://github.com/JChristensen/Timezone @ ^1.2.4
olikraus/U8g2 @ ^2.34.17 olikraus/U8g2 @ ^2.34.17
zinggjm/GxEPD2 @ ^1.5.0 zinggjm/GxEPD2 @ ^1.5.2
[env:esp8266-release] [env:esp8266-release]
platform = espressif8266 platform = espressif8266
board = esp12e board = esp12e
board_build.f_cpu = 80000000L 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 monitor_filters = esp8266_exception_decoder
[env:opendtufusionv1-release] [env:opendtufusionv1-release]
platform = espressif32@>=6.1.0 platform = espressif32@6.1.0
board = esp32-s3-devkitc-1 board = esp32-s3-devkitc-1
upload_protocol = esp-builtin upload_protocol = esp-builtin
upload_speed = 115200 upload_speed = 115200
debug_tool = esp-builtin debug_tool = esp-builtin
debug_speed = 12000 debug_speed = 12000
build_flags = -D RELEASE -std=gnu++14 build_flags = -D RELEASE -std=gnu++17
build_unflags = -std=gnu++11 build_unflags = -std=gnu++11
monitor_filters = monitor_filters =
;default ; Remove typical terminal control codes from input ;default ; Remove typical terminal control codes from input

14
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 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 uint64_t obis_yield_in_all_value, obis_yield_out_all_value;
static bool sml_trace_obis = false; static bool sml_trace_obis = false;
static File mGridPowerFile;
static IApp *mApp; static IApp *mApp;
const unsigned char version_seq[] = { SML_VERSION1_CHAR, SML_VERSION1_CHAR, SML_VERSION1_CHAR, SML_VERSION1_CHAR }; 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 #endif
char cur_file_name[sizeof (SML_OBIS_FORMAT_FILE_NAME)]; char cur_file_name[sizeof (SML_OBIS_FORMAT_FILE_NAME)];
if (mGridPowerFile) {
mGridPowerFile.close();
mGridPowerFile = (File)NULL;
}
time_today = gTimezone.toLocal (time_today); time_today = gTimezone.toLocal (time_today);
snprintf (cur_file_name, sizeof (cur_file_name), SML_OBIS_FORMAT_FILE_NAME, snprintf (cur_file_name, sizeof (cur_file_name), SML_OBIS_FORMAT_FILE_NAME,
day(time_today), month (time_today), year (time_today)); day(time_today), month (time_today), year (time_today));
@ -352,7 +357,7 @@ void sml_cleanup_history ()
while (grid_power_dir.next()) { while (grid_power_dir.next()) {
if (grid_power_dir.fileName() != cur_file_name) { 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())); ", Size: " + String (grid_power_dir.fileSize()));
LittleFS.remove (SML_OBIS_GRID_POWER_PATH "/" + grid_power_dir.fileName()); 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 */ /* calc average for last interval */
if (obis_cur_pac_cnt) { if (obis_cur_pac_cnt) {
int16_t pac_average = sml_get_obis_pac_average(); 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)]; 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, 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)); day(time_today), month(time_today), year(time_today));
// append last average // append last average
if ((file = LittleFS.open (file_name, "a"))) { if (mGridPowerFile || (mGridPowerFile = LittleFS.open (file_name, "a"))) {
unsigned char buf[4]; unsigned char buf[4];
buf[0] = obis_cur_pac_index & 0xff; buf[0] = obis_cur_pac_index & 0xff;
buf[1] = obis_cur_pac_index >> 8; buf[1] = obis_cur_pac_index >> 8;
buf[2] = pac_average & 0xff; buf[2] = pac_average & 0xff;
buf[3] = pac_average >> 8; 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"); DPRINTLN (DBG_WARN, "sml_handle_obis_pac, failed_to_write");
} else { } else {
DPRINTLN (DBG_DEBUG, "sml_handle_obis_pac, write to " + String(file_name)); DPRINTLN (DBG_DEBUG, "sml_handle_obis_pac, write to " + String(file_name));
mGridPowerFile.flush();
} }
file.close ();
} else { } else {
DPRINTLN (DBG_WARN, "sml_handle_obis_pac, failed to open"); DPRINTLN (DBG_WARN, "sml_handle_obis_pac, failed to open");
} }

20
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 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}; const uint8_t dcList[] = {FLD_UDC, FLD_IDC, FLD_PDC, FLD_YD, FLD_YT, FLD_IRR, FLD_MP};
template <class HMSYSTEM> template <class HMSYSTEM, class HMRADIO>
class RestApi { class RestApi {
public: public:
RestApi() { RestApi() {
@ -39,10 +39,11 @@ class RestApi {
nr = 0; 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; mApp = app;
mSrv = srv; mSrv = srv;
mSys = sys; mSys = sys;
mRadio = radio;
mConfig = config; mConfig = config;
mSrv->on("/api", HTTP_GET, std::bind(&RestApi::onApi, this, std::placeholders::_1)); 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( 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")] = stat->rxFail;
obj[F("rx_fail_answer")] = stat->rxFailNoAnser; obj[F("rx_fail_answer")] = stat->rxFailNoAnser;
obj[F("frame_cnt")] = stat->frmCnt; obj[F("frame_cnt")] = stat->frmCnt;
obj[F("tx_cnt")] = mSys->Radio.mSendCnt; obj[F("tx_cnt")] = mRadio->mSendCnt;
obj[F("retransmits")] = mSys->Radio.mRetransmits; obj[F("retransmits")] = mRadio->mRetransmits;
} }
void getInverterList(JsonObject obj) { void getInverterList(JsonObject obj) {
@ -583,9 +584,9 @@ class RestApi {
void getRadio(JsonObject obj) { void getRadio(JsonObject obj) {
obj[F("power_level")] = mConfig->nrf.amplifierPower; obj[F("power_level")] = mConfig->nrf.amplifierPower;
obj[F("isconnected")] = mSys->Radio.isChipConnected(); obj[F("isconnected")] = mRadio->isChipConnected();
obj[F("DataRate")] = mSys->Radio.getDataRate(); obj[F("DataRate")] = mRadio->getDataRate();
obj[F("isPVariant")] = mSys->Radio.isPVariant(); obj[F("isPVariant")] = mRadio->isPVariant();
} }
void getSerial(JsonObject obj) { void getSerial(JsonObject obj) {
@ -647,9 +648,9 @@ class RestApi {
} }
JsonArray warn = obj.createNestedArray(F("warnings")); 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")); 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")); warn.add(F("your NRF24 module isn't a plus version(+), maybe incompatible"));
if(!mApp->getSettingsValid()) if(!mApp->getSettingsValid())
warn.add(F("your settings are invalid")); warn.add(F("your settings are invalid"));
@ -807,6 +808,7 @@ class RestApi {
IApp *mApp; IApp *mApp;
HMSYSTEM *mSys; HMSYSTEM *mSys;
HMRADIO *mRadio;
AsyncWebServer *mSrv; AsyncWebServer *mSrv;
settings_t *mConfig; settings_t *mConfig;

7
src/web/web.h

@ -575,7 +575,7 @@ class Web {
mConfig->serial.debug = (request->arg("serDbg") == "on"); mConfig->serial.debug = (request->arg("serDbg") == "on");
mConfig->serial.showIv = (request->arg("serEn") == "on"); mConfig->serial.showIv = (request->arg("serEn") == "on");
// Needed to log TX buffers to serial console // 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 #ifdef AHOY_SML_OBIS_SUPPORT
@ -676,11 +676,14 @@ class Web {
// NRF Statistics // NRF Statistics
stat = mApp->getStatistics(); stat = mApp->getStatistics();
uint32_t nrfSendCnt, nrfRetransmits;
mApp->nrfGetRadioCounters (nrfSendCnt, nrfRetransmits);
metrics += radioStatistic(F("rx_success"), stat->rxSuccess); metrics += radioStatistic(F("rx_success"), stat->rxSuccess);
metrics += radioStatistic(F("rx_fail"), stat->rxFail); metrics += radioStatistic(F("rx_fail"), stat->rxFail);
metrics += radioStatistic(F("rx_fail_answer"), stat->rxFailNoAnser); metrics += radioStatistic(F("rx_fail_answer"), stat->rxFailNoAnser);
metrics += radioStatistic(F("frame_cnt"), stat->frmCnt); 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()); len = snprintf((char *)buffer,maxLen,"%s",metrics.c_str());
// Start Inverter loop // Start Inverter loop

Loading…
Cancel
Save