Browse Source

Merge branch 'development03' into fusion_eth

pull/1262/head
lumapu 10 months ago
parent
commit
6f62b12c9a
  1. 7
      src/CHANGES.md
  2. 9
      src/app.cpp
  3. 2
      src/app.h
  4. 5
      src/appInterface.h
  5. 6
      src/eth/ahoyeth.cpp
  6. 4
      src/hm/hmInverter.h
  7. 10
      src/hm/hmRadio.h
  8. 2
      src/hm/radio.h
  9. 2
      src/hms/hmsRadio.h
  10. 73
      src/plugins/Display/Display.h
  11. 25
      src/plugins/Display/Display_Mono.h
  12. 33
      src/plugins/Display/Display_Mono_128X64.h
  13. 43
      src/plugins/Display/Display_Mono_84X48.h
  14. 4
      src/plugins/Display/Display_data.h
  15. 2
      src/web/RestApi.h
  16. 8
      src/web/html/setup.html
  17. 3
      src/web/html/visualization.html
  18. 11
      tools/fonts/u8g2_font_5x8_symbols_ahoy.bdf
  19. 10
      tools/fonts/u8g2_font_5x8_symbols_ahoy.c_
  20. BIN
      tools/fonts/u8g2_font_5x8_symbols_ahoy.fon
  21. 22
      tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.bdf
  22. 14
      tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.c_
  23. BIN
      tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.fon

7
src/CHANGES.md

@ -1,5 +1,12 @@
# Development Changes
## 0.8.14 - 2023-12-07
* fixed decimal points for temperature (WebUI) PR #1254 #1251
* fixed inverter statemachine available state PR #1252 #1253
* fixed NTP update and sunrise calculation #1240 #886
* display improvments #1248 #1247
* fixed overflow in `hmRadio.h` #1244
## 0.8.13 - 2023-11-28
* merge PR #1239 symbolic layout for OLED 128x64 + motion senser functionality
* fix MqTT IP addr for ETH connections PR #1240

9
src/app.cpp

