Browse Source

0.8.63

* made code review
* fixed endless loop #1387
pull/1512/head
lumapu 1 year ago
parent
commit
77b1f96c03
  1. 4
      src/.vscode/settings.json
  2. 4
      src/CHANGES.md
  3. 24
      src/app.cpp
  4. 3
      src/app.h
  5. 8
      src/config/settings.h
  6. 2
      src/defines.h
  7. 6
      src/eth/ahoyeth.h
  8. 15
      src/hm/nrfHal.h
  9. 400
      src/plugins/Display/Display.h
  10. 19
      src/plugins/Display/Display_ePaper.cpp
  11. 4
      src/plugins/Display/Display_ePaper.h
  12. 8
      src/publisher/pubMqtt.h
  13. 6
      src/utils/crc.cpp
  14. 8
      src/utils/improv.h
  15. 7
      src/utils/scheduler.h
  16. 9
      src/utils/syslog.cpp
  17. 18
      src/web/html/api.js
  18. 2
      src/web/lang.json
  19. 3
      src/web/web.h
  20. 4
      src/wifi/ahoywifi.cpp
  21. 9
      src/wifi/ahoywifi.h

4
src/.vscode/settings.json

@ -84,5 +84,5 @@
},
"cmake.configureOnOpen": false,
"editor.formatOnSave": false,
"cmake.sourceDirectory": "C:/lpusch/github/ahoy/src/.pio/libdeps/esp32-wroom32-release-prometheus/Adafruit BusIO",
}
"cmake.sourceDirectory": "C:/lpusch/github/ahoy/src/.pio/libdeps/esp32-wroom32-release-prometheus/Adafruit BusIO"
}

4
src/CHANGES.md

@ -1,5 +1,9 @@
# Development Changes
## 0.8.63 - 2024-01-22
* made code review
* fixed endless loop #1387
## 0.8.62 - 2024-01-21
* updated version in footer #1381
* repaired radio statistics #1382

24
src/app.cpp

@ -143,22 +143,20 @@ void app::loop(void) {
esp_task_wdt_reset();
if(mConfig->nrf.enabled)
mNrfActive = mNrfRadio.loop();
mNrfRadio.loop();
if(!mNrfActive) {
#if defined(ESP32)
if(mConfig->cmt.enabled)
mNrfActive = mCmtRadio.loop();
#endif
#if defined(ESP32)
if(mConfig->cmt.enabled)
mCmtRadio.loop();
#endif
ah::Scheduler::loop();
mCommunication.loop();
ah::Scheduler::loop();
mCommunication.loop();
#if defined(ENABLE_MQTT)
if (mMqttEnabled && mNetworkConnected)
mMqtt.loop();
#endif
}
#if defined(ENABLE_MQTT)
if (mMqttEnabled && mNetworkConnected)
mMqtt.loop();
#endif
yield();
}

3
src/app.h

