diff --git a/src/CHANGES.md b/src/CHANGES.md index a16a638e..6c59822e 100644 --- a/src/CHANGES.md +++ b/src/CHANGES.md @@ -1,5 +1,22 @@ # Development Changes +## 0.7.46 - 2023-09-04 +* removed `delay` from ePaper +* started improvements of `/system` +* fix LEDs to check all configured inverters +* send loop skip disabled inverters fix +* print generated DTU SN to console +* HW Versions for MI series PR #1133 +* 2.42" display (SSD1309) integration PR #1139 +* update user manual PR #1121 +* add / rename alarm codes PR #1118 +* revert default pin ESP32 for NRF23-CE #1132 +* luminance of display can be changed during runtime #1106 + +## 0.7.45 - 2023-08-29 +* change ePaper text to symbols PR #1131 +* added some invertes to dev info list #1111 + ## 0.7.44 - 2023-08-28 * fix `last_success` transmitted to often #1124 diff --git a/src/app.cpp b/src/app.cpp index 8088d483..e2311e1c 100644 --- a/src/app.cpp +++ b/src/app.cpp @@ -463,24 +463,26 @@ void app::tickSend(void) { int8_t maxLoop = MAX_NUM_INVERTERS; Inverter<> *iv = mSys.getInverterByPos(mSendLastIvId); do { - mSendLastIvId = ((MAX_NUM_INVERTERS - 1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; - iv = mSys.getInverterByPos(mSendLastIvId); - } while ((NULL == iv) && ((maxLoop--) > 0)); + do { + mSendLastIvId = ((MAX_NUM_INVERTERS - 1) == mSendLastIvId) ? 0 : mSendLastIvId + 1; + iv = mSys.getInverterByPos(mSendLastIvId); + } while ((NULL == iv) && ((maxLoop--) > 0)); + } while((!iv->config->enabled) && (maxLoop > 0)); if (NULL != iv) { if (iv->config->enabled) { if(mConfig->nrf.enabled) { - if (iv->ivGen == IV_HM) - mPayload.ivSend(iv); - else if(iv->ivGen == IV_MI) - mMiPayload.ivSend(iv); - } - #if defined(ESP32) - if(mConfig->cmt.enabled) { - if((iv->ivGen == IV_HMS) || (iv->ivGen == IV_HMT)) - mHmsPayload.ivSend(iv); - } - #endif + if (iv->ivGen == IV_HM) + mPayload.ivSend(iv); + else if(iv->ivGen == IV_MI) + mMiPayload.ivSend(iv); + } + #if defined(ESP32) + if(mConfig->cmt.enabled) { + if((iv->ivGen == IV_HMS) || (iv->ivGen == IV_HMT)) + mHmsPayload.ivSend(iv); + } + #endif } } } else { @@ -577,11 +579,11 @@ void app::mqttSubRxCb(JsonObject obj) { void app::setupLed(void) { uint8_t led_off = (mConfig->led.led_high_active) ? LOW : HIGH; - if (mConfig->led.led0 != 0xff) { + if (mConfig->led.led0 != DEF_PIN_OFF) { pinMode(mConfig->led.led0, OUTPUT); digitalWrite(mConfig->led.led0, led_off); } - if (mConfig->led.led1 != 0xff) { + if (mConfig->led.led1 != DEF_PIN_OFF) { pinMode(mConfig->led.led1, OUTPUT); digitalWrite(mConfig->led.led1, led_off); } @@ -592,17 +594,23 @@ void app::updateLed(void) { uint8_t led_off = (mConfig->led.led_high_active) ? LOW : HIGH; uint8_t led_on = (mConfig->led.led_high_active) ? HIGH : LOW; - if (mConfig->led.led0 != 0xff) { - Inverter<> *iv = mSys.getInverterByPos(0); - if (NULL != iv) { - if (iv->isProducing()) - digitalWrite(mConfig->led.led0, led_on); - else - digitalWrite(mConfig->led.led0, led_off); + if (mConfig->led.led0 != DEF_PIN_OFF) { + Inverter<> *iv; + for (uint8_t id = 0; id < mSys.getNumInverters(); id++) { + iv = mSys.getInverterByPos(id); + if (NULL != iv) { + if (iv->isProducing()) { + // turn on when at least one inverter is producing + digitalWrite(mConfig->led.led0, led_on); + break; + } + else if(iv->config->enabled) + digitalWrite(mConfig->led.led0, led_off); + } } } - if (mConfig->led.led1 != 0xff) { + if (mConfig->led.led1 != DEF_PIN_OFF) { if (getMqttIsConnected()) { digitalWrite(mConfig->led.led1, led_on); } else { diff --git a/src/app.h b/src/app.h index 5712a72b..3989f6bd 100644 --- a/src/app.h +++ b/src/app.h @@ -276,6 +276,7 @@ class app : public IApp, public ah::Scheduler { #endif if(mConfig->plugin.display.type != 0) mDisplay.payloadEventListener(cmd); + updateLed(); } void mqttSubRxCb(JsonObject obj); diff --git a/src/config/config.h b/src/config/config.h index eae05cd6..cbf99c49 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -68,7 +68,7 @@ #define DEF_NRF_CS_PIN 5 #endif #ifndef DEF_NRF_CE_PIN - #define DEF_NRF_CE_PIN 17 + #define DEF_NRF_CE_PIN 4 #endif #ifndef DEF_NRF_IRQ_PIN #define DEF_NRF_IRQ_PIN 16 diff --git a/src/defines.h b/src/defines.h index 3884a4d2..b7da7f8d 100644 --- a/src/defines.h +++ b/src/defines.h @@ -13,7 +13,7 @@ //------------------------------------- #define VERSION_MAJOR 0 #define VERSION_MINOR 7 -#define VERSION_PATCH 44 +#define VERSION_PATCH 46 //------------------------------------- typedef struct { diff --git a/src/hm/hmDefines.h b/src/hm/hmDefines.h index 7b1549ab..71a61db5 100644 --- a/src/hm/hmDefines.h +++ b/src/hm/hmDefines.h @@ -25,7 +25,7 @@ enum {FLD_UDC = 0, FLD_IDC, FLD_PDC, FLD_YD, FLD_YW, FLD_YT, FLD_FW_BUILD_MONTH_DAY, FLD_FW_BUILD_HOUR_MINUTE, FLD_BOOTLOADER_VER, FLD_ACT_ACTIVE_PWR_LIMIT, FLD_PART_NUM, FLD_HW_VERSION, FLD_GRID_PROFILE_CODE, FLD_GRID_PROFILE_VERSION, /*FLD_ACT_REACTIVE_PWR_LIMIT, FLD_ACT_PF,*/ FLD_LAST_ALARM_CODE, FLD_MP}; - + const char* const fields[] = {"U_DC", "I_DC", "P_DC", "YieldDay", "YieldWeek", "YieldTotal", "U_AC", "U_AC_1N", "U_AC_2N", "U_AC_3N", "UAC_12", "UAC_23", "UAC_31", "I_AC", "IAC_1", "I_AC_2", "I_AC_3", "P_AC", "F_AC", "Temp", "PF_AC", "Efficiency", "Irradiation","Q_AC", @@ -259,20 +259,60 @@ typedef struct { uint16_t maxPower; } devInfo_t; +// https://github.com/lumapu/ahoy/issues/1111 +// Hardware number: +// 0xAABBCCDD +// ^^ ------- always 10 (for MI, HM, HMS, HMT) +// ^ ------ 0 = MI +// 1 = HM +// 1, 2 = HMS (version) +// 3 = HMT +// ^ ----- 0 = 1 Input +// 1 = 2 Inputs +// 2 = 4 Inputs +// 3 = 6 Inputs +// ^ ---- 0 = smallest with x inputs +// 7 = biggest with x inputs + const devInfo_t devInfo[] = { + // MI 2nd gen; only 0x001311 is tested, + // others (starting with MI-250) according to https://github.com/lumapu/ahoy/issues/1111#issuecomment-1698100571 + { 0x000111, 250 }, + { 0x000311, 300 }, + { 0x000411, 350 }, + { 0x001111, 500 }, + { 0x001311, 600 }, + { 0x001321, 600 }, + { 0x001421, 700 }, + { 0x001411, 700 }, + { 0x002111, 1000 }, + { 0x002311, 1200 }, + { 0x002511, 1500 }, + { 0x002411, 1500 }, + // MI 3rd gen + { 0x100000, 250 }, + { 0x100010, 300 }, + { 0x100020, 350 }, + { 0x100030, 400 }, + { 0x100100, 500 }, + { 0x100110, 600 }, + { 0x100120, 700 }, + { 0x100130, 800 }, + { 0x100200, 1000 }, + { 0x100210, 1200 }, { 0x100230, 1500 }, // HM { 0x101010, 300 }, { 0x101020, 350 }, { 0x101030, 400 }, - { 0x101040, 400 }, - { 0x101110, 600 }, // [TSOL800(DE) ..20, HWv=??], [HM-600 ..20, HWv=2.66] + { 0x101110, 600 }, // [TSOL800(DE) ..20, HWv=2.66], [HM-600 ..20, HWv=2.66] { 0x101120, 700 }, { 0x101130, 800 }, { 0x101140, 800 }, - { 0x101210, 1200 }, // ..00 + { 0x101200, 1000 }, + { 0x101210, 1200 }, { 0x101230, 1500 }, // HMS @@ -281,18 +321,19 @@ const devInfo_t devInfo[] = { { 0x101051, 450 }, { 0x101071, 500 }, { 0x102111, 600 }, + { 0x101120, 700 }, { 0x102141, 800 }, { 0x101151, 900 }, { 0x102171, 1000 }, { 0x102241, 1600 }, { 0x101251, 1800 }, { 0x102251, 1800 }, - { 0x101271, 2000 }, // ..00 - { 0x102271, 2000 }, + { 0x101271, 2000 }, // v1 grey backplane, 14A + { 0x102271, 2000 }, // v2 black backplane, 16A // HMT { 0x103311, 1800 }, - { 0x103331, 2250 } // ..00 + { 0x103331, 2250 } }; #endif /*__HM_DEFINES_H__*/ diff --git a/src/hm/hmInverter.h b/src/hm/hmInverter.h index b8dd4468..a43788a9 100644 --- a/src/hm/hmInverter.h +++ b/src/hm/hmInverter.h @@ -210,8 +210,13 @@ class Inverter { enqueCommand(InverterDevInform_Simple); // hardware version enqueCommand(RealTimeRunData_Debug); // live data } else if (ivGen == IV_MI){ - if (getFwVersion() == 0) - enqueCommand(InverterDevInform_All); // firmware version; might not work, esp. for 1/2 ch hardware + if (getFwVersion() == 0) { + enqueCommand(InverterDevInform_All); // hard- and firmware version + } else { + record_t<> *rec = getRecordStruct(InverterDevInform_Simple); + if (getChannelFieldValue(CH0, FLD_PART_NUM, rec) == 0) + enqueCommand(InverterDevInform_All); // hard- and firmware version for missing HW part nr, delivered by frame 1 + } if (type == INV_TYPE_4CH) { enqueCommand(0x36); } else { diff --git a/src/hm/hmPayload.h b/src/hm/hmPayload.h index f5b56405..7826dbdd 100644 --- a/src/hm/hmPayload.h +++ b/src/hm/hmPayload.h @@ -347,6 +347,9 @@ class HmPayload { yield(); } } + if( (InverterDevInform_All == mPayload[iv->id].txCmd) && (mHighPrioIv == NULL) ) // process next request immediately if possible + mHighPrioIv = iv; + } else { DPRINT(DBG_ERROR, F("plausibility check failed, expected ")); DBGPRINT(String(rec->pyldLen)); diff --git a/src/hm/hmRadio.h b/src/hm/hmRadio.h index 0b5feea5..ee037adb 100644 --- a/src/hm/hmRadio.h +++ b/src/hm/hmRadio.h @@ -32,7 +32,7 @@ class HmRadio { public: HmRadio() : mNrf24(CE_PIN, CS_PIN, SPI_SPEED) { if(mSerialDebug) { - DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); + DPRINT(DBG_VERBOSE, F("hmRadio.h : HmRadio():mNrf24(CE_PIN: ")); DBGPRINT(String(CE_PIN)); DBGPRINT(F(", CS_PIN: ")); DBGPRINT(String(CS_PIN)); @@ -117,8 +117,9 @@ class HmRadio { if(mNrf24.isChipConnected()) { DPRINTLN(DBG_INFO, F("Radio Config:")); mNrf24.printPrettyDetails(); - } - else + DPRINT(DBG_INFO, F("DTU_SN: 0x")); + DBGPRINTLN(String(DTU_RADIO_ID, HEX)); + } else DPRINTLN(DBG_WARN, F("WARNING! your NRF24 module can't be reached, check the wiring")); } diff --git a/src/hm/miPayload.h b/src/hm/miPayload.h index e461a8dc..ca2da50e 100644 --- a/src/hm/miPayload.h +++ b/src/hm/miPayload.h @@ -193,6 +193,8 @@ class MiPayload { record_t<> *rec = iv->getRecordStruct(InverterDevInform_All); // choose the record structure rec->ts = mPayload[iv->id].ts; mPayload[iv->id].gotFragment = true; + if(mHighPrioIv == NULL) // process next request immediately if possible + mHighPrioIv = iv; /* Polling the device software and hardware version number command @@ -219,12 +221,13 @@ case InverterDevInform_All: rec->assign = (byteAssign_t *)InfoAssignment; rec->pyldLen = HMINFO_PAYLOAD_LEN; break; + const byteAssign_t InfoAssignment[] = { { FLD_FW_VERSION, UNIT_NONE, CH0, 0, 2, 1 }, { FLD_FW_BUILD_YEAR, UNIT_NONE, CH0, 2, 2, 1 }, { FLD_FW_BUILD_MONTH_DAY, UNIT_NONE, CH0, 4, 2, 1 }, { FLD_FW_BUILD_HOUR_MINUTE, UNIT_NONE, CH0, 6, 2, 1 }, - { FLD_HW_ID, UNIT_NONE, CH0, 8, 2, 1 } + { FLD_BOOTLOADER_VER, UNIT_NONE, CH0, 8, 2, 1 } }; */ @@ -237,27 +240,48 @@ const byteAssign_t InfoAssignment[] = { mPayload[iv->id].gotFragment = true; if(mSerialDebug) { DPRINT_IVID(DBG_INFO, iv->id); - DPRINT(DBG_INFO,F("HW_VER is ")); - DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); + DPRINT(DBG_INFO,F("HW_VER is ")); + DBGPRINTLN(String((p->packet[24] << 8) + p->packet[25])); } + record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = mPayload[iv->id].ts; + iv->setValue(1, rec, (uint32_t) ((p->packet[24] << 8) + p->packet[25])/1); + //notify(InverterDevInform_All, iv); + //28737 } else if ( p->packet[9] == 0x01 || p->packet[9] == 0x10 ) {//second frame for MI, 3rd gen. answers in 0x10 DPRINT_IVID(DBG_INFO, iv->id); if ( p->packet[9] == 0x01 ) { DBGPRINTLN(F("got 2nd frame (hw info)")); - DPRINT(DBG_INFO,F("HW_PartNo ")); - DBGPRINTLN(String((uint32_t) (((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])); + /* according to xlsx (different start byte -1!) + byte[11] to byte[14] HW_PN + byte[15] byte[16] HW_FB_TLmValue + byte[17] byte[18] HW_FB_ReSPRT + byte[19] byte[20] HW_GridSamp_ResValule + byte[21] byte[22] HW_ECapValue + byte[23] to byte[26] Matching_APPFW_PN + */ + + DPRINT(DBG_INFO,F("HW_PartNo ")); + DBGPRINTLN(String((uint32_t) (((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])); mPayload[iv->id].gotFragment = true; - iv->setValue(iv->getPosByChFld(0, FLD_YT, rec), rec, (float) ((p->packet[20] << 8) + p->packet[21])/1); + record_t<> *rec = iv->getRecordStruct(InverterDevInform_Simple); // choose the record structure + rec->ts = mPayload[iv->id].ts; + iv->setValue(0, rec, (uint32_t) ((((p->packet[10] << 8) | p->packet[11]) << 8 | p->packet[12]) << 8 | p->packet[13])/1); + if(mSerialDebug) { - DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); - DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); - DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); - DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); - DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); - DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); + DPRINT(DBG_INFO,F("HW_FB_TLmValue ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + DPRINT(DBG_INFO,F("HW_FB_ReSPRT ")); + DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); + DPRINT(DBG_INFO,F("HW_GridSamp_ResValule ")); + DBGPRINTLN(String((p->packet[18] << 8) + p->packet[19])); DPRINT(DBG_INFO,F("HW_ECapValue ")); DBGPRINTLN(String((p->packet[20] << 8) + p->packet[21])); - } + DPRINT(DBG_INFO,F("Matching_APPFW_PN ")); + DBGPRINTLN(String((uint32_t) (((p->packet[22] << 8) | p->packet[23]) << 8 | p->packet[24]) << 8 | p->packet[25])); + } + //notify(InverterDevInform_Simple, iv); + notify(InverterDevInform_All, iv); } else { DBGPRINTLN(F("3rd gen. inverter!")); // see table in OpenDTU code, DevInfoParser.cpp devInfo[] } @@ -265,6 +289,22 @@ const byteAssign_t InfoAssignment[] = { } else if ( p->packet[9] == 0x12 ) {//3rd frame DPRINT_IVID(DBG_INFO, iv->id); DBGPRINTLN(F("got 3rd frame (hw info)")); + /* according to xlsx (different start byte -1!) + byte[11] byte[12] APPFW_MINVER + byte[13] byte[14] HWInfoAddr + byte[15] byte[16] PNInfoCRC_gusv + byte[15] byte[16] PNInfoCRC_gusv + */ + if(mSerialDebug) { + DPRINT(DBG_INFO,F("APPFW_MINVER ")); + DBGPRINTLN(String((p->packet[10] << 8) + p->packet[11])); + DPRINT(DBG_INFO,F("HWInfoAddr ")); + DBGPRINTLN(String((p->packet[12] << 8) + p->packet[13])); + DPRINT(DBG_INFO,F("PNInfoCRC_gusv ")); + DBGPRINTLN(String((p->packet[14] << 8) + p->packet[15])); + DPRINT(DBG_INFO,F("PNInfoCRC_gusv (pt. 2?) ")); + DBGPRINTLN(String((p->packet[16] << 8) + p->packet[17])); + } iv->setQueuedCmdFinished(); mPayload[iv->id].complete = true; mStat->rxSuccess++; @@ -697,7 +737,7 @@ const byteAssign_t InfoAssignment[] = { uint8_t txCmd = mPayload[id].txCmd; if(!*complete) { - DPRINTLN(DBG_VERBOSE, F("incomlete, txCmd is 0x") + String(txCmd, HEX)); + DPRINTLN(DBG_VERBOSE, F("incomplete, txCmd is 0x") + String(txCmd, HEX)); //DBGHEXLN(txCmd); if (txCmd == 0x09 || txCmd == 0x11 || (txCmd >= 0x36 && txCmd <= 0x39)) return false; @@ -728,8 +768,8 @@ const byteAssign_t InfoAssignment[] = { */ void reset(uint8_t id, bool clrSts = false) { - DPRINT_IVID(DBG_INFO, id); - DBGPRINTLN(F("resetPayload")); + //DPRINT_IVID(DBG_INFO, id); + //DBGPRINTLN(F("resetPayload")); memset(mPayload[id].len, 0, MAX_PAYLOAD_ENTRIES); mPayload[id].gotFragment = false; /*mPayload[id].maxPackId = MAX_PAYLOAD_ENTRIES; diff --git a/src/hms/hmsRadio.h b/src/hms/hmsRadio.h index dc79afcb..c515ae0e 100644 --- a/src/hms/hmsRadio.h +++ b/src/hms/hmsRadio.h @@ -25,7 +25,8 @@ class CmtRadio { typedef Cmt2300a CmtType; public: CmtRadio() { - mDtuSn = DTU_SN; + mDtuSn = DTU_SN; + mCmtAvail = false; } void setup(uint8_t pinCsb, uint8_t pinFcsb, bool genDtuSn = true) { @@ -63,6 +64,10 @@ class CmtRadio { mSerialDebug = true; } + bool cmtIsAvail() { + return mCmtAvail; + } + void sendControlPacket(const uint64_t *ivId, uint8_t cmd, uint16_t *data, bool isRetransmit) { DPRINT(DBG_INFO, F("sendControlPacket cmd: 0x")); DBGHEXLN(cmd); @@ -143,10 +148,14 @@ class CmtRadio { inline void reset(bool genDtuSn) { if(genDtuSn) generateDtuSn(); - if(!mCmt.reset()) + if(!mCmt.reset()) { + mCmtAvail = false; DPRINTLN(DBG_WARN, F("Initializing CMT2300A failed!")); - else + } + else { + mCmtAvail = true; mCmt.goRx(); + } mSendCnt = 0; mRetransmits = 0; @@ -208,6 +217,7 @@ class CmtRadio { bool mSerialDebug; bool mIrqRcvd; bool mRqstGetRx; + bool mCmtAvail; }; #endif /*__HMS_RADIO_H__*/ diff --git a/src/platformio.ini b/src/platformio.ini index 1e61dda1..42c1557a 100644 --- a/src/platformio.ini +++ b/src/platformio.ini @@ -127,8 +127,6 @@ monitor_filters = platform = espressif32@6.3.2 board = esp32-s3-devkitc-1 upload_protocol = esp-builtin -debug_tool = esp-builtin -debug_speed = 12000 build_flags = ${env.build_flags} -DDEF_NRF_CS_PIN=37 -DDEF_NRF_CE_PIN=38 @@ -142,5 +140,7 @@ build_flags = ${env.build_flags} -DDEF_LED0=18 -DDEF_LED1=17 -DLED_ACTIVE_HIGH + -DARDUINO_USB_MODE=1 + -DARDUINO_USB_CDC_ON_BOOT=1 monitor_filters = - esp32_exception_decoder + esp32_exception_decoder, colorize diff --git a/src/plugins/Display/Display.h b/src/plugins/Display/Display.h index 2340fd42..36a7df46 100644 --- a/src/plugins/Display/Display.h +++ b/src/plugins/Display/Display.h @@ -35,7 +35,7 @@ class Display { case 3: mMono = new DisplayMono84X48(); break; case 4: mMono = new DisplayMono128X32(); break; case 5: mMono = new DisplayMono64X48(); break; - + case 6: mMono = new DisplayMono128X64(); break; #if defined(ESP32) case 10: mMono = NULL; // ePaper does not use this @@ -59,13 +59,16 @@ class Display { void tickerSecond() { if (mMono != NULL) - mMono->loop(); + mMono->loop(mCfg->contrast); - if (mNewPayload || ((++mLoopCnt % 10) == 0)) { + if (mNewPayload || (((++mLoopCnt) % 30) == 0)) { mNewPayload = false; mLoopCnt = 0; DataScreen(); } + #if defined(ESP32) + mEpaper.tickerSecond(); + #endif } private: @@ -102,13 +105,10 @@ class Display { } #if defined(ESP32) else if (mCfg->type == 10) { - mEpaper.loop(totalPower, totalYieldDay, totalYieldTotal, isprod); mRefreshCycle++; } -#endif -#if defined(ESP32) if (mRefreshCycle > 480) { mEpaper.fullRefresh(); mRefreshCycle = 0; diff --git a/src/plugins/Display/Display_Mono.h b/src/plugins/Display/Display_Mono.h index 42eea5f3..4739f83f 100644 --- a/src/plugins/Display/Display_Mono.h +++ b/src/plugins/Display/Display_Mono.h @@ -23,7 +23,7 @@ class DisplayMono { virtual void init(uint8_t type, uint8_t rot, uint8_t cs, uint8_t dc, uint8_t reset, uint8_t clock, uint8_t data, uint32_t* utcTs, const char* version) = 0; virtual void config(bool enPowerSafe, bool enScreenSaver, uint8_t lum) = 0; - virtual void loop(void) = 0; + virtual void loop(uint8_t lum) = 0; virtual void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) = 0; protected: diff --git a/src/plugins/Display/Display_Mono_128X32.h b/src/plugins/Display/Display_Mono_128X32.h index e9e09d28..5a6d6c7e 100644 --- a/src/plugins/Display/Display_Mono_128X32.h +++ b/src/plugins/Display/Display_Mono_128X32.h @@ -46,11 +46,16 @@ class DisplayMono128X32 : public DisplayMono { mLuminance = lum; } - void loop(void) { + void loop(uint8_t lum) { if (mEnPowerSafe) { if (mTimeout != 0) mTimeout--; } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); + } } void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { diff --git a/src/plugins/Display/Display_Mono_128X64.h b/src/plugins/Display/Display_Mono_128X64.h index a828816c..438cb79e 100644 --- a/src/plugins/Display/Display_Mono_128X64.h +++ b/src/plugins/Display/Display_Mono_128X64.h @@ -27,10 +27,12 @@ class DisplayMono128X64 : public DisplayMono { case 1: mDisplay = new U8G2_SSD1306_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); break; - default: case 2: mDisplay = new U8G2_SH1106_128X64_NONAME_F_HW_I2C(rot, reset, clock, data); break; + case 6: + mDisplay = new U8G2_SSD1309_128X64_NONAME0_F_HW_I2C(rot, reset, clock, data); + break; } mUtcTs = utcTs; @@ -52,11 +54,16 @@ class DisplayMono128X64 : public DisplayMono { mLuminance = lum; } - void loop(void) { + void loop(uint8_t lum) { if (mEnPowerSafe) { if (mTimeout != 0) mTimeout--; } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); + } } void disp(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { diff --git a/src/plugins/Display/Display_Mono_64X48.h b/src/plugins/Display/Display_Mono_64X48.h index 8c355322..ae074c33 100644 --- a/src/plugins/Display/Display_Mono_64X48.h +++ b/src/plugins/Display/Display_Mono_64X48.h @@ -47,10 +47,15 @@ class DisplayMono64X48 : public DisplayMono { mLuminance = lum; } - void loop(void) { + void loop(uint8_t lum) { if (mEnPowerSafe) { if (mTimeout != 0) - mTimeout--; + mTimeout--; + } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); } } diff --git a/src/plugins/Display/Display_Mono_84X48.h b/src/plugins/Display/Display_Mono_84X48.h index aefe1372..fff983bc 100644 --- a/src/plugins/Display/Display_Mono_84X48.h +++ b/src/plugins/Display/Display_Mono_84X48.h @@ -47,10 +47,15 @@ class DisplayMono84X48 : public DisplayMono { mLuminance = lum; } - void loop(void) { + void loop(uint8_t lum) { if (mEnPowerSafe) { if (mTimeout != 0) - mTimeout--; + mTimeout--; + } + + if(mLuminance != lum) { + mLuminance = lum; + mDisplay->setContrast(mLuminance); } } diff --git a/src/plugins/Display/Display_ePaper.cpp b/src/plugins/Display/Display_ePaper.cpp index 8a72a485..9a4b594c 100644 --- a/src/plugins/Display/Display_ePaper.cpp +++ b/src/plugins/Display/Display_ePaper.cpp @@ -1,9 +1,9 @@ #include "Display_ePaper.h" #ifdef ESP8266 - #include +#include #elif defined(ESP32) - #include +#include #endif #include "../../utils/helper.h" #include "imagedata.h" @@ -26,6 +26,9 @@ DisplayEPaper::DisplayEPaper() { void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t *utcTs, const char *version) { mUtcTs = utcTs; + mRefreshState = RefreshStatus::LOGO; + mSecondCnt = 0; + if (type == 10) { Serial.begin(115200); _display = new GxEPD2_BW(GxEPD2_150_BN(_CS, _DC, _RST, _BUSY)); @@ -39,23 +42,7 @@ void DisplayEPaper::init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, u _display->init(115200, true, 20, false); _display->setRotation(mDisplayRotation); _display->setFullWindow(); - - // Logo - _display->fillScreen(GxEPD_BLACK); - _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); - while (_display->nextPage()) - ; - - // clean the screen - delay(2000); - _display->fillScreen(GxEPD_WHITE); - while (_display->nextPage()) - ; - - headlineIP(); - - // call the PowerPage to change the PV Power Values - actualPowerPaged(0, 0, 0, 0); + _version = version; } } @@ -66,15 +53,51 @@ void DisplayEPaper::config(uint8_t rotation, bool enPowerSafe) { //*************************************************************************** void DisplayEPaper::fullRefresh() { - // screen complete black - _display->fillScreen(GxEPD_BLACK); - while (_display->nextPage()) - ; - delay(2000); - // screen complete white - _display->fillScreen(GxEPD_WHITE); - while (_display->nextPage()) - ; + if(RefreshStatus::DONE != mRefreshState) + return; + mSecondCnt = 2; + mRefreshState = RefreshStatus::BLACK; +} + +//*************************************************************************** +void DisplayEPaper::refreshLoop() { + switch(mRefreshState) { + case RefreshStatus::LOGO: + _display->fillScreen(GxEPD_BLACK); + _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); + mNextRefreshState = RefreshStatus::PARTITIALS; + mRefreshState = RefreshStatus::WAIT; + break; + + case RefreshStatus::BLACK: + _display->fillScreen(GxEPD_BLACK); + mNextRefreshState = RefreshStatus::WHITE; + mRefreshState = RefreshStatus::WAIT; + break; + + case RefreshStatus::WHITE: + if(mSecondCnt == 0) { + _display->fillScreen(GxEPD_WHITE); + mNextRefreshState = RefreshStatus::PARTITIALS; + mRefreshState = RefreshStatus::WAIT; + } + break; + + case RefreshStatus::WAIT: + if(!_display->nextPage()) + mRefreshState = mNextRefreshState; + break; + + case RefreshStatus::PARTITIALS: + headlineIP(); + versionFooter(); + mSecondCnt = 4; // display Logo time during boot up + mRefreshState = RefreshStatus::DONE; + break; + + default: // RefreshStatus::DONE + break; + } } //*************************************************************************** void DisplayEPaper::headlineIP() { @@ -123,6 +146,26 @@ void DisplayEPaper::lastUpdatePaged() { } while (_display->nextPage()); } //*************************************************************************** +void DisplayEPaper::versionFooter() { + int16_t tbx, tby; + uint16_t tbw, tbh; + + _display->setFont(&FreeSans9pt7b); + _display->setTextColor(GxEPD_WHITE); + + _display->setPartialWindow(0, _display->height() - mHeadFootPadding, _display->width(), mHeadFootPadding); + _display->fillScreen(GxEPD_BLACK); + do { + snprintf(_fmtText, sizeof(_fmtText), "Version: %s", _version); + + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + uint16_t x = ((_display->width() - tbw) / 2) - tbx; + + _display->setCursor(x, (_display->height() - 3)); + _display->println(_fmtText); + } while (_display->nextPage()); +} +//*************************************************************************** void DisplayEPaper::offlineFooter() { int16_t tbx, tby; uint16_t tbw, tbh; @@ -154,18 +197,20 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa _display->setPartialWindow(0, mHeadFootPadding, _display->width(), _display->height() - (mHeadFootPadding * 2)); _display->fillScreen(GxEPD_WHITE); + do { + // actual Production if (totalPower > 9999) { - snprintf(_fmtText, sizeof(_fmtText), "%.1f kW", (totalPower / 10000)); + snprintf(_fmtText, sizeof(_fmtText), "%.1f kW", (totalPower / 1000)); _changed = true; } else if ((totalPower > 0) && (totalPower <= 9999)) { snprintf(_fmtText, sizeof(_fmtText), "%.0f W", totalPower); _changed = true; - } else { + } else snprintf(_fmtText, sizeof(_fmtText), "offline"); - } - if (totalPower == 0){ - _display->fillRect(0, mHeadFootPadding, 200,200, GxEPD_BLACK); + + if ((totalPower == 0) && (mEnPowerSafe)) { + _display->fillRect(0, mHeadFootPadding, 200, 200, GxEPD_BLACK); _display->drawBitmap(0, 0, logo, 200, 200, GxEPD_WHITE); } else { _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); @@ -173,42 +218,69 @@ void DisplayEPaper::actualPowerPaged(float totalPower, float totalYieldDay, floa _display->setCursor(x, mHeadFootPadding + tbh + 10); _display->print(_fmtText); + if ((totalYieldDay > 0) && (totalYieldTotal > 0)) { + // Today Production + bool kwh = (totalYieldDay > 9999); + if(kwh) + snprintf(_fmtText, _display->width(), "%.1f", (totalYieldDay / 1000)); + else + snprintf(_fmtText, _display->width(), "%.0f", (totalYieldDay)); + + _display->setFont(&FreeSans18pt7b); + y = _display->height() / 2; + _display->setCursor(5, y); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, ((kwh) ? (y - ((tbh + 30) / 2)) : (y - tbh)), myToday, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - ((kwh) ? 50 : 38), y); + _display->setFont(&FreeSans12pt7b); + _display->println((kwh) ? "kWh" : "Wh"); + y = y + tbh + 15; + + + // Total Production + bool mwh = (totalYieldTotal > 9999); + if(mwh) + snprintf(_fmtText, _display->width(), "%.1f", (totalYieldTotal / 1000)); + else + snprintf(_fmtText, _display->width(), "%.0f", (totalYieldTotal)); + + _display->setFont(&FreeSans18pt7b); + _display->setCursor(5, y); + _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); + _display->drawInvertedBitmap(5, y - tbh, mySigma, 30, 30, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; + _display->setCursor(x, y); + _display->print(_fmtText); + _display->setCursor(_display->width() - ((mwh) ? 59 : 50), y); + _display->setFont(&FreeSans12pt7b); + _display->println((mwh) ? "MWh" : "kWh"); + } + + // Inverter online _display->setFont(&FreeSans12pt7b); - y = _display->height() / 2; - _display->setCursor(5, y); - _display->print("today:"); - snprintf(_fmtText, _display->width(), "%.0f", totalYieldDay); + y = _display->height() - (mHeadFootPadding + 10); + snprintf(_fmtText, sizeof(_fmtText), " %d online", isprod); _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; + _display->drawInvertedBitmap(10, y - tbh, myWR, 20, 20, GxEPD_BLACK); + x = ((_display->width() - tbw - 20) / 2) - tbx; _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 38, y); - _display->println("Wh"); - - y = y + tbh + 7; - _display->setCursor(5, y); - _display->print("total:"); - snprintf(_fmtText, _display->width(), "%.1f", totalYieldTotal); - _display->getTextBounds(_fmtText, 0, 0, &tbx, &tby, &tbw, &tbh); - x = ((_display->width() - tbw) / 2) - tbx; - _display->setCursor(x, y); - _display->print(_fmtText); - _display->setCursor(_display->width() - 50, y); - _display->println("kWh"); - - _display->setCursor(10, _display->height() - (mHeadFootPadding + 10)); - snprintf(_fmtText, sizeof(_fmtText), "%d Inverter online", isprod); _display->println(_fmtText); - } + yield(); } while (_display->nextPage()); } //*************************************************************************** void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod) { + if(RefreshStatus::DONE != mRefreshState) + return; + // check if the IP has changed - if (_settedIP != WiFi.localIP().toString().c_str()) { + if (_settedIP != WiFi.localIP().toString()) { // save the new IP and call the Headline Function to adapt the Headline - _settedIP = WiFi.localIP().toString().c_str(); + _settedIP = WiFi.localIP().toString(); headlineIP(); } @@ -219,10 +291,16 @@ void DisplayEPaper::loop(float totalPower, float totalYieldDay, float totalYield if ((isprod > 0) && (_changed)) { _changed = false; lastUpdatePaged(); - } else if((0 == totalPower) && (mEnPowerSafe)) + } else if ((0 == totalPower) && (mEnPowerSafe)) offlineFooter(); _display->powerOff(); } + //*************************************************************************** -#endif // ESP32 +void DisplayEPaper::tickerSecond() { + if(mSecondCnt != 0) + mSecondCnt--; + refreshLoop(); +} +#endif // ESP32 diff --git a/src/plugins/Display/Display_ePaper.h b/src/plugins/Display/Display_ePaper.h index d9b24e34..2ff7e58d 100644 --- a/src/plugins/Display/Display_ePaper.h +++ b/src/plugins/Display/Display_ePaper.h @@ -24,28 +24,42 @@ // GDEH0154D67 1.54" b/w 200x200 class DisplayEPaper { - public: - DisplayEPaper(); - void fullRefresh(); - void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t *utcTs, const char* version); - void config(uint8_t rotation, bool enPowerSafe); - void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); - - - private: - void headlineIP(); - void actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod); - void lastUpdatePaged(); - void offlineFooter(); - - uint8_t mDisplayRotation; - bool _changed = false; - char _fmtText[35]; - const char* _settedIP; - uint8_t mHeadFootPadding; - GxEPD2_GFX* _display; - uint32_t *mUtcTs; - bool mEnPowerSafe; + public: + DisplayEPaper(); + void fullRefresh(); + void init(uint8_t type, uint8_t _CS, uint8_t _DC, uint8_t _RST, uint8_t _BUSY, uint8_t _SCK, uint8_t _MOSI, uint32_t* utcTs, const char* version); + void config(uint8_t rotation, bool enPowerSafe); + void loop(float totalPower, float totalYieldDay, float totalYieldTotal, uint8_t isprod); + void refreshLoop(); + void tickerSecond(); + + private: + void headlineIP(); + void actualPowerPaged(float _totalPower, float _totalYieldDay, float _totalYieldTotal, uint8_t _isprod); + void lastUpdatePaged(); + void offlineFooter(); + void versionFooter(); + + enum class RefreshStatus : uint8_t { + DONE, + BLACK, + WHITE, + WAIT, + PARTITIALS, + LOGO + }; + + uint8_t mDisplayRotation; + bool _changed = false; + char _fmtText[35]; + String _settedIP; + uint8_t mHeadFootPadding; + GxEPD2_GFX* _display; + uint32_t* mUtcTs; + bool mEnPowerSafe; + const char* _version; + RefreshStatus mRefreshState, mNextRefreshState; + uint8_t mSecondCnt; }; -#endif // ESP32 +#endif // ESP32 diff --git a/src/plugins/Display/imagedata.h b/src/plugins/Display/imagedata.h index baaddec8..b136193b 100644 --- a/src/plugins/Display/imagedata.h +++ b/src/plugins/Display/imagedata.h @@ -9,6 +9,47 @@ #include #endif +// 'Sigma', 30x30px +const unsigned char mySigma[] PROGMEM = { + 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x3f, 0x80, 0x07, 0xf0, 0x3f, 0x80, 0x07, 0xf0, 0x3f, 0x9f, 0xe7, 0xf0, 0x3f, 0xcf, 0xe7, 0xf0, + 0x3f, 0xcf, 0xff, 0xf0, 0x3f, 0xe7, 0xff, 0xf0, 0x3f, 0xe7, 0xff, 0xf0, 0x3f, 0xf3, 0xff, 0xf0, + 0x3f, 0xf3, 0xff, 0xf0, 0x3f, 0xf9, 0xff, 0xf0, 0x3f, 0xf8, 0xff, 0xf0, 0x3f, 0xf8, 0xff, 0xf0, + 0x3f, 0xf9, 0xff, 0xf0, 0x3f, 0xf3, 0xff, 0xf0, 0x3f, 0xf3, 0xff, 0xf0, 0x3f, 0xe7, 0xff, 0xf0, + 0x3f, 0xe7, 0xff, 0xf0, 0x3f, 0xcf, 0xff, 0xf0, 0x3f, 0xcf, 0xe7, 0xf0, 0x3f, 0x9f, 0xe7, 0xf0, + 0x3f, 0x80, 0x07, 0xf0, 0x3f, 0x80, 0x07, 0xf0, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04 +}; +// 'Sun', 30x30px +const unsigned char mySun[] PROGMEM = { + 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xfb, 0xf0, + 0x3f, 0xfc, 0xfb, 0xf0, 0x3f, 0xfc, 0xfb, 0xf0, 0x3e, 0xfc, 0xf3, 0xf0, 0x3c, 0x7c, 0xf3, 0xf0, + 0x3e, 0x30, 0x33, 0xf0, 0x3f, 0x0f, 0xcb, 0xf0, 0x3f, 0x9f, 0xeb, 0xf0, 0x3f, 0xbf, 0xeb, 0xf0, + 0x3f, 0x7f, 0xd8, 0x30, 0x3f, 0x7f, 0xdf, 0xb0, 0x30, 0x7f, 0xdf, 0xb0, 0x30, 0x7f, 0xbf, 0x70, + 0x3f, 0x7f, 0xbf, 0x70, 0x3f, 0x7f, 0x83, 0x70, 0x3f, 0xbf, 0xf2, 0xf0, 0x3f, 0x9f, 0xe2, 0xf0, + 0x3f, 0x0f, 0xca, 0xf0, 0x3e, 0x30, 0x39, 0xf0, 0x3c, 0x7c, 0xf9, 0xf0, 0x3e, 0xfc, 0xf9, 0xf0, + 0x3f, 0xfc, 0xfb, 0xf0, 0x3f, 0xfc, 0xfb, 0xf0, 0x3f, 0xff, 0xfb, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04 +}; +// 'Today', 30x30px +const unsigned char myToday[] PROGMEM = { + 0xf3, 0xff, 0xff, 0x3c, 0xf3, 0xff, 0xff, 0x3c, 0x80, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, + 0x33, 0xff, 0xff, 0x30, 0x33, 0xff, 0xff, 0x30, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x3f, 0xff, 0xff, 0xf0, 0x3f, 0xff, 0xfc, 0xf0, 0x3f, 0xff, 0xf8, 0xf0, 0x3f, 0xff, 0xf1, 0xf0, + 0x3f, 0xff, 0xe3, 0xf0, 0x3f, 0xff, 0xc7, 0xf0, 0x3f, 0xff, 0x8f, 0xf0, 0x3f, 0xff, 0x1f, 0xf0, + 0x3f, 0xfe, 0x3f, 0xf0, 0x3e, 0x7c, 0x7f, 0xf0, 0x3e, 0x38, 0xff, 0xf0, 0x3f, 0x11, 0xff, 0xf0, + 0x3f, 0x83, 0xff, 0xf0, 0x3f, 0xc7, 0xff, 0xf0, 0x3f, 0xef, 0xff, 0xf0, 0x3f, 0xff, 0xff, 0xf0, + 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x04 +}; +// 'WR', 20x20px +const unsigned char myWR[] PROGMEM = { + 0x80, 0x00, 0x10, 0x00, 0x00, 0x00, 0x3f, 0xff, 0x80, 0x3f, 0xff, 0x40, 0x30, 0x7e, 0xc0, 0x3f, + 0xfd, 0xc0, 0x30, 0x7b, 0xc0, 0x3f, 0xf7, 0xc0, 0x3f, 0xef, 0xc0, 0x3f, 0xdf, 0xc0, 0x3f, 0xbf, + 0xc0, 0x3f, 0x7f, 0xc0, 0x3e, 0xff, 0xc0, 0x3d, 0xf7, 0xc0, 0x3b, 0xea, 0xc0, 0x37, 0xfd, 0xc0, + 0x2f, 0xff, 0xc0, 0x1f, 0xff, 0xc0, 0x00, 0x00, 0x00, 0x80, 0x00, 0x10 +}; + // 'Logo', 200x200px const unsigned char logo[] PROGMEM = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, diff --git a/src/web/RestApi.h b/src/web/RestApi.h index eb313c3c..7c3debe9 100644 --- a/src/web/RestApi.h +++ b/src/web/RestApi.h @@ -224,7 +224,7 @@ class RestApi { #endif /* !defined(ETHERNET) */ obj[F("device_name")] = mConfig->sys.deviceName; obj[F("dark_mode")] = (bool)mConfig->sys.darkMode; - obj[F("sched_reboot")] = (bool)mConfig->sys.schedReboot; + obj[F("sched_reboot")] = (bool)mConfig->sys.schedReboot; obj[F("mac")] = WiFi.macAddress(); obj[F("hostname")] = mConfig->sys.deviceName; diff --git a/src/web/html/colorBright.css b/src/web/html/colorBright.css index 255b5130..47382daa 100644 --- a/src/web/html/colorBright.css +++ b/src/web/html/colorBright.css @@ -8,6 +8,7 @@ --success: #009900; --input-bg: #eee; + --table-border: #ccc; --nav-bg: #333; --primary: #006ec0; diff --git a/src/web/html/colorDark.css b/src/web/html/colorDark.css index d143f8be..3d9d167a 100644 --- a/src/web/html/colorDark.css +++ b/src/web/html/colorDark.css @@ -8,6 +8,7 @@ --success: #00bb00; --input-bg: #333; + --table-border: #333; --nav-bg: #333; --primary: #004d87; diff --git a/src/web/html/setup.html b/src/web/html/setup.html index e33f4710..995dd37d 100644 --- a/src/web/html/setup.html +++ b/src/web/html/setup.html @@ -869,7 +869,7 @@ } // 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"], [3, "Nokia5110"]]; + 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"]]; if("ESP32" == type) opts.push([10, "ePaper"]); var dispType = sel("disp_typ", opts, obj["disp_typ"]); diff --git a/src/web/html/style.css b/src/web/html/style.css index 4d4dc6f8..6d19bd21 100644 --- a/src/web/html/style.css +++ b/src/web/html/style.css @@ -329,7 +329,7 @@ th { .table td, .table th { padding: .75rem; - border-bottom: 1px solid var(--nav-bg); + border-bottom: 1px solid var(--table-border); } #wrapper { @@ -737,3 +737,30 @@ h5 { .pointer { cursor: pointer; } + +.badge-success { + color: #fff; + background-color: #28a745; +} + +.badge-warning { + color: #212529; + background-color: #ffc107; +} + +.badge-error { + color: #fff; + background-color: #dc3545; +} + +.badge { + display: inline-block; + padding: .25em .4em; + font-size: 75%; + font-weight: 700; + line-height: 1; + text-align: center; + white-space: nowrap; + vertical-align: baseline; + border-radius: .25rem; +} diff --git a/src/web/html/system.html b/src/web/html/system.html index d51c01cc..c504057f 100644 --- a/src/web/html/system.html +++ b/src/web/html/system.html @@ -49,33 +49,47 @@ } } + function badge(success, text) { + return ml("span", {class: "badge badge-" + ((success) ? "success" : "error")}, text); + } + + function headline(text) { + return ml("div", {class: "head p-2 mt-3"}, ml("div", {class: "row"}, ml("div", {class: "col a-c"}, text))) + } + + function tr(val1, val2) { + if(typeof val2 == "number") + val2 = String(val2); + return ml("tr", {}, [ + ml("th", {}, val1), + ml("td", {}, val2) + ]); + } + function parseRadio(obj, stat) { const pa = ["MIN (recommended)", "LOW", "HIGH", "MAX"]; const datarate = ["1 MBps", "2 MBps", "250 kbps"]; - var main = document.getElementById("radio"); - var h = div(["head", "p-2"]); - var r = div(["row"]); - r.appendChild(div(["col", "a-c"], "Radio")); - h.appendChild(r); - main.appendChild(h); - - main.appendChild( - genTabRow("nrf24l01" + (obj["isPVariant"] ? "+ " : ""), (obj["isconnected"] ? "is connected " : "is not connected ")) - ); - - if(obj["isconnected"]) { - main.appendChild(genTabRow("Datarate", datarate[obj["DataRate"]])); - main.appendChild(genTabRow("Power Level", pa[obj["power_level"]])); - } + document.getElementById("radio").append( + headline("NRF Radio"), + ml("table", {class: "table"}, [ + ml("tbody", {}, [ + tr("NRF24L01", badge(obj.isconnected, ((obj.isconnected) ? "" : "not ") + "connected")), + tr("Power Level", pa[obj.power_level]) + ]) + ]), - main.append( - genTabRow("TX count", stat["tx_cnt"]), - genTabRow("RX success", stat["rx_success"]), - genTabRow("RX fail", stat["rx_fail"]), - genTabRow("RX no answer", stat["rx_fail_answer"]), - genTabRow("RX fragments", stat["frame_cnt"]), - genTabRow("TX retransmits", stat["retransmits"]) + headline("Statistics"), + ml("table", {class: "table"}, [ + ml("tbody", {}, [ + tr("TX count", stat.tx_cnt), + tr("RX success", stat.rx_success), + tr("RX fail", stat.rx_fail), + tr("RX no answer", stat.rx_fail_answer), + tr("RX fragments", stat.frame_cnt), + tr("TX retransmits", stat.retransmits) + ]) + ]) ); }