@ -86,7 +86,11 @@ void app::setup() {
// Plugins
#if defined(PLUGIN_DISPLAY)
if (mConfig->plugin.display.type != 0)
mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, &mTimestamp);
#if defined(ESP32)
mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, &mCmtRadio, &mTimestamp);
#else
mDisplay.setup(this, &mConfig->plugin.display, &mSys, &mNrfRadio, NULL, &mTimestamp);
#endif
#endif
mPubSerial.setup(mConfig, &mSys, &mTimestamp);
@ -197,7 +201,8 @@ void app::updateNtp(void) {
void app::tickNtpUpdate(void) {
uint32_t nxtTrig = 5; // default: check again in 5 sec
#if defined(ETHERNET)
bool isOK = mEth.updateNtpTime();
bool isOK = (mTimestamp != 0);
mEth.updateNtpTime();
#else
bool isOK = mWifi.getNtpTime();
#endif

2
src/app.h

@ -50,7 +50,7 @@ typedef PubSerial<HmSystemType> PubSerialType;
#if defined(PLUGIN_DISPLAY)
#include "plugins/Display/Display.h"
#include "plugins/Display/Display_data.h"
typedef Display<HmSystemType, HmRadio<>> DisplayType;
typedef Display<HmSystemType, Radio> DisplayType;
#endif
class app : public IApp, public ah::Scheduler {

5
src/appInterface.h

@ -53,8 +53,11 @@ class IApp {
virtual bool getSettingsValid() = 0;
virtual void setMqttDiscoveryFlag() = 0;
virtual void setMqttPowerLimitAck(Inverter<> *iv) = 0;
virtual bool getMqttIsConnected() = 0;
virtual bool getNrfEnabled() = 0;
virtual bool getCmtEnabled() = 0;
virtual uint32_t getMqttRxCnt() = 0;
virtual uint32_t getMqttTxCnt() = 0;

6
src/eth/ahoyeth.cpp

@ -59,8 +59,7 @@ bool ahoyeth::updateNtpTime(void) {
return false;
DPRINTLN(DBG_DEBUG, F("updateNtpTime: checking udp \"connection\"...")); Serial.flush();
if (!mUdp.connected())
{
if (!mUdp.connected()) {
DPRINTLN(DBG_DEBUG, F("updateNtpTime: About to (re)connect...")); Serial.flush();
IPAddress timeServer;
if (!WiFi.hostByName(mConfig->ntp.addr, timeServer))
@ -70,8 +69,7 @@ bool ahoyeth::updateNtpTime(void) {
return false;
DPRINTLN(DBG_DEBUG, F("updateNtpTime: Connected...")); Serial.flush();
mUdp.onPacket([this](AsyncUDPPacket packet)
{
mUdp.onPacket([this](AsyncUDPPacket packet) {
DPRINTLN(DBG_DEBUG, F("updateNtpTime: about to handle ntp packet...")); Serial.flush();
this->handleNTPPacket(packet);
});

4
src/hm/hmInverter.h

@ -391,6 +391,10 @@ class Inverter {
bool isAvailable() {
bool avail = false;
if((recordMeas.ts == 0) && (recordInfo.ts == 0) && (recordConfig.ts == 0) && (recordAlarm.ts == 0))
return false;
if((*timestamp - recordMeas.ts) < INVERTER_INACT_THRES_SEC)
avail = true;
if((*timestamp - recordInfo.ts) < INVERTER_INACT_THRES_SEC)

10
src/hm/hmRadio.h

@ -127,10 +127,10 @@ class HmRadio : public Radio {
if(NULL == mLastIv) // prevent reading on NULL object!
return;
uint32_t startMicros = micros() + 5110;
uint32_t loopMillis = millis() + 400;
while (millis() < loopMillis) {
while (micros() < startMicros) { // listen (4088us or?) 5110us to each channel
uint32_t startMicros = micros();
uint32_t loopMillis = millis();
while ((millis() - loopMillis) < 400) {
while ((micros() - startMicros) < 5110) { // listen (4088us or?) 5110us to each channel
if (mIrqRcvd) {
mIrqRcvd = false;
@ -144,7 +144,7 @@ class HmRadio : public Radio {
if(++mRxChIdx >= RF_CHANNELS)
mRxChIdx = 0;
mNrf24->setChannel(mRfChLst[mRxChIdx]);
startMicros = micros() + 5110;
startMicros = micros();
}
// not finished but time is over
if(++mRxChIdx >= RF_CHANNELS)

2
src/hm/radio.h

@ -24,6 +24,8 @@ class Radio {
virtual void sendControlPacket(Inverter<> *iv, uint8_t cmd, uint16_t *data, bool isRetransmit) = 0;
virtual bool switchFrequency(Inverter<> *iv, uint32_t fromkHz, uint32_t tokHz) { return true; }
virtual bool switchFrequencyCh(Inverter<> *iv, uint8_t fromCh, uint8_t toCh) { return true; }
virtual bool isChipConnected(void) { return false; }
virtual void loop(void) {};
bool get() {

2
src/hms/hmsRadio.h

@ -37,7 +37,7 @@ class CmtRadio : public Radio {
}
}
bool isConnected() {
bool isChipConnected(void) {
return mCmtAvail;
}

73
src/plugins/Display/Display.h

@ -15,16 +15,17 @@
#include "Display_ePaper.h"
#include "Display_data.h"
template <class HMSYSTEM, class HMRADIO>
template <class HMSYSTEM, class RADIO>
class Display {
public:
Display() {
mMono = NULL;
}
void setup(IApp *app, display_t *cfg, HMSYSTEM *sys, HMRADIO *radio, uint32_t *utcTs) {
void setup(IApp *app, display_t *cfg, HMSYSTEM *sys, RADIO *hmradio, RADIO *hmsradio, uint32_t *utcTs) {
mApp = app;
mHmRadio = radio;
mHmRadio = hmradio;
mHmsRadio = hmsradio;
mCfg = cfg;
mSys = sys;
mUtcTs = utcTs;
@ -34,13 +35,13 @@ class Display {
mDisplayData.version = app->getVersion(); // version never changes, so only set once
switch (mCfg->type) {
case 0: mMono = NULL; break;
case 1: // fall-through
case 2: mMono = new DisplayMono128X64(); break;
case 3: mMono = new DisplayMono84X48(); break;
case 4: mMono = new DisplayMono128X32(); break;
case 5: mMono = new DisplayMono64X48(); break;
case 6: mMono = new DisplayMono128X64(); break;
case 0: mMono = NULL; break; // None
case 1: mMono = new DisplayMono128X64(); break; // SSD1306_128X64 (0.96", 1.54")
case 2: mMono = new DisplayMono128X64(); break; // SH1106_128X64 (1.3")
case 3: mMono = new DisplayMono84X48(); break; // PCD8544_84X48 (1.6" - Nokia 5110)
case 4: mMono = new DisplayMono128X32(); break; // SSD1306_128X32 (0.91")
case 5: mMono = new DisplayMono64X48(); break; // SSD1306_64X48 (0.66" - Wemos OLED Shield)
case 6: mMono = new DisplayMono128X64(); break; // SSD1309_128X64 (2.42")
#if defined(ESP32)
case 10:
mMono = NULL; // ePaper does not use this
@ -92,9 +93,9 @@ class Display {
if (mCfg->type == 0)
return;
float totalPower = 0;
float totalYieldDay = 0;
float totalYieldTotal = 0;
float totalPower = 0.0;
float totalYieldDay = 0.0;
float totalYieldTotal = 0.0;
uint8_t nrprod = 0;
uint8_t nrsleep = 0;
@ -109,6 +110,14 @@ class Display {
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->txRfQuality[ch];
@ -118,33 +127,36 @@ class Display {
if (maxQInv < minQAllInv)
minQAllInv = maxQInv;
rec = iv->getRecordStruct(RealTimeRunData_Debug);
if (iv->isProducing())
nrprod++;
else
nrsleep++;
totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec); // add only FLD_PAC from inverters still communicating
allOff = false;
}
totalPower += iv->getChannelFieldValue(CH0, FLD_PAC, rec);
totalYieldDay += iv->getChannelFieldValue(CH0, FLD_YD, rec);
totalYieldTotal += iv->getChannelFieldValue(CH0, FLD_YT, rec);
if(allOff) {
if(iv->status != InverterStatus::OFF)
allOff = false;
}
}
if (allOff)
minQAllInv = -6;
// prepare display data
mDisplayData.nrProducing = nrprod;
mDisplayData.nrSleeping = nrsleep;
mDisplayData.totalPower = (allOff) ? 0.0 : totalPower; // if all inverters are off, total power can't be greater than 0
mDisplayData.totalPower = totalPower;
mDisplayData.totalYieldDay = totalYieldDay;
mDisplayData.totalYieldTotal = totalYieldTotal;
mDisplayData.RadioSymbol = mHmRadio->isChipConnected();
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 = (0 < mDisplayData.nrProducing) ? ivQuality2RadioRSSI(minQAllInv) : SCHAR_MIN; // Workaround as NRF24 has no RSSI. Approximation by quality levels from heuristic function
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();
time_t utc= mApp->getTimestamp();
@ -158,7 +170,7 @@ class Display {
}
#if defined(ESP32)
else if (mCfg->type == 10) {
mEpaper.loop(((allOff) ? 0.0 : totalPower), totalYieldDay, totalYieldTotal, nrprod);
mEpaper.loop((totalPower), totalYieldDay, totalYieldTotal, nrprod);
mRefreshCycle++;
}
@ -212,7 +224,8 @@ class Display {
uint32_t *mUtcTs;
display_t *mCfg;
HMSYSTEM *mSys;
HMRADIO *mHmRadio;
RADIO *mHmRadio;
RADIO *mHmsRadio;
uint16_t mRefreshCycle;
#if defined(ESP32)

25
src/plugins/Display/Display_Mono.h

@ -114,8 +114,8 @@ Symbols:
\x87 ... moon
\x88 ... calendar/day
\x89 ... MQTT */
const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_symbols_ahoy") =
"j\0\3\2\4\4\3\4\5\10\10\0\377\6\377\6\0\1\61\2b\4\3 \5\0\304\11!\7a\306"
const uint8_t u8g2_font_5x8_symbols_ahoy[1049] U8G2_FONT_SECTION("u8g2_font_5x8_symbols_ahoy") =
"j\0\3\2\4\4\3\4\5\10\10\0\377\6\377\6\0\1\61\2b\4\0 \5\0\304\11!\7a\306"
"\212!\11\42\7\63\335\212\304\22#\16u\304\232R\222\14JePJI\2$\14u\304\252l\251m"
"I\262E\0%\10S\315\212(\351\24&\13t\304\232(i\252\64%\1'\6\61\336\212\1(\7b"
"\305\32\245))\11b\305\212(\251(\0*\13T\304\212(Q\206D\211\2+\12U\304\252\60\32\244"
@ -145,9 +145,10 @@ const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_
"\0z\11D\304\212!*\15\1{\12t\304*%L\304(\24|\6a\306\212\3}\13t\304\12\61"
"\12\225\60\221\0~\10$\344\232DI\0\5\0\304\12\200\13u\274\212K\242T\266\260\4\201\14f"
"D\233!\11#-\312!\11\202\15hD<\65\12\243,\214\302$\16\203\15w<\214C\22F\71\220"
"\26\207A\204\16\205\274\212,)%Y\230%QR\13\205\17\206<\213\60\31\22\311\66D\245!\11\3"
"\206\20\210<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w"
"<\214\203RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0";
"\26\207A\204\13u\274\212\244\232t\313\241\10\205\17\206<\213\60\31\22\311\66D\245!\11\3\206\20\210"
"<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w<\214\203"
"RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0";
const uint8_t u8g2_font_ncenB08_symbols8_ahoy[173] U8G2_FONT_SECTION("u8g2_font_ncenB08_symbols8_ahoy") =
"\13\0\3\2\4\4\1\2\5\10\11\0\0\10\0\10\0\0\0\0\0\0\224A\14\207\305\70H\321\222H"
@ -157,11 +158,11 @@ const uint8_t u8g2_font_ncenB08_symbols8_ahoy[173] U8G2_FONT_SECTION("u8g2_font_
"Q\4H\14w\307\215Uq\33\16\321\20\1I\21\227\305\311\222aP\245H\221\244H\212\324a\20J"
"\5\0\275\0K\5\0\315\0\0\0\0";
const uint8_t u8g2_font_ncenB10_symbols10_ahoy[220] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") =
"\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\303A\15\267\212q\220\42\251\322"
const uint8_t u8g2_font_ncenB10_symbols10_ahoy[217] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") =
"\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\300A\15\267\212q\220\42\251\322"
"\266\306\275\1B\20\230\236\65da\22Ima\250F\71\254\1C\23\272\272\251\3Q\32\366Q\212\243"
"\70\212\243\70\311\221\0D\20\271\252\361\242F:\242#: {\36\16\1E\22\267\212\361\222\14I\242"
"\14\332\232\216[RJ\232\12F\25\250\233\221\14I\61I\206$\252%J\250Fa\224%J\71G\30"
"\273\312W\316r`T\262DJ\303\64L#%K\304\35\310\342,\3H\27\272\272\217\344P\16\351\210"
"\16\354\300<\244C\70,\303 \16!\0I\24\271\252\241\34\336\1-\223\64-\323\62-\323\62\35x"
"\10J\22\210\232\61Hi\64Di\64DI\226$KeiK\5\0\232\1\0\0\0";
"\70\212\243\70\311\221\0D\20\271\252\361\242F:\242#: {\36\16\1E\17\267\212\221\264\3Q\35"
"\332\321\34\316\341\14F\25\250\233\221\14I\61I\206$\252%J\250Fa\224%J\71G\30\273\312W"
"\316r`T\262DJ\303\64L#%K\304\35\310\342,\3H\27\272\272\217\344P\16\351\210\16\354\300"
"<\244C\70,\303 \16!\0I\24\271\252\241\34\336\1-\223\64-\323\62-\323\62\35x\10J\22"
"\210\232\61Hi\64Di\64DI\226$KeiK\5\0\212\1\0\0\0";

33
src/plugins/Display/Display_Mono_128X64.h

@ -49,9 +49,9 @@ class DisplayMono128X64 : public DisplayMono {
/*
mDisplayData->nrSleeping = 10;
mDisplayData->nrProducing = 10;
mDisplayData->totalPower = 99990;
mDisplayData->totalYieldDay = 8888;
mDisplayData->totalYieldTotal = 9999;
mDisplayData->totalPower = 54321.9; // W
mDisplayData->totalYieldDay = 4321.9; // Wh
mDisplayData->totalYieldTotal = 4321.9; // kWh
mDisplay->drawPixel(0, 0);
mDisplay->drawPixel(mDispWidth-1, 0);
mDisplay->drawPixel(0, mDispHeight-1);
@ -64,9 +64,10 @@ class DisplayMono128X64 : public DisplayMono {
// print total power
if (mDisplayData->nrProducing > 0) {
if (mDisplayData->totalPower > 999)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000));
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kW", (mDisplayData->totalPower / 1000.0));
else
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower);
printText(mFmtText, l_TotalPower, 0xff);
} else {
printText("offline", l_TotalPower, 0xff);
@ -109,19 +110,27 @@ class DisplayMono128X64 : public DisplayMono {
pos = (mDispWidth - mDisplay->getStrWidth(mFmtText)) / 2;
mDisplay->setFont(u8g2_font_ncenB08_symbols8_ahoy);
if (sun_pos!=-1)
mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun
mDisplay->drawStr(pos + sun_pos + mPixelshift, mLineYOffsets[l_Status], "G"); // sun symbol
if (moon_pos!=-1)
mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon
mDisplay->drawStr(pos + moon_pos + mPixelshift, mLineYOffsets[l_Status], "H"); // moon symbol
}
// print yields
mDisplay->setFont(u8g2_font_ncenB10_symbols10_ahoy);
mDisplay->drawStr(17 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day
mDisplay->drawStr(17 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.0f Wh", mDisplayData->totalYieldDay);
printText(mFmtText, l_YieldDay, 25);
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.1f kWh", mDisplayData->totalYieldTotal);
printText(mFmtText, l_YieldTotal, 25);
mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldDay], "I"); // day symbol
mDisplay->drawStr(16 + mPixelshift, mLineYOffsets[l_YieldTotal], "D"); // total symbol
if (mDisplayData->totalYieldDay > 999.0)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldDay / 1000.0);
else
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay);
printText(mFmtText, l_YieldDay, 0xff);
if (mDisplayData->totalYieldTotal > 999.0)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f MWh", mDisplayData->totalYieldTotal / 1000.0);
else
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldTotal);
printText(mFmtText, l_YieldTotal, 0xff);
// draw dynamic RSSI bars
int xoffs;

43
src/plugins/Display/Display_Mono_84X48.h

@ -34,12 +34,11 @@ class DisplayMono84X48 : public DisplayMono {
// Layout-Test
/*
mDisplayData->nrSleeping = 0;
mDisplayData->nrProducing = 1;
mDisplayData->totalPower = 12345.67;
mDisplayData->totalYieldDay = 12345.67;
mDisplayData->totalYieldTotal = 1234;
mDisplayData->utcTs += 1000000;
mDisplayData->nrSleeping = 10;
mDisplayData->nrProducing = 10;
mDisplayData->totalPower = 111.91; // W
mDisplayData->totalYieldDay = 54321.9; // Wh
mDisplayData->totalYieldTotal = 654321.9; // kWh
mDisplay->drawPixel(0, 0);
mDisplay->drawPixel(mDispWidth-1, 0);
mDisplay->drawPixel(0, mDispHeight-1);
@ -48,12 +47,10 @@ class DisplayMono84X48 : public DisplayMono {
// print total power
if (mDisplayData->nrProducing > 0) {
if (mDisplayData->totalPower > 9999)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2fkW", (mDisplayData->totalPower / 1000)); // forgo spacing between value and SI unit in favor of second position after decimal point
else if (mDisplayData->totalPower > 999)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.2f kW", (mDisplayData->totalPower / 1000));
if (mDisplayData->totalPower > 999)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kW", (mDisplayData->totalPower / 1000));
else
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f W", mDisplayData->totalPower);
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f W", mDisplayData->totalPower);
printText(mFmtText, l_TotalPower, 0xff);
} else {
@ -75,21 +72,29 @@ class DisplayMono84X48 : public DisplayMono {
if (0 == mDisplayData->nrSleeping + mDisplayData->nrProducing)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "no inverter");
else if (0 == mDisplayData->nrSleeping)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x86");
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x86"); // sun symbol
else if (0 == mDisplayData->nrProducing)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x87");
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "\x87"); // moon symbol
else
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%d\x86 %d\x87", mDisplayData->nrProducing, mDisplayData->nrSleeping);
printText(mFmtText, l_Status, 0xff);
}
// print yields
printText("\x88", l_YieldDay, 11); // day symbol
printText("\x83", l_YieldTotal, 11); // total symbol
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.0f Wh", mDisplayData->totalYieldDay);
printText(mFmtText, l_YieldDay, 18);
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%7.1f kWh", mDisplayData->totalYieldTotal);
printText(mFmtText, l_YieldTotal, 18);
printText("\x88", l_YieldDay, 10); // day symbol
printText("\x83", l_YieldTotal, 10); // total symbol
if (mDisplayData->totalYieldDay > 999.0)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldDay / 1000.0);
else
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.0f Wh", mDisplayData->totalYieldDay);
printText(mFmtText, l_YieldDay, 0xff);
if (mDisplayData->totalYieldTotal > 999.0)
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f MWh", mDisplayData->totalYieldTotal / 1000.0);
else
snprintf(mFmtText, DISP_FMT_TEXT_LEN, "%.1f kWh", mDisplayData->totalYieldTotal);
printText(mFmtText, l_YieldTotal, 0xff);
// draw dynamic Nokia RSSI bars
int rssi_bar_height = 7;

4
src/plugins/Display/Display_data.h

@ -6,8 +6,8 @@
struct DisplayData {
const char *version=nullptr;
float totalPower=0.0f; // indicate current power (W)
float totalYieldDay=0.0f; // indicate day yield (W)
float totalYieldTotal=0.0f; // indicate total yield (W)
float totalYieldDay=0.0f; // indicate day yield (Wh)
float totalYieldTotal=0.0f; // indicate total yield (kWh)
uint32_t utcTs=0; // indicate absolute timestamp (utc unix time). 0 = time is not synchonized
uint8_t nrProducing=0; // indicate number of producing inverters
uint8_t nrSleeping=0; // indicate number of sleeping inverters

2
src/web/RestApi.h

@ -547,7 +547,7 @@ class RestApi {
void getRadioCmtInfo(JsonObject obj) {
obj[F("en")] = (bool) mConfig->cmt.enabled;
obj[F("isconnected")] = mRadioCmt->isConnected();
obj[F("isconnected")] = mRadioCmt->isChipConnected();
obj[F("sn")] = String(mRadioCmt->getDTUSn(), HEX);
}
#endif

8
src/web/html/setup.html

@ -964,7 +964,13 @@
);
}
// keep display types grouped
var opts = [[0, "None"], [2, "SH1106 1.3\" 128X64"], [5, "SSD1306 0.66\" 64X48 (Wemos OLED Shield)"], [4, "SSD1306 0.91\" 128X32"], [1, "SSD1306 0.96\" 128X64"], [6, "SSD1309 2.42\" 128X64"], [3, "Nokia5110"]];
var opts = [[0, "None"],
[2, "SH1106 128x64 (1.3\")"],
[5, "SSD1306 64x48 (0.66\" Wemos OLED Shield)"],
[4, "SSD1306 128x32 (0.91\")"],
[1, "SSD1306 128x64 (0.96\", 1.54\")"],
[6, "SSD1309 128X64 (2.42\")"],
[3, "PCD8544 84X48 (1.6\" Nokia 5110)"]];
/*IF_ESP32*/
opts.push([10, "ePaper"]);
/*ENDIF_ESP32*/

3
src/web/html/visualization.html

@ -108,7 +108,6 @@
if(0 != obj.max_pwr)
pwrLimit += ", " + Math.round(obj.max_pwr * obj.power_limit_read / 100) + "W";
}
return ml("div", {class: "row mt-2"},
ml("div", {class: "col"}, [
ml("div", {class: "p-2 " + clh},
@ -123,7 +122,7 @@
ml("div", {class: "col a-c"}, ml("span", { class: "pointer", onclick: function() {
getAjax("/api/inverter/alarm/" + obj.id, parseIvAlarm);
}}, ("Alarms: " + obj.alarm_cnt))),
ml("div", {class: "col a-r mx-2 mx-md-1"}, String(obj.ch[0][5]) + t.innerText)
ml("div", {class: "col a-r mx-2 mx-md-1"}, String(obj.ch[0][5].toFixed(1)) + t.innerText)
])
),
ml("div", {class: "p-2 " + clbg}, [

11
tools/fonts/u8g2_font_5x8_symbols_ahoy.bdf

@ -1243,16 +1243,15 @@ STARTCHAR 132
ENCODING 132
SWIDTH 360 0
DWIDTH 5 0
BBX 5 8 0 -1
BBX 5 7 0 -1
BITMAP
88
50
A8
00
A8
50
20
00
20
50
50
88
ENDCHAR
STARTCHAR 133
ENCODING 133

10
tools/fonts/u8g2_font_5x8_symbols_ahoy.c_

@ -4,8 +4,8 @@
Glyphs: 106/106
BBX Build Mode: 0
*/
const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_symbols_ahoy") =
"j\0\3\2\4\4\3\4\5\10\10\0\377\6\377\6\0\1\61\2b\4\3 \5\0\304\11!\7a\306"
const uint8_t u8g2_font_5x8_symbols_ahoy[1049] U8G2_FONT_SECTION("u8g2_font_5x8_symbols_ahoy") =
"j\0\3\2\4\4\3\4\5\10\10\0\377\6\377\6\0\1\61\2b\4\0 \5\0\304\11!\7a\306"
"\212!\11\42\7\63\335\212\304\22#\16u\304\232R\222\14JePJI\2$\14u\304\252l\251m"
"I\262E\0%\10S\315\212(\351\24&\13t\304\232(i\252\64%\1'\6\61\336\212\1(\7b"
"\305\32\245))\11b\305\212(\251(\0*\13T\304\212(Q\206D\211\2+\12U\304\252\60\32\244"
@ -35,6 +35,6 @@ const uint8_t u8g2_font_5x8_symbols_ahoy[1052] U8G2_FONT_SECTION("u8g2_font_5x8_
"\0z\11D\304\212!*\15\1{\12t\304*%L\304(\24|\6a\306\212\3}\13t\304\12\61"
"\12\225\60\221\0~\10$\344\232DI\0\5\0\304\12\200\13u\274\212K\242T\266\260\4\201\14f"
"D\233!\11#-\312!\11\202\15hD<\65\12\243,\214\302$\16\203\15w<\214C\22F\71\220"
"\26\207A\204\16\205\274\212,)%Y\230%QR\13\205\17\206<\213\60\31\22\311\66D\245!\11\3"
"\206\20\210<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w"
"<\214\203RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0";
"\26\207A\204\13u\274\212\244\232t\313\241\10\205\17\206<\213\60\31\22\311\66D\245!\11\3\206\20\210"
"<\254\342\20]\302(L\246C\30E\0\207\15wD\334X\25\267\341\20\15\21\0\210\16w<\214\203"
"RQ\25I\212\324a\20\211\15f\304\213)\213\244,\222\222\245\0\0\0\0";

BIN
tools/fonts/u8g2_font_5x8_symbols_ahoy.fon

Binary file not shown.

22
tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.bdf

@ -88,17 +88,17 @@ SWIDTH 576 0
DWIDTH 8 0
BBX 7 11 0 0
BITMAP
FE
D6
D6
7C
AA
00
92
00
38
00
10
00
10
00
10
38
38
54
54
92
ENDCHAR
STARTCHAR 070
ENCODING 70
@ -188,8 +188,8 @@ D5
ENDCHAR
STARTCHAR 075
ENCODING 75
SWIDTH 648 0
DWIDTH 9 0
SWIDTH 576 0
DWIDTH 8 0
BBX 0 0 0 0
BITMAP
ENDCHAR

14
tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.c_

@ -4,11 +4,11 @@
Glyphs: 11/11
BBX Build Mode: 0
*/
const uint8_t u8g2_font_ncenB10_symbols10_ahoy[220] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") =
"\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\303A\15\267\212q\220\42\251\322"
const uint8_t u8g2_font_ncenB10_symbols10_ahoy[217] U8G2_FONT_SECTION("u8g2_font_ncenB10_symbols10_ahoy") =
"\13\0\3\2\4\4\2\2\5\13\13\0\0\13\0\13\0\0\0\0\0\0\300A\15\267\212q\220\42\251\322"
"\266\306\275\1B\20\230\236\65da\22Ima\250F\71\254\1C\23\272\272\251\3Q\32\366Q\212\243"
"\70\212\243\70\311\221\0D\20\271\252\361\242F:\242#: {\36\16\1E\22\267\212\361\222\14I\242"
"\14\332\232\216[RJ\232\12F\25\250\233\221\14I\61I\206$\252%J\250Fa\224%J\71G\30"
"\273\312W\316r`T\262DJ\303\64L#%K\304\35\310\342,\3H\27\272\272\217\344P\16\351\210"
"\16\354\300<\244C\70,\303 \16!\0I\24\271\252\241\34\336\1-\223\64-\323\62-\323\62\35x"
"\10J\22\210\232\61Hi\64Di\64DI\226$KeiK\5\0\232\1\0\0\0";
"\70\212\243\70\311\221\0D\20\271\252\361\242F:\242#: {\36\16\1E\17\267\212\221\264\3Q\35"
"\332\321\34\316\341\14F\25\250\233\221\14I\61I\206$\252%J\250Fa\224%J\71G\30\273\312W"
"\316r`T\262DJ\303\64L#%K\304\35\310\342,\3H\27\272\272\217\344P\16\351\210\16\354\300"
"<\244C\70,\303 \16!\0I\24\271\252\241\34\336\1-\223\64-\323\62-\323\62\35x\10J\22"
"\210\232\61Hi\64Di\64DI\226$KeiK\5\0\212\1\0\0\0";

BIN
tools/fonts/u8g2_font_ncenB10_symbols10_ahoy.fon

Binary file not shown.
Loading…
Cancel
Save