@ -82,7 +82,7 @@ class app : public IApp, public ah::Scheduler {
~app() {}
void setup(void);
void loop(void);
void loop(void) override;
void onNetwork(bool gotIp);
void regularTickers(void);
@ -405,7 +405,6 @@ class app : public IApp, public ah::Scheduler {
uint8_t mSendLastIvId;
bool mSendFirst;
bool mAllIvNotAvail;
bool mNrfActive = false;
bool mNetworkConnected;

8
src/config/settings.h

@ -824,8 +824,10 @@ class settings {
#if defined(ESP32)
void getChar(JsonObject obj, const char *key, char *dst, int maxLen) {
if(obj.containsKey(key))
if(obj.containsKey(key)) {
snprintf(dst, maxLen, "%s", obj[key].as<const char*>());
dst[maxLen-1] = '\0';
}
}
template<typename T=uint8_t>
@ -835,8 +837,10 @@ class settings {
}
#else
void getChar(JsonObject obj, const __FlashStringHelper *key, char *dst, int maxLen) {
if(obj.containsKey(key))
if(obj.containsKey(key)) {
snprintf(dst, maxLen, "%s", obj[key].as<const char*>());
dst[maxLen-1] = '\0';
}
}
template<typename T=uint8_t>

2
src/defines.h

@ -13,7 +13,7 @@
//-------------------------------------
#define VERSION_MAJOR 0
#define VERSION_MINOR 8
#define VERSION_PATCH 62
#define VERSION_PATCH 63
//-------------------------------------
typedef struct {

6
src/eth/ahoyeth.h

@ -1,6 +1,6 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#if defined(ETHERNET)
@ -49,7 +49,7 @@ class ahoyeth {
#if defined(CONFIG_IDF_TARGET_ESP32S3)
EthSpi mEthSpi;
#endif
settings_t *mConfig;
settings_t *mConfig = NULL;
uint32_t *mUtcTimestamp;
AsyncUDP mUdp; // for time server

15
src/hm/nrfHal.h

@ -1,6 +1,6 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#ifndef __NRF_HAL_H__
@ -144,6 +144,8 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle {
uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t len) override {
uint8_t data[NRF_MAX_TRANSFER_SZ];
data[0] = cmd;
if(len > NRF_MAX_TRANSFER_SZ)
len = NRF_MAX_TRANSFER_SZ;
memset(&data[1], 0xff, len);
request_spi();
@ -168,13 +170,16 @@ class nrfHal: public RF24_hal, public SpiPatcherHandle {
}
uint8_t read(uint8_t cmd, uint8_t* buf, uint8_t data_len, uint8_t blank_len) override {
uint8_t data[NRF_MAX_TRANSFER_SZ];
uint8_t data[NRF_MAX_TRANSFER_SZ + 1];
uint8_t len = data_len + blank_len;
data[0] = cmd;
memset(&data[1], 0xff, (data_len + blank_len));
if(len > (NRF_MAX_TRANSFER_SZ + 1))
len = (NRF_MAX_TRANSFER_SZ + 1);
memset(&data[1], 0xff, len);
request_spi();
size_t spiLen = (static_cast<size_t>(data_len) + static_cast<size_t>(blank_len) + 1u) << 3;
size_t spiLen = (static_cast<size_t>(len) + 1u) << 3;
spi_transaction_t t = {
.flags = 0,
.cmd = 0,

400
src/plugins/Display/Display.h

@ -19,226 +19,226 @@
template <class HMSYSTEM, class RADIO>
class Display {
public:
Display() {
mMono = NULL;
}
void setup(IApp *app, display_t *cfg, HMSYSTEM *sys, RADIO *hmradio, RADIO *hmsradio, uint32_t *utcTs) {
mApp = app;
mHmRadio = hmradio;
mHmsRadio = hmsradio;
mCfg = cfg;
mSys = sys;
mUtcTs = utcTs;
mNewPayload = false;
mLoopCnt = 0;
mDisplayData.version = app->getVersion(); // version never changes, so only set once
switch (mCfg->type) {
case DISP_TYPE_T0_NONE: mMono = NULL; break; // None
case DISP_TYPE_T1_SSD1306_128X64: mMono = new DisplayMono128X64(); break; // SSD1306_128X64 (0.96", 1.54")
case DISP_TYPE_T2_SH1106_128X64: mMono = new DisplayMono128X64(); break; // SH1106_128X64 (1.3")
case DISP_TYPE_T3_PCD8544_84X48: mMono = new DisplayMono84X48(); break; // PCD8544_84X48 (1.6" - Nokia 5110)
case DISP_TYPE_T4_SSD1306_128X32: mMono = new DisplayMono128X32(); break; // SSD1306_128X32 (0.91")
case DISP_TYPE_T5_SSD1306_64X48: mMono = new DisplayMono64X48(); break; // SSD1306_64X48 (0.66" - Wemos OLED Shield)
case DISP_TYPE_T6_SSD1309_128X64: mMono = new DisplayMono128X64(); break; // SSD1309_128X64 (2.42")
#if defined(ESP32) && !defined(ETHERNET)
case DISP_TYPE_T10_EPAPER:
mMono = NULL; // ePaper does not use this
mRefreshCycle = 0;
mEpaper.config(mCfg->rot, mCfg->pwrSaveAtIvOffline);
mEpaper.init(mCfg->type, mCfg->disp_cs, mCfg->disp_dc, mCfg->disp_reset, mCfg->disp_busy, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mDisplayData.version);
break;
#endif
default: mMono = NULL; break;
}
if(mMono) {
mMono->config(mCfg);
mMono->init(&mDisplayData);
public:
Display() {
mMono = NULL;
}
// setup PIR pin for motion sensor
#ifdef ESP32
if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF))
pinMode(mCfg->pirPin, INPUT);
#endif
#ifdef ESP8266
if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF) && (mCfg->pirPin != A0))
pinMode(mCfg->pirPin, INPUT);
#endif
}
void setup(IApp *app, display_t *cfg, HMSYSTEM *sys, RADIO *hmradio, RADIO *hmsradio, uint32_t *utcTs) {
mApp = app;
mHmRadio = hmradio;
mHmsRadio = hmsradio;
mCfg = cfg;
mSys = sys;
mUtcTs = utcTs;
mNewPayload = false;
mLoopCnt = 0;
void payloadEventListener(uint8_t cmd) {
mNewPayload = true;
}
mDisplayData.version = app->getVersion(); // version never changes, so only set once
switch (mCfg->type) {
case DISP_TYPE_T0_NONE: mMono = NULL; break; // None
case DISP_TYPE_T1_SSD1306_128X64: mMono = new DisplayMono128X64(); break; // SSD1306_128X64 (0.96", 1.54")
case DISP_TYPE_T2_SH1106_128X64: mMono = new DisplayMono128X64(); break; // SH1106_128X64 (1.3")
case DISP_TYPE_T3_PCD8544_84X48: mMono = new DisplayMono84X48(); break; // PCD8544_84X48 (1.6" - Nokia 5110)
case DISP_TYPE_T4_SSD1306_128X32: mMono = new DisplayMono128X32(); break; // SSD1306_128X32 (0.91")
case DISP_TYPE_T5_SSD1306_64X48: mMono = new DisplayMono64X48(); break; // SSD1306_64X48 (0.66" - Wemos OLED Shield)
case DISP_TYPE_T6_SSD1309_128X64: mMono = new DisplayMono128X64(); break; // SSD1309_128X64 (2.42")
#if defined(ESP32) && !defined(ETHERNET)
case DISP_TYPE_T10_EPAPER:
mMono = NULL; // ePaper does not use this
mRefreshCycle = 0;
mEpaper.config(mCfg->rot, mCfg->pwrSaveAtIvOffline);
mEpaper.init(mCfg->type, mCfg->disp_cs, mCfg->disp_dc, mCfg->disp_reset, mCfg->disp_busy, mCfg->disp_clk, mCfg->disp_data, mUtcTs, mDisplayData.version);
break;
#endif
default: mMono = NULL; break;
}
if(mMono) {
mMono->config(mCfg);
mMono->init(&mDisplayData);
}
void tickerSecond() {
bool request_refresh = false;
// setup PIR pin for motion sensor
#ifdef ESP32
if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF))
pinMode(mCfg->pirPin, INPUT);
#endif
#ifdef ESP8266
if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF) && (mCfg->pirPin != A0))
pinMode(mCfg->pirPin, INPUT);
#endif
if (mMono != NULL)
request_refresh = mMono->loop(motionSensorActive());
}
if (mNewPayload || (((++mLoopCnt) % 5) == 0) || request_refresh) {
DataScreen();
mNewPayload = false;
mLoopCnt = 0;
void payloadEventListener(uint8_t cmd) {
mNewPayload = true;
}
#if defined(ESP32) && !defined(ETHERNET)
mEpaper.tickerSecond();
#endif
}
private:
void DataScreen() {
if (DISP_TYPE_T0_NONE == mCfg->type)
return;
float totalPower = 0.0;
float totalYieldDay = 0.0;
float totalYieldTotal = 0.0;
uint8_t nrprod = 0;
uint8_t nrsleep = 0;
int8_t minQAllInv = 4;
Inverter<> *iv;
record_t<> *rec;
bool allOff = true;
uint8_t nInv = mSys->getNumInverters();
for (uint8_t i = 0; i < nInv; i++) {
iv = mSys->getInverterByPos(i);
if (iv == NULL)
continue;
if (iv->isProducing()) // also updates inverter state engine
nrprod++;
else
nrsleep++;
void tickerSecond() {
bool request_refresh = false;
rec = iv->getRecordStruct(RealTimeRunData_Debug);
if (mMono != NULL)
request_refresh = mMono->loop(motionSensorActive());
if (iv->isAvailable()) { // consider only radio quality of inverters still communicating
int8_t maxQInv = -6;
for(uint8_t ch = 0; ch < RF_MAX_CHANNEL_ID; ch++) {
int8_t q = iv->heuristics.txRfQuality[ch];
if (q > maxQInv)
maxQInv = q;
if (mNewPayload || (((++mLoopCnt) % 5) == 0) || request_refresh) {
DataScreen();
mNewPayload = false;
mLoopCnt = 0;
}
#if defined(ESP32) && !defined(ETHERNET)
mEpaper.tickerSecond();
#endif
}
private:
void DataScreen() {
if (DISP_TYPE_T0_NONE == mCfg->type)
return;
float totalPower = 0.0;
float totalYieldDay = 0.0;
float totalYieldTotal = 0.0;
uint8_t nrprod = 0;
uint8_t nrsleep = 0;
int8_t minQAllInv = 4;
Inverter<> *iv;
record_t<> *rec;
bool allOff = true;
uint8_t nInv = mSys->getNumInverters();
for (uint8_t i = 0; i < nInv; i++) {
iv = mSys->getInverterByPos(i);
if (iv == NULL)
continue;
if (iv->isProducing()) // also updates inverter state engine
nrprod++;
else
nrsleep++;
rec = iv->getRecordStruct(RealTimeRunData_Debug);
if (iv->isAvailable()) { // consider only radio quality of inverters still communicating
int8_t maxQInv = -6;
for(uint8_t ch = 0; ch < RF_MAX_CHANNEL_ID; ch++) {
int8_t q = iv->heuristics.txRfQuality[ch];
if (q > maxQInv)
maxQInv = q;
}
if (maxQInv < minQAllInv)
minQAllInv = maxQInv;
totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec); // add only FLD_PAC from inverters still communicating
allOff = false;
}
if (maxQInv < minQAllInv)
minQAllInv = maxQInv;
totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec); // add only FLD_PAC from inverters still communicating
allOff = false;
totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec);
totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec);
}
totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec);
totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec);
}
if (allOff)
minQAllInv = -6;
// prepare display data
mDisplayData.nrProducing = nrprod;
mDisplayData.nrSleeping = nrsleep;
mDisplayData.totalPower = totalPower;
mDisplayData.totalYieldDay = totalYieldDay;
mDisplayData.totalYieldTotal = totalYieldTotal;
bool nrf_en = mApp->getNrfEnabled();
bool nrf_ok = nrf_en && mHmRadio->isChipConnected();
#if defined(ESP32)
bool cmt_en = mApp->getCmtEnabled();
bool cmt_ok = cmt_en && mHmsRadio->isChipConnected();
#else
bool cmt_en = false;
bool cmt_ok = false;
#endif
mDisplayData.RadioSymbol = (nrf_ok && !cmt_en) || (cmt_ok && !nrf_en) || (nrf_ok && cmt_ok);
mDisplayData.WifiSymbol = (WiFi.status() == WL_CONNECTED);
mDisplayData.MQTTSymbol = mApp->getMqttIsConnected();
mDisplayData.RadioRSSI = ivQuality2RadioRSSI(minQAllInv); // Workaround as NRF24 has no RSSI. Approximation by quality levels from heuristic function
mDisplayData.WifiRSSI = (WiFi.status() == WL_CONNECTED) ? WiFi.RSSI() : SCHAR_MIN;
mDisplayData.ipAddress = WiFi.localIP();
// provide localized times to display classes
time_t utc= mApp->getTimestamp();
if (year(utc) > 2020)
mDisplayData.utcTs = gTimezone.toLocal(utc);
else
mDisplayData.utcTs = 0;
mDisplayData.pGraphStartTime = gTimezone.toLocal(mApp->getSunrise());
mDisplayData.pGraphEndTime = gTimezone.toLocal(mApp->getSunset());
if (allOff)
minQAllInv = -6;
// prepare display data
mDisplayData.nrProducing = nrprod;
mDisplayData.nrSleeping = nrsleep;
mDisplayData.totalPower = totalPower;
mDisplayData.totalYieldDay = totalYieldDay;
mDisplayData.totalYieldTotal = totalYieldTotal;
bool nrf_en = mApp->getNrfEnabled();
bool nrf_ok = nrf_en && mHmRadio->isChipConnected();
#if defined(ESP32)
bool cmt_en = mApp->getCmtEnabled();
bool cmt_ok = cmt_en && mHmsRadio->isChipConnected();
#else
bool cmt_en = false;
bool cmt_ok = false;
#endif
mDisplayData.RadioSymbol = (nrf_ok && !cmt_en) || (cmt_ok && !nrf_en) || (nrf_ok && cmt_ok);
mDisplayData.WifiSymbol = (WiFi.status() == WL_CONNECTED);
mDisplayData.MQTTSymbol = mApp->getMqttIsConnected();
mDisplayData.RadioRSSI = ivQuality2RadioRSSI(minQAllInv); // Workaround as NRF24 has no RSSI. Approximation by quality levels from heuristic function
mDisplayData.WifiRSSI = (WiFi.status() == WL_CONNECTED) ? WiFi.RSSI() : SCHAR_MIN;
mDisplayData.ipAddress = WiFi.localIP();
// provide localized times to display classes
time_t utc= mApp->getTimestamp();
if (year(utc) > 2020)
mDisplayData.utcTs = gTimezone.toLocal(utc);
else
mDisplayData.utcTs = 0;
mDisplayData.pGraphStartTime = gTimezone.toLocal(mApp->getSunrise());
mDisplayData.pGraphEndTime = gTimezone.toLocal(mApp->getSunset());
if (mMono ) {
mMono->disp();
}
#if defined(ESP32) && !defined(ETHERNET)
else if (DISP_TYPE_T10_EPAPER == mCfg->type) {
mEpaper.loop((totalPower), totalYieldDay, totalYieldTotal, nrprod);
mRefreshCycle++;
}
if (mMono ) {
mMono->disp();
}
#if defined(ESP32) && !defined(ETHERNET)
else if (DISP_TYPE_T10_EPAPER == mCfg->type) {
mEpaper.loop((totalPower), totalYieldDay, totalYieldTotal, nrprod);
mRefreshCycle++;
}
if (mRefreshCycle > 480) {
mEpaper.fullRefresh();
mRefreshCycle = 0;
if (mRefreshCycle > 480) {
mEpaper.fullRefresh();
mRefreshCycle = 0;
}
#endif
}
#endif
}
bool motionSensorActive() {
if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF)) {
#if defined(ESP8266)
if (mCfg->pirPin == A0)
return((analogRead(A0) >= 512));
else
bool motionSensorActive() {
if ((mCfg->screenSaver == 2) && (mCfg->pirPin != DEF_PIN_OFF)) {
#if defined(ESP8266)
if (mCfg->pirPin == A0)
return((analogRead(A0) >= 512));
else
return(digitalRead(mCfg->pirPin));
#elif defined(ESP32)
return(digitalRead(mCfg->pirPin));
#elif defined(ESP32)
return(digitalRead(mCfg->pirPin));
#endif
#endif
}
else
return(false);
}
else
return(false);
}
// approximate RSSI in dB by invQuality levels from heuristic function (very unscientific but better than nothing :-) )
int8_t ivQuality2RadioRSSI(int8_t invQuality) {
int8_t pseudoRSSIdB;
switch(invQuality) {
case 4: pseudoRSSIdB = -55; break;
case 3:
case 2:
case 1: pseudoRSSIdB = -65; break;
case 0:
case -1:
case -2: pseudoRSSIdB = -75; break;
case -3:
case -4:
case -5: pseudoRSSIdB = -85; break;
case -6:
default: pseudoRSSIdB = -95; break;
// approximate RSSI in dB by invQuality levels from heuristic function (very unscientific but better than nothing :-) )
int8_t ivQuality2RadioRSSI(int8_t invQuality) {
int8_t pseudoRSSIdB;
switch(invQuality) {
case 4: pseudoRSSIdB = -55; break;
case 3:
case 2:
case 1: pseudoRSSIdB = -65; break;
case 0:
case -1:
case -2: pseudoRSSIdB = -75; break;
case -3:
case -4:
case -5: pseudoRSSIdB = -85; break;
case -6:
default: pseudoRSSIdB = -95; break;
}
return (pseudoRSSIdB);
}
return (pseudoRSSIdB);
}
// private member variables
IApp *mApp;
DisplayData mDisplayData;
bool mNewPayload;
uint8_t mLoopCnt;
uint32_t *mUtcTs;
display_t *mCfg;
HMSYSTEM *mSys;
RADIO *mHmRadio;
RADIO *mHmsRadio;
uint16_t mRefreshCycle;
#if defined(ESP32) && !defined(ETHERNET)
DisplayEPaper mEpaper;
#endif
DisplayMono *mMono;
// private member variables
IApp *mApp;
DisplayData mDisplayData;
bool mNewPayload;
uint8_t mLoopCnt;
uint32_t *mUtcTs;
display_t *mCfg;
HMSYSTEM *mSys;
RADIO *mHmRadio;
RADIO *mHmsRadio;
uint16_t mRefreshCycle;
#if defined(ESP32) && !defined(ETHERNET)
DisplayEPaper mEpaper;
#endif
DisplayMono *mMono;
};
#endif /*PLUGIN_DISPLAY*/

19
src/plugins/Display/Display_ePaper.cpp

@ -20,6 +20,7 @@ SPIClass hspi(HSPI);
DisplayEPaper::DisplayEPaper() {
mDisplayRotation = 2;
mHeadFootPadding = 16;
memset(_fmtText, 0, EPAPER_MAX_TEXT_LEN);
}
@ -114,9 +115,9 @@ void DisplayEPaper::headlineIP() {
do {
if ((WiFi.isConnected() == true) && (WiFi.localIP() > 0)) {
snprintf(_fmtText, sizeof(_fmtText), "%s", WiFi.localIP().toString().c_str());
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, "%s", WiFi.localIP().toString().c_str());
} else {
snprintf(_fmtText, sizeof(_fmtText), "WiFi not connected");
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, "WiFi not connected");
}
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = ((_display->width() - tbw) / 2) - tbx;
@ -137,7 +138,7 @@ void DisplayEPaper::lastUpdatePaged() {
_display->fillScreen(GxEPD_BLACK);
do {
if (NULL != mUtcTs) {
snprintf(_fmtText, sizeof(_fmtText), ah::getDateTimeStr(gTimezone.toLocal(*mUtcTs)).c_str());
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, ah::getDateTimeStr(gTimezone.toLocal(*mUtcTs)).c_str());
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = ((_display->width() - tbw) / 2) - tbx;
@ -158,7 +159,7 @@ void DisplayEPaper::versionFooter() {
_display->setPartialWindow(0, _display->height() - mHeadFootPadding, _display->width(), mHeadFootPadding);
_display->fillScreen(GxEPD_BLACK);
do {
snprintf(_fmtText, sizeof(_fmtText), "Version: %s", _version);
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, "Version: %s", _version);
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = ((_display->width() - tbw) / 2) - tbx;
@ -179,7 +180,7 @@ void DisplayEPaper::offlineFooter() {
_display->fillScreen(GxEPD_BLACK);
do {
if (NULL != mUtcTs) {
snprintf(_fmtText, sizeof(_fmtText), "offline");
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, "offline");
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
uint16_t x = ((_display->width() - tbw) / 2) - tbx;
@ -203,13 +204,13 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa
do {
// actual Production
if (totalPower > 9999) {
snprintf(_fmtText, sizeof(_fmtText), "%.1f kW", (totalPower / 1000));
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, "%.1f kW", (totalPower / 1000));
_changed = true;
} else if ((totalPower > 0) && (totalPower <= 9999)) {
snprintf(_fmtText, sizeof(_fmtText), "%.0f W", totalPower);
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, "%.0f W", totalPower);
_changed = true;
} else
snprintf(_fmtText, sizeof(_fmtText), "offline");
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, "offline");
if ((totalPower == 0) && (mEnPowerSave)) {
_display->fillRect(0, mHeadFootPadding, 200, 200, GxEPD_BLACK);
@ -264,7 +265,7 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa
// Inverter online
_display->setFont(&FreeSans12pt7b);
y = _display->height() - (mHeadFootPadding + 10);
snprintf(_fmtText, sizeof(_fmtText), " %d online", isprod);
snprintf(_fmtText, EPAPER_MAX_TEXT_LEN, " %d online", isprod);
_display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh);
_display->drawInvertedBitmap(10, y - tbh, myWR, 20, 20, GxEPD_BLACK);
x = ((_display->width() - tbw - 20) / 2) - tbx;

4
src/plugins/Display/Display_ePaper.h

@ -9,6 +9,8 @@
// enable GxEPD2_GFX base class
#define ENABLE_GxEPD2_GFX 1
#define EPAPER_MAX_TEXT_LEN 35
#include <GxEPD2_BW.h>
#include <SPI.h>
@ -49,7 +51,7 @@ class DisplayEPaper {
uint8_t mDisplayRotation;
bool _changed = false;
char _fmtText[35];
char _fmtText[EPAPER_MAX_TEXT_LEN];
String _settedIP;
uint8_t mHeadFootPadding;
GxEPD2_GFX* _display;

8
src/publisher/pubMqtt.h

@ -70,8 +70,8 @@ class PubMqtt {
if(strlen(mCfgMqtt->clientId) > 0)
snprintf(mClientId, 23, "%s", mCfgMqtt->clientId);
else{
snprintf(mClientId, 24, "%s-", mDevName);
else {
snprintf(mClientId, 23, "%s-", mDevName);
uint8_t pos = strlen(mClientId);
mClientId[pos++] = WiFi.macAddress().substring( 9, 10).c_str()[0];
mClientId[pos++] = WiFi.macAddress().substring(10, 11).c_str()[0];
@ -308,7 +308,7 @@ class PubMqtt {
bool limitAbs = false;
if(len > 0) {
char *pyld = new char[len + 1];
strncpy(pyld, (const char*)payload, len);
memcpy(pyld, payload, len);
pyld[len] = '\0';
if(NULL == strstr(topic, "limit"))
root[F("val")] = atoi(pyld);
@ -326,7 +326,7 @@ class PubMqtt {
while(1) {
if(('/' == p[pos]) || ('\0' == p[pos])) {
strncpy(tmp, p, pos);
memcpy(tmp, p, pos);
tmp[pos] = '\0';
switch(elm++) {
case 1: root[F("path")] = String(tmp); break;

6
src/utils/crc.cpp

@ -1,6 +1,6 @@
//-----------------------------------------------------------------------------
// 2022 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#include "crc.h"
@ -19,7 +19,7 @@ namespace ah {
uint16_t crc16(uint8_t buf[], uint8_t len, uint16_t start) {
uint16_t crc = start;
uint8_t shift = 0;
uint8_t shift;
for(uint8_t i = 0; i < len; i ++) {
crc = crc ^ buf[i];

8
src/utils/improv.h

@ -1,5 +1,5 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://github.com/lumpapu/ahoy
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
@ -72,10 +72,10 @@ class Improv {
void dumpBuf(uint8_t buf[], uint8_t len) {
for(uint8_t i = 0; i < len; i++) {
DHEX(buf[i], false);
DBGPRINT(" ", false);
DHEX(buf[i]);
DBGPRINT(F(" "));
}
DBGPRINTLN("", false);
DBGPRINTLN("");
}
inline uint8_t buildChecksum(uint8_t buf[], uint8_t len) {

7
src/utils/scheduler.h

@ -1,7 +1,6 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://ahoydtu.de
// Lukas Pusch, lukas@lpusch.de
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
// 2024 Ahoy, https://ahoydtu.de
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#ifndef __SCHEDULER_H__
@ -40,7 +39,7 @@ namespace ah {
resetTicker();
}
void loop(void) {
virtual void loop(void) {
mMillis = millis();
mDiff = mMillis - mPrevMillis;
if (mDiff < 1000)

9
src/utils/syslog.cpp

@ -1,3 +1,8 @@
//-----------------------------------------------------------------------------
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
#include <algorithm>
#include "syslog.h"
@ -87,7 +92,7 @@ void DbgSyslog::log(const char *hostname, uint8_t facility, uint8_t severity, ch
// This is a unit8 instead of a char because that's what udp.write() wants
uint8_t buffer[SYSLOG_MAX_PACKET_SIZE];
int len = snprintf((char*)buffer, SYSLOG_MAX_PACKET_SIZE, "<%d>%s %s: %s", priority, hostname, SYSLOG_APP, msg);
int len = snprintf(static_cast<char*>(buffer), SYSLOG_MAX_PACKET_SIZE, "<%d>%s %s: %s", priority, hostname, SYSLOG_APP, msg);
//printf("syslog::log %s\n",mSyslogIP.toString().c_str());
//printf("syslog::log %d %s\n",len,buffer);
// Send the raw UDP packet
@ -96,4 +101,4 @@ void DbgSyslog::log(const char *hostname, uint8_t facility, uint8_t severity, ch
mSyslogUdp.endPacket();
}
#endif
#endif

18
src/web/html/api.js

@ -1,42 +1,42 @@
/* SVG ICONS - https://icons.getbootstrap.com */
iconWifi1 = [
var iconWifi1 = [
"M11.046 10.454c.226-.226.185-.605-.1-.75A6.473 6.473 0 0 0 8 9c-1.06 0-2.062.254-2.946.704-.285.145-.326.524-.1.75l.015.015c.16.16.407.19.611.09A5.478 5.478 0 0 1 8 10c.868 0 1.69.201 2.42.56.203.1.45.07.611-.091l.015-.015zM9.06 12.44c.196-.196.198-.52-.04-.66A1.99 1.99 0 0 0 8 11.5a1.99 1.99 0 0 0-1.02.28c-.238.14-.236.464-.04.66l.706.706a.5.5 0 0 0 .707 0l.708-.707z"
];
iconWifi2 = [
var iconWifi2 = [
"M13.229 8.271c.216-.216.194-.578-.063-.745A9.456 9.456 0 0 0 8 6c-1.905 0-3.68.56-5.166 1.526a.48.48 0 0 0-.063.745.525.525 0 0 0 .652.065A8.46 8.46 0 0 1 8 7a8.46 8.46 0 0 1 4.577 1.336c.205.132.48.108.652-.065zm-2.183 2.183c.226-.226.185-.605-.1-.75A6.473 6.473 0 0 0 8 9c-1.06 0-2.062.254-2.946.704-.285.145-.326.524-.1.75l.015.015c.16.16.408.19.611.09A5.478 5.478 0 0 1 8 10c.868 0 1.69.201 2.42.56.203.1.45.07.611-.091l.015-.015zM9.06 12.44c.196-.196.198-.52-.04-.66A1.99 1.99 0 0 0 8 11.5a1.99 1.99 0 0 0-1.02.28c-.238.14-.236.464-.04.66l.706.706a.5.5 0 0 0 .708 0l.707-.707z"
];
iconWifi3 = [
var iconWifi3 = [
"M15.384 6.115a.485.485 0 0 0-.047-.736A12.444 12.444 0 0 0 8 3C5.259 3 2.723 3.882.663 5.379a.485.485 0 0 0-.048.736.518.518 0 0 0 .668.05A11.448 11.448 0 0 1 8 4c2.507 0 4.827.802 6.716 2.164.205.148.49.13.668-.049z",
"M13.229 8.271a.482.482 0 0 0-.063-.745A9.455 9.455 0 0 0 8 6c-1.905 0-3.68.56-5.166 1.526a.48.48 0 0 0-.063.745.525.525 0 0 0 .652.065A8.46 8.46 0 0 1 8 7a8.46 8.46 0 0 1 4.576 1.336c.206.132.48.108.653-.065zm-2.183 2.183c.226-.226.185-.605-.1-.75A6.473 6.473 0 0 0 8 9c-1.06 0-2.062.254-2.946.704-.285.145-.326.524-.1.75l.015.015c.16.16.407.19.611.09A5.478 5.478 0 0 1 8 10c.868 0 1.69.201 2.42.56.203.1.45.07.61-.091l.016-.015zM9.06 12.44c.196-.196.198-.52-.04-.66A1.99 1.99 0 0 0 8 11.5a1.99 1.99 0 0 0-1.02.28c-.238.14-.236.464-.04.66l.706.706a.5.5 0 0 0 .707 0l.707-.707z"
];
iconWarn = [
var iconWarn = [
"M7.938 2.016A.13.13 0 0 1 8.002 2a.13.13 0 0 1 .063.016.146.146 0 0 1 .054.057l6.857 11.667c.036.06.035.124.002.183a.163.163 0 0 1-.054.06.116.116 0 0 1-.066.017H1.146a.115.115 0 0 1-.066-.017.163.163 0 0 1-.054-.06.176.176 0 0 1 .002-.183L7.884 2.073a.147.147 0 0 1 .054-.057zm1.044-.45a1.13 1.13 0 0 0-1.96 0L.165 13.233c-.457.778.091 1.767.98 1.767h13.713c.889 0 1.438-.99.98-1.767L8.982 1.566z",
"M7.002 12a1 1 0 1 1 2 0 1 1 0 0 1-2 0zM7.1 5.995a.905.905 0 1 1 1.8 0l-.35 3.507a.552.552 0 0 1-1.1 0L7.1 5.995z"
];
iconInfo = [
var iconInfo = [
"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z",
"m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533L8.93 6.588zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0z"
];
iconSuccess = [
var iconSuccess = [
"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z",
"M10.97 4.97a.235.235 0 0 0-.02.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-1.071-1.05z"
];
iconSuccessFull = [
var iconSuccessFull = [
"M16 8A8 8 0 1 1 0 8a8 8 0 0 1 16 0zm-3.97-3.03a.75.75 0 0 0-1.08.022L7.477 9.417 5.384 7.323a.75.75 0 0 0-1.06 1.06L6.97 11.03a.75.75 0 0 0 1.079-.02l3.992-4.99a.75.75 0 0 0-.01-1.05z"
];
iconGear = [
var iconGear = [
"M9.405 1.05c-.413-1.4-2.397-1.4-2.81 0l-.1.34a1.464 1.464 0 0 1-2.105.872l-.31-.17c-1.283-.698-2.686.705-1.987 1.987l.169.311c.446.82.023 1.841-.872 2.105l-.34.1c-1.4.413-1.4 2.397 0 2.81l.34.1a1.464 1.464 0 0 1 .872 2.105l-.17.31c-.698 1.283.705 2.686 1.987 1.987l.311-.169a1.464 1.464 0 0 1 2.105.872l.1.34c.413 1.4 2.397 1.4 2.81 0l.1-.34a1.464 1.464 0 0 1 2.105-.872l.31.17c1.283.698 2.686-.705 1.987-1.987l-.169-.311a1.464 1.464 0 0 1 .872-2.105l.34-.1c1.4-.413 1.4-2.397 0-2.81l-.34-.1a1.464 1.464 0 0 1-.872-2.105l.17-.31c.698-1.283-.705-2.686-1.987-1.987l-.311.169a1.464 1.464 0 0 1-2.105-.872l-.1-.34zM8 10.93a2.929 2.929 0 1 1 0-5.86 2.929 2.929 0 0 1 0 5.858z"
];
iconDel = [
var iconDel = [
"M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14zm0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16z",
"M4.646 4.646a.5.5 0 0 1 .708 0L8 7.293l2.646-2.647a.5.5 0 0 1 .708.708L8.707 8l2.647 2.646a.5.5 0 0 1-.708.708L8 8.707l-2.646 2.647a.5.5 0 0 1-.708-.708L7.293 8 4.646 5.354a.5.5 0 0 1 0-.708z"
];

2
src/web/lang.json

@ -280,7 +280,7 @@
},
{
"token": "INV_GAP",
"en": "Communication Gap [ms]",
"en": "Communication Gap",
"de": "Kommunikationsl&uuml;cke"
},
{

3
src/web/web.h

@ -828,10 +828,9 @@ class Web {
if (0 == channel) {
// Report a _total value if also channel values were reported. Otherwise report without _total
char total[7];
total[0] = 0;
if (metricDeclared) {
// A declaration and value for channels have been delivered. So declare and deliver a _total metric
strncpy(total,"_total",sizeof(total));
strncpy(total, "_total", 6);
}
if (!metricTotalDeclard) {
snprintf(type, sizeof(type), "# TYPE %s%s%s%s %s\n",metricConstPrefix, iv->getFieldName(metricsChannelId, rec), promUnit.c_str(), total, promType.c_str());

4
src/wifi/ahoywifi.cpp

@ -1,5 +1,5 @@
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://ahoydtu.de
// 2024 Ahoy, https://ahoydtu.de
// Creative Commons - https://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
@ -293,7 +293,7 @@ bool ahoywifi::getNtpTime(void) {
if(NTP_PACKET_SIZE <= mUdp.parsePacket()) {
uint64_t secsSince1900;
mUdp.read(buf, NTP_PACKET_SIZE);
secsSince1900 = (buf[40] << 24);
secsSince1900 = ((uint64_t)buf[40] << 24);
secsSince1900 |= (buf[41] << 16);
secsSince1900 |= (buf[42] << 8);
secsSince1900 |= (buf[43] );

9
src/wifi/ahoywifi.h

@ -1,7 +1,8 @@
//------------------------------------//-----------------------------------------------------------------------------
// 2024 Ahoy, https://github.com/lumpapu/ahoy
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/4.0/deed
//-----------------------------------------------------------------------------
// 2023 Ahoy, https://www.mikrocontroller.net/topic/525778
// Creative Commons - http://creativecommons.org/licenses/by-nc-sa/3.0/de/
//-----------------------------------------------------------------------------
#if !defined(ETHERNET)
#ifndef __AHOYWIFI_H__
#define __AHOYWIFI_H__
@ -66,7 +67,7 @@ class ahoywifi {
void welcome(String ip, String mode);
settings_t *mConfig;
settings_t *mConfig = NULL;
appWifiCb mAppWifiCb;
DNSServer mDns;

Loading…
Cancel
Save