From 44cb8d35ce5dedf2c0bfbd8de055b2b599ffbe13 Mon Sep 17 00:00:00 2001 From: Thomas Hooge <thomas@hoogi.de> Date: Wed, 22 Jan 2025 12:07:00 +0100 Subject: [PATCH 01/17] Improved page refresh possibilities and page white --- lib/obp60task/PageWhite.cpp | 12 ++++++++++-- lib/obp60task/Pagedata.h | 1 + lib/obp60task/obp60task.cpp | 17 +++++++++++++---- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/lib/obp60task/PageWhite.cpp b/lib/obp60task/PageWhite.cpp index a2b6737..e40a3ac 100644 --- a/lib/obp60task/PageWhite.cpp +++ b/lib/obp60task/PageWhite.cpp @@ -13,6 +13,7 @@ public: PageWhite(CommonData &common){ commonData = &common; common.logger->logDebug(GwLog::LOG,"Instantiate PageWhite"); + refreshtime = 15000; } virtual int handleKey(int key) { @@ -53,7 +54,11 @@ public: int bgcolor = GxEPD_WHITE; // Set display in partial refresh mode - getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update + if (mode == 'W') { + getdisplay().setFullWindow(); + } else { + getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update + } if (mode == 'L') { getdisplay().drawBitmap(0, 0, gImage_Logo_OBP_400x300_sw, getdisplay().width(), getdisplay().height(), commonData->fgcolor); @@ -62,7 +67,10 @@ public: } // Update display - getdisplay().nextPage(); // Partial update (fast) + getdisplay().nextPage(); + if (mode == 'W') { + getdisplay().hibernate(); + } }; }; diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h index cc4c45b..b385b5c 100644 --- a/lib/obp60task/Pagedata.h +++ b/lib/obp60task/Pagedata.h @@ -100,6 +100,7 @@ class Page{ protected: CommonData *commonData; public: + int refreshtime = 1000; virtual void displayPage(PageData &pageData)=0; virtual void displayNew(PageData &pageData){} virtual void setupKeys() { diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 662942e..e56aaaf 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -550,8 +550,10 @@ void OBP60Task(GwApi *api){ //#################################################################################### bool systemPage = false; + Page *currentPage; while (true){ delay(100); // Delay 100ms (loop time) + bool keypressed = false; // Undervoltage detection if(uvoltage == true){ @@ -593,8 +595,8 @@ void OBP60Task(GwApi *api){ int keyboardMessage=0; while (xQueueReceive(allParameters.queue,&keyboardMessage,0)){ LOG_DEBUG(GwLog::LOG,"new key from keyboard %d",keyboardMessage); + keypressed = true; - Page *currentPage; if (keyboardMessage == 12) { LOG_DEBUG(GwLog::LOG, "Calling system page"); systemPage = true; // System page is out of band @@ -725,9 +727,17 @@ void OBP60Task(GwApi *api){ } } - // Refresh display data all 1s - if(millis() > starttime3 + 1000){ + // Refresh display data, default all 1s + currentPage = pages[pageNumber].page; + int pagetime = 1000; + if ((lastPage == pageNumber) and (!keypressed)) { + // same page we use page defined time + pagetime = currentPage->refreshtime; + } + if(millis() > starttime3 + pagetime){ + LOG_DEBUG(GwLog::DEBUG,"Page with refreshtime=%d", pagetime); starttime3 = millis(); + //refresh data from api api->getBoatDataValues(boatValues.numValues,boatValues.allBoatValues); api->getStatus(commonData.status); @@ -749,7 +759,6 @@ void OBP60Task(GwApi *api){ syspage->displayPage(sysparams); } else { - Page *currentPage = pages[pageNumber].page; if (currentPage == NULL){ LOG_DEBUG(GwLog::ERROR,"page number %d not found", pageNumber); // Error handling for missing page From a42d31ff49744d1a7b02a7b8801f907e88bc5d88 Mon Sep 17 00:00:00 2001 From: Thomas Hooge <thomas@hoogi.de> Date: Wed, 22 Jan 2025 20:14:55 +0100 Subject: [PATCH 02/17] System page inprovements, e.g. soft reset --- lib/obp60task/PageSystem.cpp | 32 +++++++++++++++++++++++++------- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/lib/obp60task/PageSystem.cpp b/lib/obp60task/PageSystem.cpp index 7beb13d..58d3788 100644 --- a/lib/obp60task/PageSystem.cpp +++ b/lib/obp60task/PageSystem.cpp @@ -48,7 +48,7 @@ public: commonData->keydata[0].label = "EXIT"; commonData->keydata[1].label = "MODE"; commonData->keydata[2].label = ""; - commonData->keydata[3].label = ""; + commonData->keydata[3].label = "RST"; commonData->keydata[4].label = "STBY"; commonData->keydata[5].label = "ILUM"; } @@ -67,9 +67,13 @@ public: return 0; } // grab cursor keys to disable page navigation - if (key == 3 or key == 4) { + if (key == 3) { return 0; } + // soft reset + if (key == 4) { + ESP.restart(); + } // Code for keylock if (key == 11) { commonData->keylock = !commonData->keylock; @@ -133,11 +137,25 @@ public: getdisplay().setCursor(120, y0 + 16); getdisplay().print(env_module); + // total RAM free + int Heap_free = esp_get_free_heap_size(); + getdisplay().setCursor(202, y0 + 16); + getdisplay().print("Total free:"); + getdisplay().setCursor(300, y0 + 16); + getdisplay().print(String(Heap_free)); + getdisplay().setCursor(2, y0 + 32); getdisplay().print("Buzzer:"); getdisplay().setCursor(120, y0 + 32); getdisplay().print(buzzer_mode); + // RAM free for task + int RAM_free = uxTaskGetStackHighWaterMark(NULL); + getdisplay().setCursor(202, y0 + 32); + getdisplay().print("Task free:"); + getdisplay().setCursor(300, y0 + 32); + getdisplay().print(String(RAM_free)); + getdisplay().setCursor(2, y0 + 48); getdisplay().print("CPU speed:"); getdisplay().setCursor(120, y0 + 48); @@ -146,11 +164,6 @@ public: int cpu_freq = esp_clk_cpu_freq() / 1000000; getdisplay().print(String(cpu_freq)); - getdisplay().setCursor(2, y0 + 64); - getdisplay().print("RTC:"); - getdisplay().setCursor(120, y0 + 64); - getdisplay().print(rtc_module); - getdisplay().setCursor(202, y0 + 64); getdisplay().print("GPS:"); getdisplay().setCursor(300, y0 + 64); @@ -161,6 +174,11 @@ public: getdisplay().setCursor(120, y0 + 80); getdisplay().print(hasFRAM ? "available" : "not found"); + getdisplay().setCursor(202, y0 + 80); + getdisplay().print("RTC:"); + getdisplay().setCursor(300, y0 + 80); + getdisplay().print(rtc_module); + getdisplay().setCursor(2, y0 + 120); getdisplay().print("Firmware Version: "); getdisplay().print(VERSINFO); From 1ff0de5d2483863e58c858810d9c51c11aff6499 Mon Sep 17 00:00:00 2001 From: Thomas Hooge <thomas@hoogi.de> Date: Thu, 23 Jan 2025 19:49:44 +0100 Subject: [PATCH 03/17] Deep sleep for OBP60 and small fix for BMP180 --- lib/obp60task/OBP60Extensions.cpp | 32 +++++++++++++++++++++++++++++++ lib/obp60task/OBP60Extensions.h | 6 ++++++ lib/obp60task/PageBME280.cpp | 6 +++--- lib/obp60task/PageSystem.cpp | 4 ++++ lib/obp60task/obp60task.cpp | 24 +++++++++++++++++++++++ 5 files changed, 69 insertions(+), 3 deletions(-) diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 8c4ec27..a98cba5 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -70,6 +70,9 @@ bool statusBacklightLED = false;// Actual status of flash LED on/off int uvDuration = 0; // Under voltage duration in n x 100ms +RTC_DATA_ATTR uint8_t RTC_lastpage; // Remember last page while deep sleeping + + LedTaskData *ledTaskData=nullptr; void hardwareInit(GwApi *api) @@ -118,6 +121,35 @@ void startLedTask(GwApi *api){ createSpiLedTask(ledTaskData); } +uint8_t getLastPage() { + return RTC_lastpage; +} + +#ifdef BOARD_OBP60S3 +void deepSleep(CommonData &common){ + RTC_lastpage = common.data.actpage - 1; + // Switch off all power lines + setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off + setFlashLED(false); // Flash LED Off + buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms + // Shutdown EInk display + getdisplay().setFullWindow(); // Set full Refresh + getdisplay().fillScreen(common.bgcolor); // Clear screen + getdisplay().setTextColor(common.fgcolor); + getdisplay().setFont(&Ubuntu_Bold20pt7b); + getdisplay().setCursor(85, 150); + getdisplay().print("Sleep Mode"); + getdisplay().setFont(&Ubuntu_Bold8pt7b); + getdisplay().setCursor(65, 175); + getdisplay().print("For wakeup press key and wait 5s"); + getdisplay().nextPage(); // Update display contents + getdisplay().powerOff(); // Display power off + setPortPin(OBP_POWER_50, false); // Power off ePaper display + // Stop system + esp_deep_sleep_start(); // Deep Sleep with weakup via GPIO pin +} +#endif + // Valid colors see hue Color colorMapping(const String &colorString){ Color color = COLOR_RED; diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h index fa80cc9..727f912 100644 --- a/lib/obp60task/OBP60Extensions.h +++ b/lib/obp60task/OBP60Extensions.h @@ -64,6 +64,12 @@ Point rotatePoint(const Point& origin, const Point& p, double angle); std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle); void fillPoly4(const std::vector<Point>& p4, uint16_t color); +#ifdef BOARD_OBP60S3 +void deepSleep(CommonData &common); +#endif + +uint8_t getLastPage(); + void hardwareInit(GwApi *api); void setPortPin(uint pin, bool value); // Set port pin for extension port diff --git a/lib/obp60task/PageBME280.cpp b/lib/obp60task/PageBME280.cpp index d731005..9bf0df2 100644 --- a/lib/obp60task/PageBME280.cpp +++ b/lib/obp60task/PageBME280.cpp @@ -48,7 +48,7 @@ class PageBME280 : public Page value1 = 23.0 + float(random(0, 10)) / 10.0; } // Display data when sensor activated - if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){ + if((useenvsensor == "BME280") or (useenvsensor == "BMP280") or (useenvsensor == "BMP180")){ svalue1 = String(value1, 1); // Formatted value as string including unit conversion and switching decimal places } else{ @@ -66,7 +66,7 @@ class PageBME280 : public Page value2 = 43 + float(random(0, 4)); } // Display data when sensor activated - if(String(useenvsensor) == "BME280"){ + if(useenvsensor == "BME280"){ svalue2 = String(value2, 0); // Formatted value as string including unit conversion and switching decimal places } else{ @@ -84,7 +84,7 @@ class PageBME280 : public Page value3 = 1006 + float(random(0, 5)); } // Display data when sensor activated - if((String(useenvsensor) == "BME280") or (String(useenvsensor) == "BMP280")){ + if((useenvsensor == "BME280") or (useenvsensor == "BMP280") or (useenvsensor == "BMP180")){ svalue3 = String(value3 / 100, 1); // Formatted value as string including unit conversion and switching decimal places } else{ diff --git a/lib/obp60task/PageSystem.cpp b/lib/obp60task/PageSystem.cpp index 58d3788..64b08d7 100644 --- a/lib/obp60task/PageSystem.cpp +++ b/lib/obp60task/PageSystem.cpp @@ -74,6 +74,10 @@ public: if (key == 4) { ESP.restart(); } + // standby / deep sleep + if (key == 5) { + deepSleep(*commonData); + } // Code for keylock if (key == 11) { commonData->keylock = !commonData->keylock; diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 662942e..8678402 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -117,6 +117,16 @@ void OBP60Init(GwApi *api){ } #endif + #ifdef BOARD_OBP60S3 + touchSleepWakeUpEnable(TP1, 45); + touchSleepWakeUpEnable(TP2, 45); + touchSleepWakeUpEnable(TP3, 45); + touchSleepWakeUpEnable(TP4, 45); + touchSleepWakeUpEnable(TP5, 45); + touchSleepWakeUpEnable(TP6, 45); + esp_sleep_enable_touchpad_wakeup(); + #endif + // Get CPU speed int freq = getCpuFrequencyMhz(); api->getLogger()->logDebug(GwLog::LOG,"CPU speed at boot: %i MHz", freq); @@ -356,6 +366,8 @@ void deepSleep(CommonData &common){ } #endif + + // OBP60 Task //#################################################################################### void OBP60Task(GwApi *api){ @@ -440,6 +452,18 @@ void OBP60Task(GwApi *api){ PageStruct pages[MAX_PAGE_NUMBER]; // Set start page int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1; + +#ifdef BOARD_OBP60S3 + LOG_DEBUG(GwLog::LOG,"Checking wakeup..."); + if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TOUCHPAD) { + LOG_DEBUG(GwLog::LOG,"Wake up by touch pad %d",esp_sleep_get_touchpad_wakeup_status()); + pageNumber = getLastPage(); + } else { + LOG_DEBUG(GwLog::LOG,"Other wakeup reason"); + } + LOG_DEBUG(GwLog::LOG,"...done"); +#endif + int lastPage=pageNumber; BoatValueList boatValues; //all the boat values for the api query From 78b5861da42169f10724fc6920f85dabc4a93ac5 Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Thu, 23 Jan 2025 22:55:35 +0100 Subject: [PATCH 04/17] Typo --- lib/obp60task/obp60task.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 662942e..b2cbe2e 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -9,7 +9,7 @@ #include <NMEA0183.h> // NMEA0183 #include <NMEA0183Msg.h> #include <NMEA0183Messages.h> -#include <GxEPD2_BW.h> // GxEPD2 lib for black 6 white E-Ink displays +#include <GxEPD2_BW.h> // GxEPD2 lib for b/w E-Ink displays #include "OBP60Extensions.h" // Functions lib for extension board #include "OBP60Keypad.h" // Functions for keypad From 46af8916e7ebd2e1a1b3ac4fb465ec70338d990c Mon Sep 17 00:00:00 2001 From: Thomas Hooge <thomas@hoogi.de> Date: Fri, 24 Jan 2025 08:06:26 +0100 Subject: [PATCH 05/17] Fix for OBP40 in page system and deepSleep --- lib/obp60task/PageSystem.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/obp60task/PageSystem.cpp b/lib/obp60task/PageSystem.cpp index 64b08d7..e56d94b 100644 --- a/lib/obp60task/PageSystem.cpp +++ b/lib/obp60task/PageSystem.cpp @@ -74,10 +74,12 @@ public: if (key == 4) { ESP.restart(); } +#ifdef BOARD_OBP60S3 // standby / deep sleep if (key == 5) { deepSleep(*commonData); } +#endif // Code for keylock if (key == 11) { commonData->keylock = !commonData->keylock; From 28e4fc0643336b33df3c9ef1c060877663c6ecc7 Mon Sep 17 00:00:00 2001 From: free-x <oroitburd@gmail.com> Date: Fri, 24 Jan 2025 12:22:26 +0100 Subject: [PATCH 06/17] extend CI for OBP boards --- lib/obp60task/platformio.ini | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini index da78f39..16f3269 100644 --- a/lib/obp60task/platformio.ini +++ b/lib/obp60task/platformio.ini @@ -2,7 +2,9 @@ #if you want a pio run to only build #your special environments you can set this here #by uncommenting the next line -default_envs = obp60_s3 +default_envs = + obp60_s3 + obp40_s3 [env:obp60_s3] platform = espressif32@6.8.1 From 1174622b4a95285fff8f425480752287c38f5332 Mon Sep 17 00:00:00 2001 From: Thomas Hooge <thomas@hoogi.de> Date: Fri, 24 Jan 2025 12:42:07 +0100 Subject: [PATCH 07/17] System page for OBP40 and deep sleep improvements --- lib/obp60task/OBP60Extensions.cpp | 26 +++++++ lib/obp60task/OBP60Extensions.h | 2 - lib/obp60task/OBP60Keypad.h | 10 ++- lib/obp60task/PageSystem.cpp | 109 +++++++++++++++++++++--------- lib/obp60task/config_obp40.json | 11 +++ lib/obp60task/obp60task.cpp | 61 +++++++---------- 6 files changed, 144 insertions(+), 75 deletions(-) diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index a98cba5..9f7df24 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -146,6 +146,32 @@ void deepSleep(CommonData &common){ getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_50, false); // Power off ePaper display // Stop system + esp_deep_sleep_start(); // Deep Sleep with weakup via touch pin +} +#endif +#ifdef BOARD_OBP40S3 +// Deep sleep funktion +void deepSleep(CommonData &common){ + RTC_lastpage = common.data.actpage - 1; + // Switch off all power lines + setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off + setFlashLED(false); // Flash LED Off + // Shutdown EInk display + getdisplay().setFullWindow(); // Set full Refresh + //getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update + getdisplay().fillScreen(common.bgcolor); // Clear screen + getdisplay().setTextColor(common.fgcolor); + getdisplay().setFont(&Ubuntu_Bold20pt7b); + getdisplay().setCursor(85, 150); + getdisplay().print("Sleep Mode"); + getdisplay().setFont(&Ubuntu_Bold8pt7b); + getdisplay().setCursor(65, 175); + getdisplay().print("For wakeup press wheel and wait 5s"); + getdisplay().nextPage(); // Partial update + getdisplay().powerOff(); // Display power off + setPortPin(OBP_POWER_EPD, false); // Power off ePaper display + setPortPin(OBP_POWER_SD, false); // Power off SD card + // Stop system esp_deep_sleep_start(); // Deep Sleep with weakup via GPIO pin } #endif diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h index 727f912..b6f653f 100644 --- a/lib/obp60task/OBP60Extensions.h +++ b/lib/obp60task/OBP60Extensions.h @@ -64,9 +64,7 @@ Point rotatePoint(const Point& origin, const Point& p, double angle); std::vector<Point> rotatePoints(const Point& origin, const std::vector<Point>& pts, double angle); void fillPoly4(const std::vector<Point>& p4, uint16_t color); -#ifdef BOARD_OBP60S3 void deepSleep(CommonData &common); -#endif uint8_t getLastPage(); diff --git a/lib/obp60task/OBP60Keypad.h b/lib/obp60task/OBP60Keypad.h index 122355c..937f44e 100644 --- a/lib/obp60task/OBP60Keypad.h +++ b/lib/obp60task/OBP60Keypad.h @@ -60,7 +60,7 @@ void initKeys(CommonData &commonData) { #ifdef HARDWARE_V21 // Keypad functions for original OBP60 hardware - int readKeypad(GwLog* logger, uint thSensitivity) { + int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) { // Touch sensor values // 35000 - Not touched @@ -261,7 +261,7 @@ void initKeys(CommonData &commonData) { } // Keypad functions for OBP60 clone (thSensitivity is inactiv) - int readKeypad(GwLog* logger, uint thSensitivity) { + int readKeypad(GwLog* logger, uint thSensitivity, bool use_syspage) { pinMode(UP, INPUT); pinMode(DOWN, INPUT); pinMode(CONF, INPUT); @@ -279,7 +279,11 @@ void initKeys(CommonData &commonData) { } // If key pressed longer than 200ms if(millis() > starttime + 200 && keycode == keycodeold) { - keystatus = keycode; + if (use_syspage and keycode == 3) { + keystatus = 12; + } else { + keystatus = keycode; + } // Copy keycode keycodeold = keycode; while(readSensorpads() > 0){} // Wait for pad release diff --git a/lib/obp60task/PageSystem.cpp b/lib/obp60task/PageSystem.cpp index e56d94b..7f601a1 100644 --- a/lib/obp60task/PageSystem.cpp +++ b/lib/obp60task/PageSystem.cpp @@ -4,6 +4,7 @@ #include "OBP60Extensions.h" #include "images/logo64.xbm" #include <esp32/clk.h> +#include "qrcode.h" #define STRINGIZE_IMPL(x) #x #define STRINGIZE(x) STRINGIZE_IMPL(x) @@ -66,7 +67,8 @@ public: if (hasFRAM) fram.write(FRAM_SYSTEM_MODE, mode); return 0; } - // grab cursor keys to disable page navigation +#ifdef BOARD_OBP60S3 + // grab cursor key to disable page navigation if (key == 3) { return 0; } @@ -74,20 +76,55 @@ public: if (key == 4) { ESP.restart(); } -#ifdef BOARD_OBP60S3 // standby / deep sleep if (key == 5) { deepSleep(*commonData); } -#endif // Code for keylock if (key == 11) { commonData->keylock = !commonData->keylock; return 0; } +#endif +#ifdef BOARD_OBP40S3 + // grab cursor keys to disable page navigation + if (key == 9 or key == 10) { + return 0; + } + // standby / deep sleep + if (key == 12) { + deepSleep(*commonData); + } +#endif return key; } + void displayBarcode(String serialno, uint16_t x, uint16_t y, uint16_t s) { + // Barcode with serial number + // x, y is top left corner + // s is pixel size of a single box + QRCode qrcode; + uint8_t qrcodeData[qrcode_getBufferSize(4)]; + #ifdef BOARD_OBP40S3 + String prefix = "OBP40:SN:"; + #endif + #ifdef BOARD_OBP60S3 + String prefix = "OBP60:SN:"; + #endif + qrcode_initText(&qrcode, qrcodeData, 4, 0, (prefix + serialno).c_str()); + int16_t x0 = x; + for (uint8_t j = 0; j < qrcode.size; j++) { + for (uint8_t i = 0; i < qrcode.size; i++) { + if (qrcode_getModule(&qrcode, i, j)) { + getdisplay().fillRect(x, y, s, s, commonData->fgcolor); + } + x += s; + } + y += s; + x = x0; + } + } + virtual void displayPage(PageData &pageData){ GwConfigHandler *config = commonData->config; GwLog *logger = commonData->logger; @@ -114,30 +151,36 @@ public: if (mode == 'N') { getdisplay().setFont(&Ubuntu_Bold12pt7b); - getdisplay().setCursor(20, 50); + getdisplay().setCursor(8, 50); getdisplay().print("System Information"); getdisplay().drawXBitmap(320, 25, logo64_bits, logo64_width, logo64_height, commonData->fgcolor); getdisplay().setFont(&Ubuntu_Bold8pt7b); - char ssid[23]; - snprintf(ssid, 23, "MCUDEVICE-%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid); - getdisplay().setCursor(20, 70); - getdisplay().print(ssid); - getdisplay().setCursor(20, 100); - getdisplay().print("Press STBY for white page and standby"); + char ssid[13]; + snprintf(ssid, 13, "%04X%08X", (uint16_t)(chipid >> 32), (uint32_t)chipid); + displayBarcode(String(ssid), 320, 200, 2); + getdisplay().setCursor(8, 70); + getdisplay().print(String("MUDEVICE-") + String(ssid)); + + getdisplay().setCursor(8, 90); + getdisplay().print("Firmware Version: "); + getdisplay().print(VERSINFO); + + getdisplay().setCursor(8, 265); + #ifdef BOARD_OBP60S3 + getdisplay().print("Press STBY to enter deep sleep mode"); + #endif + #ifdef BOARD_OBP40S3 + getdisplay().print("Press wheel to enter deep sleep mode"); + #endif getdisplay().setCursor(2, y0); getdisplay().print("Simulation:"); getdisplay().setCursor(120, y0); getdisplay().print(simulation ? "on" : "off"); - getdisplay().setCursor(202, y0); - getdisplay().print("Wifi:"); - getdisplay().setCursor(300, y0); - getdisplay().print(commonData->status.wifiApOn ? "On" : "Off"); - getdisplay().setCursor(2, y0 + 16); getdisplay().print("Environment:"); getdisplay().setCursor(120, y0 + 16); @@ -145,9 +188,9 @@ public: // total RAM free int Heap_free = esp_get_free_heap_size(); - getdisplay().setCursor(202, y0 + 16); + getdisplay().setCursor(202, y0); getdisplay().print("Total free:"); - getdisplay().setCursor(300, y0 + 16); + getdisplay().setCursor(300, y0); getdisplay().print(String(Heap_free)); getdisplay().setCursor(2, y0 + 32); @@ -157,37 +200,39 @@ public: // RAM free for task int RAM_free = uxTaskGetStackHighWaterMark(NULL); - getdisplay().setCursor(202, y0 + 32); + getdisplay().setCursor(202, y0 + 16); getdisplay().print("Task free:"); - getdisplay().setCursor(300, y0 + 32); + getdisplay().setCursor(300, y0 + 16); getdisplay().print(String(RAM_free)); - getdisplay().setCursor(2, y0 + 48); + // FRAM available / status + getdisplay().setCursor(202, y0 + 32); + getdisplay().print("FRAM:"); + getdisplay().setCursor(300, y0 + 32); + getdisplay().print(hasFRAM ? "available" : "not found"); + + getdisplay().setCursor(202, y0 + 64); getdisplay().print("CPU speed:"); - getdisplay().setCursor(120, y0 + 48); + getdisplay().setCursor(300, y0 + 64); getdisplay().print(cpuspeed); getdisplay().print(" / "); int cpu_freq = esp_clk_cpu_freq() / 1000000; getdisplay().print(String(cpu_freq)); - getdisplay().setCursor(202, y0 + 64); + getdisplay().setCursor(2, y0 + 64); getdisplay().print("GPS:"); - getdisplay().setCursor(300, y0 + 64); + getdisplay().setCursor(120, y0 + 64); getdisplay().print(gps_module); getdisplay().setCursor(2, y0 + 80); - getdisplay().print("FRAM:"); - getdisplay().setCursor(120, y0 + 80); - getdisplay().print(hasFRAM ? "available" : "not found"); - - getdisplay().setCursor(202, y0 + 80); getdisplay().print("RTC:"); - getdisplay().setCursor(300, y0 + 80); + getdisplay().setCursor(120, y0 + 80); getdisplay().print(rtc_module); - getdisplay().setCursor(2, y0 + 120); - getdisplay().print("Firmware Version: "); - getdisplay().print(VERSINFO); + getdisplay().setCursor(2, y0 + 96); + getdisplay().print("Wifi:"); + getdisplay().setCursor(120, y0 + 96); + getdisplay().print(commonData->status.wifiApOn ? "On" : "Off"); } else { diff --git a/lib/obp60task/config_obp40.json b/lib/obp60task/config_obp40.json index d18533c..3a4b6bf 100644 --- a/lib/obp60task/config_obp40.json +++ b/lib/obp60task/config_obp40.json @@ -913,6 +913,17 @@ "obp40": "true" } }, + { + "name": "systemPage", + "label": "System Page", + "type": "boolean", + "default": "false", + "description": "Use wheel button for system page or direct deep sleep mode", + "category":"OBP40 Pages", + "capabilities": { + "obp40": "true" + } + }, { "name": "imageFormat", "label": "Screenshot Format", diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 3defb2b..a55e62b 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -118,7 +118,7 @@ void OBP60Init(GwApi *api){ #endif #ifdef BOARD_OBP60S3 - touchSleepWakeUpEnable(TP1, 45); + touchSleepWakeUpEnable(TP1, 45); // TODO sensitivity should be configurable via web interface touchSleepWakeUpEnable(TP2, 45); touchSleepWakeUpEnable(TP3, 45); touchSleepWakeUpEnable(TP4, 45); @@ -169,6 +169,7 @@ typedef struct { GwLog* logger = NULL; // GwApi* api = NULL; uint sensitivity = 100; + bool use_syspage = true; } MyData; // Keyboard Task @@ -180,7 +181,7 @@ void keyboardTask(void *param){ // Loop for keyboard task while (true){ - keycode = readKeypad(data->logger, data->sensitivity); + keycode = readKeypad(data->logger, data->sensitivity, data->use_syspage); //send a key event if(keycode != 0){ xQueueSend(data->queue, &keycode, 0); @@ -336,38 +337,6 @@ void underVoltageDetection(GwApi *api, CommonData &common){ } } -#ifdef BOARD_OBP40S3 -// Deep sleep funktion -void deepSleep(CommonData &common){ - // Switch off all power lines - setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off - setFlashLED(false); // Flash LED Off - buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms - // Shutdown EInk display - getdisplay().setFullWindow(); // Set full Refresh - //getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update - getdisplay().fillScreen(common.bgcolor); // Clear screen - getdisplay().setTextColor(common.fgcolor); - getdisplay().setFont(&Ubuntu_Bold20pt7b); - getdisplay().setCursor(85, 150); - getdisplay().print("Sleep Mode"); - getdisplay().setFont(&Ubuntu_Bold8pt7b); - getdisplay().setCursor(65, 175); - getdisplay().print("For wakeup press wheel and wait 5s"); - getdisplay().nextPage(); // Partial update - getdisplay().powerOff(); // Display power off - setPortPin(OBP_POWER_EPD, false); // Power off ePaper display - setPortPin(OBP_POWER_SD, false); // Power off SD card - // Stop system - while(true){ - esp_deep_sleep_start(); // Deep Sleep with weakup via GPIO pin - } - -} -#endif - - - // OBP60 Task //#################################################################################### void OBP60Task(GwApi *api){ @@ -412,6 +381,9 @@ void OBP60Task(GwApi *api){ bool refreshmode = api->getConfig()->getConfigItem(api->getConfig()->refresh,true)->asBoolean(); String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString(); uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt()); + #ifdef BOARD_OBP40S3 + bool syspage_enabled = config->getBool(config->systemPage); + #endif #ifdef DISPLAY_GDEY042T81 getdisplay().init(115200, true, 2, false); // Use this for Waveshare boards with "clever" reset circuit, 2ms reset pulse @@ -453,16 +425,24 @@ void OBP60Task(GwApi *api){ // Set start page int pageNumber = int(api->getConfig()->getConfigItem(api->getConfig()->startPage,true)->asInt()) - 1; -#ifdef BOARD_OBP60S3 LOG_DEBUG(GwLog::LOG,"Checking wakeup..."); +#ifdef BOARD_OBP60S3 if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_TOUCHPAD) { LOG_DEBUG(GwLog::LOG,"Wake up by touch pad %d",esp_sleep_get_touchpad_wakeup_status()); pageNumber = getLastPage(); } else { LOG_DEBUG(GwLog::LOG,"Other wakeup reason"); } - LOG_DEBUG(GwLog::LOG,"...done"); #endif +#ifdef BOARD_OBP40S3 + if (esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_EXT0) { + LOG_DEBUG(GwLog::LOG,"Wake up by key"); + pageNumber = getLastPage(); + } else { + LOG_DEBUG(GwLog::LOG,"Other wakeup reason"); + } +#endif + LOG_DEBUG(GwLog::LOG,"...done"); int lastPage=pageNumber; @@ -525,6 +505,9 @@ void OBP60Task(GwApi *api){ allParameters.page0=3; allParameters.queue=xQueueCreate(10,sizeof(int)); allParameters.sensitivity= api->getConfig()->getInt(GwConfigDefinitions::tSensitivity); + #ifdef BOARD_OBP40S3 + allParameters.use_syspage = syspage_enabled; + #endif xTaskCreate(keyboardTask,"keyboard",2000,&allParameters,configMAX_PRIORITIES-1,NULL); SharedData *shared=new SharedData(api); createSensorTask(shared); @@ -621,10 +604,11 @@ void OBP60Task(GwApi *api){ LOG_DEBUG(GwLog::LOG,"new key from keyboard %d",keyboardMessage); keypressed = true; - if (keyboardMessage == 12) { + if (keyboardMessage == 12 and !systemPage) { LOG_DEBUG(GwLog::LOG, "Calling system page"); systemPage = true; // System page is out of band syspage->setupKeys(); + keyboardMessage = 0; } else { currentPage = pages[pageNumber].page; @@ -632,6 +616,7 @@ void OBP60Task(GwApi *api){ // exit system mode with exit key number 1 systemPage = false; currentPage->setupKeys(); + keyboardMessage = 0; } } if (systemPage) { @@ -652,7 +637,7 @@ void OBP60Task(GwApi *api){ } #ifdef BOARD_OBP40S3 // #3 Deep sleep mode for OBP40 - if (keyboardMessage == 3){ + if ((keyboardMessage == 3) and !syspage_enabled){ deepSleep(commonData); } #endif From 7afcb864042343dd863439f07793d678309d1370 Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Fri, 24 Jan 2025 15:23:02 +0100 Subject: [PATCH 08/17] OBP40 Battery voltage measuring and capacity calculation --- lib/obp60task/OBPSensorTask.cpp | 33 +++++++++++++++++++++++++++++++-- lib/obp60task/Pagedata.h | 2 ++ lib/obp60task/platformio.ini | 6 +++++- 3 files changed, 38 insertions(+), 3 deletions(-) diff --git a/lib/obp60task/OBPSensorTask.cpp b/lib/obp60task/OBPSensorTask.cpp index 99071ab..cd488ab 100644 --- a/lib/obp60task/OBPSensorTask.cpp +++ b/lib/obp60task/OBPSensorTask.cpp @@ -88,8 +88,16 @@ void sensorTask(void *param){ double voffset = (api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asString()).toFloat(); double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat(); if(String(powsensor1) == "off"){ - sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 + #ifdef VOLTAGE_SENSOR + sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 + #else + sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 + #endif sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration + #ifdef LIPO_ACCU_1200 + sensors.BatteryChargeStatus = 0; // Set to discharging + sensors.batteryLevelLiPo = 0; // Level 0...100% + #endif sensors.batteryCurrent = 0; sensors.batteryPower = 0; // Fill average arrays with start values @@ -459,8 +467,29 @@ void sensorTask(void *param){ // Send supply voltage value all 1s if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){ starttime5 = millis(); - sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 + #ifdef VOLTAGE_SENSOR + sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 + #else + sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 + #endif sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration + #ifdef LIPO_ACCU_1200 + if(sensors.batteryVoltage > 4.1){ + sensors.BatteryChargeStatus = 1; // Charging active + } + else{ + sensors.BatteryChargeStatus = 0; // Discharging + } + // Polynomfit for LiPo capacity calculation for 3,7V LiPo accus, 0...100% + sensors.batteryLevelLiPo = sensors.batteryVoltage * sensors.batteryVoltage * 174.9513 + sensors.batteryVoltage * 1147,7686 + 1868.5120; + // Limiter + if(sensors.batteryLevelLiPo > 100){ + sensors.batteryLevelLiPo = 100; + } + if(sensors.batteryLevelLiPo < 0){ + sensors.batteryLevelLiPo = 0; + } + #endif // Save new data in average array batV.reading(int(sensors.batteryVoltage * 100)); // Calculate the average values for different time lines from integer values diff --git a/lib/obp60task/Pagedata.h b/lib/obp60task/Pagedata.h index b385b5c..d511aee 100644 --- a/lib/obp60task/Pagedata.h +++ b/lib/obp60task/Pagedata.h @@ -31,6 +31,8 @@ typedef struct{ double batteryVoltage300 = 0; // Sliding average over 300 values double batteryCurrent300 = 0; double batteryPower300 = 0; + double batteryLevelLiPo = 0; // Battery level for OBP40 LiPo accu + int BatteryChargeStatus = 0; // LiPo charge status: 0 = discharge, 1 = loading activ double solarVoltage = 0; double solarCurrent = 0; double solarPower = 0; diff --git a/lib/obp60task/platformio.ini b/lib/obp60task/platformio.ini index da78f39..662032a 100644 --- a/lib/obp60task/platformio.ini +++ b/lib/obp60task/platformio.ini @@ -2,7 +2,9 @@ #if you want a pio run to only build #your special environments you can set this here #by uncommenting the next line -default_envs = obp60_s3 +default_envs = + obp60_s3 + obp40_s3 [env:obp60_s3] platform = espressif32@6.8.1 @@ -91,6 +93,8 @@ build_flags= -D DISABLE_DIAGNOSTIC_OUTPUT #Disable diagnostic output for GxEPD2 lib -D BOARD_OBP40S3 #Board OBP40 V1.0 with ESP32S3 SKU:DIE07300S (CrowPanel 4.2) -D DISPLAY_GDEY042T81 #new E-Ink display from Waveshare, R10 2.2 ohm + -D LIPO_ACCU_1200 #Hardware extension, LiPo accu 3,7V 1200mAh + -D VOLTAGE_SENSOR #Hardware extension, LiPo voltage sensor with two resistors ${env.build_flags} upload_port = /dev/ttyUSB0 #OBP40 download via external USB/Serail converter upload_protocol = esptool #firmware upload via USB OTG seriell, by first upload need to set the ESP32-S3 in the upload mode with shortcut GND to Pin27 From e9ee49a6ef923a6e888a40364acb109c1650c8bb Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Fri, 24 Jan 2025 17:33:34 +0100 Subject: [PATCH 09/17] Add undervoltage for LiPo accu for OBP40 --- lib/obp60task/obp60task.cpp | 39 ++++++++++++++++++++++++++++++++++--- 1 file changed, 36 insertions(+), 3 deletions(-) diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 3defb2b..b87c4bd 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -308,13 +308,42 @@ void registerAllPages(PageList &list){ // Undervoltage detection for shutdown display void underVoltageDetection(GwApi *api, CommonData &common){ + float actVoltage = 0; + float minVoltage = 0; // Read settings float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat()); float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat()); // Read supply voltage - float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // V = 1/20 * Vin + #if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200 + actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 + minVoltage = 3.65; // Absolut minimum volatge for 3,7V LiPo accu + #else + actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 + minVoltage = MIN_VOLTAGE; + #endif actVoltage = actVoltage * vslope + voffset; - if(actVoltage < MIN_VOLTAGE){ + if(actVoltage < minVoltage){ + #if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200 + // Switch off all power lines + setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off + setFlashLED(false); // Flash LED Off + buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms + // Shutdown EInk display + getdisplay().setFullWindow(); // Set full Refresh + //getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update + getdisplay().fillScreen(common.bgcolor); // Clear screen + getdisplay().setTextColor(common.fgcolor); + getdisplay().setFont(&Ubuntu_Bold20pt7b); + getdisplay().setCursor(65, 150); + getdisplay().print("Undervoltage"); + getdisplay().setFont(&Ubuntu_Bold8pt7b); + getdisplay().setCursor(65, 175); + getdisplay().print("To wake up press reset"); + getdisplay().nextPage(); // Partial update + getdisplay().powerOff(); // Display power off + setPortPin(OBP_POWER_EPD, false); // Power off ePaper display + setPortPin(OBP_POWER_SD, false); // Power off SD card + #else // Switch off all power lines setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off setFlashLED(false); // Flash LED Off @@ -327,8 +356,12 @@ void underVoltageDetection(GwApi *api, CommonData &common){ getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setCursor(65, 150); getdisplay().print("Undervoltage"); + getdisplay().setFont(&Ubuntu_Bold8pt7b); + getdisplay().setCursor(65, 175); + getdisplay().print("To wake up repower system"); getdisplay().nextPage(); // Partial update getdisplay().powerOff(); // Display power off + #endif // Stop system while(true){ esp_deep_sleep_start(); // Deep Sleep without weakup. Weakup only after power cycle (restart). @@ -353,7 +386,7 @@ void deepSleep(CommonData &common){ getdisplay().print("Sleep Mode"); getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(65, 175); - getdisplay().print("For wakeup press wheel and wait 5s"); + getdisplay().print("To wake up press wheel and wait 5s"); getdisplay().nextPage(); // Partial update getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_EPD, false); // Power off ePaper display From 0b7863cb86785766929a184da43481a85e8a7061 Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Fri, 24 Jan 2025 18:41:48 +0100 Subject: [PATCH 10/17] Typo --- lib/obp60task/obp60task.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index b87c4bd..4c0ff64 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -370,7 +370,7 @@ void underVoltageDetection(GwApi *api, CommonData &common){ } #ifdef BOARD_OBP40S3 -// Deep sleep funktion +// Deep sleep function void deepSleep(CommonData &common){ // Switch off all power lines setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off From f116e41964308ffea52c9d0e6158b190167355b6 Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Fri, 24 Jan 2025 22:18:38 +0100 Subject: [PATCH 11/17] Fix for config.json, depensencies to other ode --- lib/obp60task/OBP60Extensions.cpp | 4 ++-- lib/obp60task/obp60task.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 9f7df24..3407434 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -146,7 +146,7 @@ void deepSleep(CommonData &common){ getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_50, false); // Power off ePaper display // Stop system - esp_deep_sleep_start(); // Deep Sleep with weakup via touch pin + esp_deep_sleep_start(); // Deep Sleep with weakup via touch pin } #endif #ifdef BOARD_OBP40S3 @@ -166,7 +166,7 @@ void deepSleep(CommonData &common){ getdisplay().print("Sleep Mode"); getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(65, 175); - getdisplay().print("For wakeup press wheel and wait 5s"); + getdisplay().print("to wake up press wheel and wait 5s"); getdisplay().nextPage(); // Partial update getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_EPD, false); // Power off ePaper display diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 7dfd29d..fea1fb6 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -78,7 +78,7 @@ void OBP60Init(GwApi *api){ } #ifdef BOARD_OBP40S3 - //String sdcard = config->getConfigItem(config->useSDCard, true)->asString(); +// String sdcard = config->getConfigItem(config->useSDCard, true)->asString(); String sdcard = "on"; if (sdcard == "on") { SPIClass SD_SPI = SPIClass(HSPI); @@ -415,7 +415,8 @@ void OBP60Task(GwApi *api){ String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString(); uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt()); #ifdef BOARD_OBP40S3 - bool syspage_enabled = config->getBool(config->systemPage); +// bool syspage_enabled = config->getBool(config->systemPage); + bool syspage_enabled = false; #endif #ifdef DISPLAY_GDEY042T81 From ea9a2ff9c49eb8ff98f5f3e3e17d7baeb3e51385 Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Fri, 24 Jan 2025 22:18:38 +0100 Subject: [PATCH 12/17] Fix for config.json, dependencies to other ode --- lib/obp60task/OBP60Extensions.cpp | 4 ++-- lib/obp60task/obp60task.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 9f7df24..3407434 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -146,7 +146,7 @@ void deepSleep(CommonData &common){ getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_50, false); // Power off ePaper display // Stop system - esp_deep_sleep_start(); // Deep Sleep with weakup via touch pin + esp_deep_sleep_start(); // Deep Sleep with weakup via touch pin } #endif #ifdef BOARD_OBP40S3 @@ -166,7 +166,7 @@ void deepSleep(CommonData &common){ getdisplay().print("Sleep Mode"); getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(65, 175); - getdisplay().print("For wakeup press wheel and wait 5s"); + getdisplay().print("to wake up press wheel and wait 5s"); getdisplay().nextPage(); // Partial update getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_EPD, false); // Power off ePaper display diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 7dfd29d..fea1fb6 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -78,7 +78,7 @@ void OBP60Init(GwApi *api){ } #ifdef BOARD_OBP40S3 - //String sdcard = config->getConfigItem(config->useSDCard, true)->asString(); +// String sdcard = config->getConfigItem(config->useSDCard, true)->asString(); String sdcard = "on"; if (sdcard == "on") { SPIClass SD_SPI = SPIClass(HSPI); @@ -415,7 +415,8 @@ void OBP60Task(GwApi *api){ String fastrefresh = api->getConfig()->getConfigItem(api->getConfig()->fastRefresh,true)->asString(); uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt()); #ifdef BOARD_OBP40S3 - bool syspage_enabled = config->getBool(config->systemPage); +// bool syspage_enabled = config->getBool(config->systemPage); + bool syspage_enabled = false; #endif #ifdef DISPLAY_GDEY042T81 From 26e551c6162f8ff61aae381637c29da0cd129371 Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Fri, 24 Jan 2025 22:29:12 +0100 Subject: [PATCH 13/17] Typo --- lib/obp60task/OBP60Extensions.cpp | 4 ++-- lib/obp60task/obp60task.cpp | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 3407434..b74d76d 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -141,7 +141,7 @@ void deepSleep(CommonData &common){ getdisplay().print("Sleep Mode"); getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(65, 175); - getdisplay().print("For wakeup press key and wait 5s"); + getdisplay().print("To wake up press key and wait 5s"); getdisplay().nextPage(); // Update display contents getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_50, false); // Power off ePaper display @@ -166,7 +166,7 @@ void deepSleep(CommonData &common){ getdisplay().print("Sleep Mode"); getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(65, 175); - getdisplay().print("to wake up press wheel and wait 5s"); + getdisplay().print("To wake up press wheel and wait 5s"); getdisplay().nextPage(); // Partial update getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_EPD, false); // Power off ePaper display diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index fea1fb6..51828e4 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -339,7 +339,7 @@ void underVoltageDetection(GwApi *api, CommonData &common){ getdisplay().print("Undervoltage"); getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(65, 175); - getdisplay().print("To wake up press reset"); + getdisplay().print("Charge battery and restart"); getdisplay().nextPage(); // Partial update getdisplay().powerOff(); // Display power off setPortPin(OBP_POWER_EPD, false); // Power off ePaper display @@ -416,7 +416,7 @@ void OBP60Task(GwApi *api){ uint fullrefreshtime = uint(api->getConfig()->getConfigItem(api->getConfig()->fullRefreshTime,true)->asInt()); #ifdef BOARD_OBP40S3 // bool syspage_enabled = config->getBool(config->systemPage); - bool syspage_enabled = false; + bool syspage_enabled = true; #endif #ifdef DISPLAY_GDEY042T81 From bdfaf3c8864004e0e1ee827d855559d765a4baae Mon Sep 17 00:00:00 2001 From: Thomas Hooge <thomas@hoogi.de> Date: Sat, 25 Jan 2025 09:39:12 +0100 Subject: [PATCH 14/17] Added battery symbols --- lib/obp60task/OBP60Extensions.h | 40 +++++++++++++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h index b6f653f..845283f 100644 --- a/lib/obp60task/OBP60Extensions.h +++ b/lib/obp60task/OBP60Extensions.h @@ -160,6 +160,46 @@ static std::map<String, unsigned char *> iconmap = { {"AP", ap_bits} }; +// Battery +#define battery_width 24 +#define battery_height 16 + +static unsigned char battery_0_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f, + 0x03, 0x00, 0x18, 0x03, 0x00, 0x78, 0x03, 0x00, 0xf8, 0x03, 0x00, 0xd8, + 0x03, 0x00, 0xd8, 0x03, 0x00, 0xd8, 0x03, 0x00, 0xf8, 0x03, 0x00, 0x78, + 0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 }; + +static unsigned char battery_25_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f, + 0x03, 0x00, 0x18, 0x3b, 0x00, 0x78, 0x3b, 0x00, 0xf8, 0x3b, 0x00, 0xd8, + 0x3b, 0x00, 0xd8, 0x3b, 0x00, 0xd8, 0x3b, 0x00, 0xf8, 0x3b, 0x00, 0x78, + 0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 }; + +static unsigned char battery_50_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f, + 0x03, 0x00, 0x18, 0xbb, 0x03, 0x78, 0xbb, 0x03, 0xf8, 0xbb, 0x03, 0xd8, + 0xbb, 0x03, 0xd8, 0xbb, 0x03, 0xd8, 0xbb, 0x03, 0xf8, 0xbb, 0x03, 0x78, + 0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 }; + +static unsigned char battery_75_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f, + 0x03, 0x00, 0x18, 0xbb, 0x3b, 0x78, 0xbb, 0x3b, 0xf8, 0xbb, 0x3b, 0xd8, + 0xbb, 0x3b, 0xd8, 0xbb, 0x3b, 0xd8, 0xbb, 0x3b, 0xf8, 0xbb, 0x3b, 0x78, + 0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 }; + +static unsigned char battery_100_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x0f, 0xff, 0xff, 0x1f, + 0x03, 0x00, 0x18, 0xbb, 0xbb, 0x7b, 0xbb, 0xbb, 0xfb, 0xbb, 0xbb, 0xdb, + 0xbb, 0xbb, 0xdb, 0xbb, 0xbb, 0xdb, 0xbb, 0xbb, 0xfb, 0xbb, 0xbb, 0x7b, + 0x03, 0x00, 0x18, 0xff, 0xff, 0x1f, 0xfe, 0xff, 0x0f, 0x00, 0x00, 0x00 }; + +static unsigned char battery_loading_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0xfe, 0xe4, 0x0f, 0xff, 0xec, 0x1f, + 0x03, 0x08, 0x18, 0x03, 0x18, 0x78, 0x03, 0x30, 0xf8, 0x83, 0x3f, 0xd8, + 0x03, 0x7f, 0xd8, 0x03, 0x03, 0xd8, 0x03, 0x06, 0xf8, 0x03, 0x04, 0x78, + 0x03, 0x0c, 0x18, 0xff, 0xcb, 0x1f, 0xfe, 0xd3, 0x0f, 0x00, 0x10, 0x00 }; + // Other symbols #define swipe_width 24 #define swipe_height 16 From 097111c27002b1f9bfe1032b3dd39ba107b87f9d Mon Sep 17 00:00:00 2001 From: Thomas Hooge <thomas@hoogi.de> Date: Sat, 25 Jan 2025 10:21:34 +0100 Subject: [PATCH 15/17] Added code for new OBP40 battery symbols --- lib/obp60task/OBP60Extensions.cpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/lib/obp60task/OBP60Extensions.cpp b/lib/obp60task/OBP60Extensions.cpp index 9f7df24..95b3044 100644 --- a/lib/obp60task/OBP60Extensions.cpp +++ b/lib/obp60task/OBP60Extensions.cpp @@ -392,6 +392,25 @@ void displayHeader(CommonData &commonData, GwApi::BoatValue *date, GwApi::BoatVa getdisplay().drawXBitmap(166, 1, swipe_bits, swipe_width, swipe_height, commonData.fgcolor); } #endif +#ifdef LIPO_ACCU_1200 + if (commonData.data.BatteryChargeStatus == 1) { + getdisplay().drawXBitmap(170, 1, battery_loading_bits, battery_width, battery_height, commonData.fgcolor); + } else { +#ifdef VOLTAGE_SENSOR + if (commonData.data.batteryLevelLiPo < 10) { + getdisplay().drawXBitmap(170, 1, battery_0_bits, battery_width, battery_height, commonData.fgcolor); + } else if (commonData.data.batteryLevelLiPo < 25) { + getdisplay().drawXBitmap(170, 1, battery_25_bits, battery_width, battery_height, commonData.fgcolor); + } else if (commonData.data.batteryLevelLiPo < 50) { + getdisplay().drawXBitmap(170, 1, battery_50_bits, battery_width, battery_height, commonData.fgcolor); + } else if (commonData.data.batteryLevelLiPo < 75) { + getdisplay().drawXBitmap(170, 1, battery_75_bits, battery_width, battery_height, commonData.fgcolor); + } else { + getdisplay().drawXBitmap(170, 1, battery_100_bits, battery_width, battery_height, commonData.fgcolor); + } +#endif // VOLTAGE_SENSOR + } +#endif // LIPO_ACCU_1200 // Heartbeat as dot getdisplay().setTextColor(commonData.fgcolor); From df81e6e443abc2ce80fb909ff2574c2b43e979ca Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Sat, 25 Jan 2025 16:19:10 +0100 Subject: [PATCH 16/17] Fix charge status, add to PageVoltage --- boards/obp40_s3_n8r8.json | 4 +- extra_script.py | 16 +- extra_script.py.old | 518 ++++++++++++++++++++++++++++++++ lib/obp60task/OBP60Extensions.h | 4 +- lib/obp60task/OBPSensorTask.cpp | 37 ++- lib/obp60task/PageVoltage.cpp | 17 ++ lib/obp60task/config_obp40.json | 4 +- lib/obp60task/obp60task.cpp | 18 +- 8 files changed, 586 insertions(+), 32 deletions(-) create mode 100644 extra_script.py.old diff --git a/boards/obp40_s3_n8r8.json b/boards/obp40_s3_n8r8.json index 260050c..2ac8c3e 100644 --- a/boards/obp40_s3_n8r8.json +++ b/boards/obp40_s3_n8r8.json @@ -19,8 +19,8 @@ "flash_mode": "qio", "hwids": [ [ - "0x303A", - "0x1001" + "0x1A86", + "0x7523" ] ], "mcu": "esp32s3", diff --git a/extra_script.py b/extra_script.py index ed62c64..b185a93 100644 --- a/extra_script.py +++ b/extra_script.py @@ -10,7 +10,7 @@ from datetime import datetime import re import pprint from platformio.project.config import ProjectConfig - +from platformio.project.exception import InvalidProjectConfError Import("env") #print(env.Dump()) @@ -104,7 +104,17 @@ def writeFileIfChanged(fileName,data): return True def mergeConfig(base,other): + try: + customconfig = env.GetProjectOption("custom_config") + except InvalidProjectConfError: + customconfig = None for bdir in other: + if customconfig and os.path.exists(os.path.join(bdir,customconfig)): + cname=os.path.join(bdir,customconfig) + print("merge custom config {}".format(cname)) + with open(cname,'rb') as ah: + base += json.load(ah) + continue cname=os.path.join(bdir,"config.json") if os.path.exists(cname): print("merge config %s"%cname) @@ -274,9 +284,9 @@ class Grove: def _ss(self,z=False): if z: return self.name - return self.name if self.name is not 'Z' else '' + return self.name if self.name != 'Z' else '' def _suffix(self): - return '_'+self.name if self.name is not 'Z' else '' + return '_'+self.name if self.name != 'Z' else '' def replace(self,line): if line is None: return line diff --git a/extra_script.py.old b/extra_script.py.old new file mode 100644 index 0000000..ed62c64 --- /dev/null +++ b/extra_script.py.old @@ -0,0 +1,518 @@ +print("running extra...") +import gzip +import shutil +import os +import sys +import inspect +import json +import glob +from datetime import datetime +import re +import pprint +from platformio.project.config import ProjectConfig + + +Import("env") +#print(env.Dump()) +OWN_FILE="extra_script.py" +GEN_DIR='lib/generated' +CFG_FILE='web/config.json' +XDR_FILE='web/xdrconfig.json' +INDEXJS="index.js" +INDEXCSS="index.css" +CFG_INCLUDE='GwConfigDefinitions.h' +CFG_INCLUDE_IMPL='GwConfigDefImpl.h' +XDR_INCLUDE='GwXdrTypeMappings.h' +TASK_INCLUDE='GwUserTasks.h' +GROVE_CONFIG="GwM5GroveGen.h" +GROVE_CONFIG_IN="lib/hardware/GwM5Grove.in" +EMBEDDED_INCLUDE="GwEmbeddedFiles.h" + +def getEmbeddedFiles(env): + rt=[] + efiles=env.GetProjectOption("board_build.embed_files") + for f in efiles.split("\n"): + if f == '': + continue + rt.append(f) + return rt + +def basePath(): + #see: https://stackoverflow.com/questions/16771894/python-nameerror-global-name-file-is-not-defined + return os.path.dirname(inspect.getfile(lambda: None)) + +def outPath(): + return os.path.join(basePath(),GEN_DIR) +def checkDir(): + dn=outPath() + if not os.path.exists(dn): + os.makedirs(dn) + if not os.path.isdir(dn): + print("unable to create %s"%dn) + return False + return True + +def isCurrent(infile,outfile): + if os.path.exists(outfile): + otime=os.path.getmtime(outfile) + itime=os.path.getmtime(infile) + if (otime >= itime): + own=os.path.join(basePath(),OWN_FILE) + if os.path.exists(own): + owntime=os.path.getmtime(own) + if owntime > otime: + return False + print("%s is newer then %s, no need to recreate"%(outfile,infile)) + return True + return False +def compressFile(inFile,outfile): + if isCurrent(inFile,outfile): + return + print("compressing %s"%inFile) + with open(inFile, 'rb') as f_in: + with gzip.open(outfile, 'wb') as f_out: + shutil.copyfileobj(f_in, f_out) + +def generateFile(infile,outfile,callback,inMode='rb',outMode='w'): + if isCurrent(infile,outfile): + return + print("creating %s"%outfile) + oh=None + with open(infile,inMode) as ch: + with open(outfile,outMode) as oh: + try: + callback(ch,oh,inFile=infile) + oh.close() + except Exception as e: + try: + oh.close() + except: + pass + os.unlink(outfile) + raise + +def writeFileIfChanged(fileName,data): + if os.path.exists(fileName): + with open(fileName,"r") as ih: + old=ih.read() + ih.close() + if old == data: + return False + print("#generating %s"%fileName) + with open(fileName,"w") as oh: + oh.write(data) + return True + +def mergeConfig(base,other): + for bdir in other: + cname=os.path.join(bdir,"config.json") + if os.path.exists(cname): + print("merge config %s"%cname) + with open(cname,'rb') as ah: + merge=json.load(ah) + base=base+merge + return base + +def replaceTexts(data,replacements): + if replacements is None: + return data + if isinstance(data,str): + for k,v in replacements.items(): + data=data.replace("$"+k,str(v)) + return data + if isinstance(data,list): + rt=[] + for e in data: + rt.append(replaceTexts(e,replacements)) + return rt + if isinstance(data,dict): + rt={} + for k,v in data.items(): + rt[replaceTexts(k,replacements)]=replaceTexts(v,replacements) + return rt + return data +def expandConfig(config): + rt=[] + for item in config: + type=item.get('type') + if type != 'array': + rt.append(item) + continue + replacements=item.get('replace') + children=item.get('children') + name=item.get('name') + if name is None: + name="#unknown#" + if not isinstance(replacements,list): + raise Exception("missing replacements at array %s"%name) + for replace in replacements: + if children is not None: + for c in children: + rt.append(replaceTexts(c,replace)) + return rt + +def generateMergedConfig(inFile,outFile,addDirs=[]): + if not os.path.exists(inFile): + raise Exception("unable to read cfg file %s"%inFile) + data="" + with open(inFile,'rb') as ch: + config=json.load(ch) + config=mergeConfig(config,addDirs) + config=expandConfig(config) + data=json.dumps(config,indent=2) + writeFileIfChanged(outFile,data) + +def generateCfg(inFile,outFile,impl): + if not os.path.exists(inFile): + raise Exception("unable to read cfg file %s"%inFile) + data="" + with open(inFile,'rb') as ch: + config=json.load(ch) + data+="//generated from %s\n"%inFile + l=len(config) + idx=0 + if not impl: + data+='#include "GwConfigItem.h"\n' + data+='class GwConfigDefinitions{\n' + data+=' public:\n' + data+=' int getNumConfig() const{return %d;}\n'%(l) + for item in config: + n=item.get('name') + if n is None: + continue + if len(n) > 15: + raise Exception("%s: config names must be max 15 caracters"%n) + data+=' static constexpr const char* %s="%s";\n'%(n,n) + data+="};\n" + else: + data+='void GwConfigHandler::populateConfigs(GwConfigInterface **config){\n' + for item in config: + name=item.get('name') + if name is None: + continue + data+=' configs[%d]='%(idx) + idx+=1 + secret="false"; + if item.get('type') == 'password': + secret="true" + data+=" new GwConfigInterface(%s,\"%s\",%s);\n"%(name,item.get('default'),secret) + data+='}\n' + writeFileIfChanged(outFile,data) + +def labelFilter(label): + return re.sub("[^a-zA-Z0-9]","",re.sub("\([0-9]*\)","",label)) +def generateXdrMappings(fp,oh,inFile=''): + jdoc=json.load(fp) + oh.write("static GwXDRTypeMapping* typeMappings[]={\n") + first=True + for cat in jdoc: + item=jdoc[cat] + cid=item.get('id') + if cid is None: + continue + tc=item.get('type') + if tc is not None: + if first: + first=False + else: + oh.write(",\n") + oh.write(" new GwXDRTypeMapping(%d,0,%d) /*%s*/"%(cid,tc,cat)) + fields=item.get('fields') + if fields is None: + continue + idx=0 + for fe in fields: + if not isinstance(fe,dict): + continue + tc=fe.get('t') + id=fe.get('v') + if id is None: + id=idx + idx+=1 + l=fe.get('l') or '' + if tc is None or id is None: + continue + if first: + first=False + else: + oh.write(",\n") + oh.write(" new GwXDRTypeMapping(%d,%d,%d) /*%s:%s*/"%(cid,id,tc,cat,l)) + oh.write("\n") + oh.write("};\n") + for cat in jdoc: + item=jdoc[cat] + cid=item.get('id') + if cid is None: + continue + selectors=item.get('selector') + if selectors is not None: + for selector in selectors: + label=selector.get('l') + value=selector.get('v') + if label is not None and value is not None: + label=labelFilter(label) + define=("GWXDRSEL_%s_%s"%(cat,label)).upper() + oh.write(" #define %s %s\n"%(define,value)) + fields=item.get('fields') + if fields is not None: + idx=0 + for field in fields: + v=field.get('v') + if v is None: + v=idx + else: + v=int(v) + label=field.get('l') + if v is not None and label is not None: + define=("GWXDRFIELD_%s_%s"%(cat,labelFilter(label))).upper(); + oh.write(" #define %s %s\n"%(define,str(v))) + idx+=1 + +class Grove: + def __init__(self,name) -> None: + self.name=name + def _ss(self,z=False): + if z: + return self.name + return self.name if self.name is not 'Z' else '' + def _suffix(self): + return '_'+self.name if self.name is not 'Z' else '' + def replace(self,line): + if line is None: + return line + return line.replace('$G$',self._ss()).replace('$Z$',self._ss(True)).replace('$GS$',self._suffix()) +def generateGroveDefs(inh,outh,inFile=''): + GROVES=[Grove('Z'),Grove('A'),Grove('B'),Grove('C')] + definition=[] + started=False + def writeConfig(): + for grove in GROVES: + for cl in definition: + outh.write(grove.replace(cl)) + + for line in inh: + if re.match(" *#GROVE",line): + started=True + if len(definition) > 0: + writeConfig() + definition=[] + continue + if started: + definition.append(line) + if len(definition) > 0: + writeConfig() + + + +userTaskDirs=[] + +def getUserTaskDirs(): + rt=[] + taskdirs=glob.glob(os.path.join( basePath(),'lib','*task*')) + for task in taskdirs: + rt.append(task) + return rt + +def checkAndAdd(file,names,ilist): + if not file.endswith('.h'): + return + match=False + for cmp in names: + #print("##check %s<->%s"%(f.lower(),cmp)) + if file.lower() == cmp: + match=True + if not match: + return + ilist.append(file) +def genereateUserTasks(outfile): + includes=[] + for task in userTaskDirs: + #print("##taskdir=%s"%task) + base=os.path.basename(task) + includeNames=[base.lower()+".h",'gw'+base.lower()+'.h'] + for f in os.listdir(task): + checkAndAdd(f,includeNames,includes) + includeData="" + for i in includes: + print("#task include %s"%i) + includeData+="#include <%s>\n"%i + writeFileIfChanged(outfile,includeData) + +def generateEmbedded(elist,outFile): + content="" + for entry in elist: + content+="EMBED_GZ_FILE(\"%s\",%s,\"%s\");\n"%entry + writeFileIfChanged(outFile,content) + +def getContentType(fn): + if (fn.endswith('.gz')): + fn=fn[0:-3] + if (fn.endswith('html')): + return "text/html" + if (fn.endswith('json')): + return "application/json" + if (fn.endswith('js')): + return "text/javascript" + if (fn.endswith('css')): + return "text/css" + return "application/octet-stream" + + +def getLibs(): + base=os.path.join(basePath(),"lib") + rt=[] + for sd in os.listdir(base): + if sd == '..': + continue + if sd == '.': + continue + fn=os.path.join(base,sd) + if os.path.isdir(fn): + rt.append(sd) + EXTRAS=['generated'] + for e in EXTRAS: + if not e in rt: + rt.append(e) + return rt + + + +def joinFiles(target,pattern,dirlist): + flist=[] + for dir in dirlist: + fn=os.path.join(dir,pattern) + if os.path.exists(fn): + flist.append(fn) + current=False + if os.path.exists(target): + current=True + for f in flist: + if not isCurrent(f,target): + current=False + break + if current: + print("%s is up to date"%target) + return + print("creating %s"%target) + with gzip.open(target,"wb") as oh: + for fn in flist: + print("adding %s to %s"%(fn,target)) + with open(fn,"rb") as rh: + shutil.copyfileobj(rh,oh) + + +OWNLIBS=getLibs()+["FS","WiFi"] +GLOBAL_INCLUDES=[] + +def handleDeps(env): + #overwrite the GetProjectConfig + #to inject all our libs + oldGetProjectConfig=env.GetProjectConfig + def GetProjectConfigX(env): + rt=oldGetProjectConfig() + cenv="env:"+env['PIOENV'] + libs=[] + for section,options in rt.as_tuple(): + if section == cenv: + for key,values in options: + if key == 'lib_deps': + libs=values + + mustUpdate=False + for lib in OWNLIBS: + if not lib in libs: + libs.append(lib) + mustUpdate=True + if mustUpdate: + update=[(cenv,[('lib_deps',libs)])] + rt.update(update) + return rt + env.AddMethod(GetProjectConfigX,"GetProjectConfig") + #store the list of all includes after we resolved + #the dependencies for our main project + #we will use them for all compilations afterwards + oldLibBuilder=env.ConfigureProjectLibBuilder + def ConfigureProjectLibBuilderX(env): + global GLOBAL_INCLUDES + project=oldLibBuilder() + #print("##ConfigureProjectLibBuilderX") + #pprint.pprint(project) + if project.depbuilders: + #print("##depbuilders %s"%",".join(map(lambda x: x.path,project.depbuilders))) + for db in project.depbuilders: + idirs=db.get_include_dirs() + for id in idirs: + if not id in GLOBAL_INCLUDES: + GLOBAL_INCLUDES.append(id) + return project + env.AddMethod(ConfigureProjectLibBuilderX,"ConfigureProjectLibBuilder") + def injectIncludes(env,node): + return env.Object( + node, + CPPPATH=env["CPPPATH"]+GLOBAL_INCLUDES + ) + env.AddBuildMiddleware(injectIncludes) + + +def prebuild(env): + global userTaskDirs + print("#prebuild running") + if not checkDir(): + sys.exit(1) + ldf_mode=env.GetProjectOption("lib_ldf_mode") + if ldf_mode == 'off': + print("##ldf off - own dependency handling") + handleDeps(env) + userTaskDirs=getUserTaskDirs() + mergedConfig=os.path.join(outPath(),os.path.basename(CFG_FILE)) + generateMergedConfig(os.path.join(basePath(),CFG_FILE),mergedConfig,userTaskDirs) + compressFile(mergedConfig,mergedConfig+".gz") + generateCfg(mergedConfig,os.path.join(outPath(),CFG_INCLUDE),False) + generateCfg(mergedConfig,os.path.join(outPath(),CFG_INCLUDE_IMPL),True) + joinFiles(os.path.join(outPath(),INDEXJS+".gz"),INDEXJS,["web"]+userTaskDirs) + joinFiles(os.path.join(outPath(),INDEXCSS+".gz"),INDEXCSS,["web"]+userTaskDirs) + embedded=getEmbeddedFiles(env) + filedefs=[] + for ef in embedded: + print("#checking embedded file %s"%ef) + (dn,fn)=os.path.split(ef) + pureName=fn + if pureName.endswith('.gz'): + pureName=pureName[0:-3] + ct=getContentType(pureName) + usname=ef.replace('/','_').replace('.','_') + filedefs.append((pureName,usname,ct)) + inFile=os.path.join(basePath(),"web",pureName) + if os.path.exists(inFile): + compressFile(inFile,ef) + else: + print("#WARNING: infile %s for %s not found"%(inFile,ef)) + generateEmbedded(filedefs,os.path.join(outPath(),EMBEDDED_INCLUDE)) + genereateUserTasks(os.path.join(outPath(), TASK_INCLUDE)) + generateFile(os.path.join(basePath(),XDR_FILE),os.path.join(outPath(),XDR_INCLUDE),generateXdrMappings) + generateFile(os.path.join(basePath(),GROVE_CONFIG_IN),os.path.join(outPath(),GROVE_CONFIG),generateGroveDefs,inMode='r') + version="dev"+datetime.now().strftime("%Y%m%d") + env.Append(CPPDEFINES=[('GWDEVVERSION',version)]) + +def cleangenerated(source, target, env): + od=outPath() + if os.path.isdir(od): + print("#cleaning up %s"%od) + for f in os.listdir(od): + if f == "." or f == "..": + continue + fn=os.path.join(od,f) + os.unlink(f) + + +print("#prescript...") +prebuild(env) +board="PLATFORM_BOARD_%s"%env["BOARD"].replace("-","_").upper() +print("Board=#%s#"%board) +print("BuildFlags=%s"%(" ".join(env["BUILD_FLAGS"]))) +env.Append( + LINKFLAGS=[ "-u", "custom_app_desc" ], + CPPDEFINES=[(board,"1")] +) +#script does not run on clean yet - maybe in the future +env.AddPostAction("clean",cleangenerated) diff --git a/lib/obp60task/OBP60Extensions.h b/lib/obp60task/OBP60Extensions.h index b6f653f..5e0d953 100644 --- a/lib/obp60task/OBP60Extensions.h +++ b/lib/obp60task/OBP60Extensions.h @@ -100,8 +100,8 @@ void displayFooter(CommonData &commonData); SunData calcSunsetSunrise(GwApi *api, double time, double date, double latitude, double longitude, double timezone); // Calulate sunset and sunrise void batteryGraphic(uint x, uint y, float percent, int pcolor, int bcolor); // Battery graphic with fill level -void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic with fill level -void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic with fill level +void solarGraphic(uint x, uint y, int pcolor, int bcolor); // Solar graphic +void generatorGraphic(uint x, uint y, int pcolor, int bcolor); // Generator graphic void startLedTask(GwApi *api); void doImageRequest(GwApi *api, int *pageno, const PageStruct pages[MAX_PAGE_NUMBER], AsyncWebServerRequest *request); diff --git a/lib/obp60task/OBPSensorTask.cpp b/lib/obp60task/OBPSensorTask.cpp index cd488ab..9fb6d90 100644 --- a/lib/obp60task/OBPSensorTask.cpp +++ b/lib/obp60task/OBPSensorTask.cpp @@ -89,11 +89,11 @@ void sensorTask(void *param){ double vslope = (api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asString()).toFloat(); if(String(powsensor1) == "off"){ #ifdef VOLTAGE_SENSOR - sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 + float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 #else - sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 + float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 #endif - sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration + sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration #ifdef LIPO_ACCU_1200 sensors.BatteryChargeStatus = 0; // Set to discharging sensors.batteryLevelLiPo = 0; // Level 0...100% @@ -468,20 +468,14 @@ void sensorTask(void *param){ if(millis() > starttime5 + 1000 && String(powsensor1) == "off"){ starttime5 = millis(); #ifdef VOLTAGE_SENSOR - sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 + float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 #else - sensors.batteryVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 + float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 #endif - sensors.batteryVoltage = sensors.batteryVoltage * vslope + voffset; // Calibration + sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration #ifdef LIPO_ACCU_1200 - if(sensors.batteryVoltage > 4.1){ - sensors.BatteryChargeStatus = 1; // Charging active - } - else{ - sensors.BatteryChargeStatus = 0; // Discharging - } // Polynomfit for LiPo capacity calculation for 3,7V LiPo accus, 0...100% - sensors.batteryLevelLiPo = sensors.batteryVoltage * sensors.batteryVoltage * 174.9513 + sensors.batteryVoltage * 1147,7686 + 1868.5120; + sensors.batteryLevelLiPo = sensors.batteryVoltage * sensors.batteryVoltage * 174.9513 + sensors.batteryVoltage * 1147.7686 + 1868.5120; // Limiter if(sensors.batteryLevelLiPo > 100){ sensors.batteryLevelLiPo = 100; @@ -496,11 +490,28 @@ void sensorTask(void *param){ sensors.batteryVoltage10 = batV.getAvg(10) / 100.0; sensors.batteryVoltage60 = batV.getAvg(60) / 100.0; sensors.batteryVoltage300 = batV.getAvg(300) / 100.0; + // Charging detection + float deltaV = sensors.batteryVoltage - sensors.batteryVoltage10; + if(deltaV > 0.03){ + sensors.BatteryChargeStatus = 1; // Charging active + } + if(deltaV < -0.03){ + sensors.BatteryChargeStatus = 0; // Discharging + } + #ifdef BOARD_OBP40S3 + // Send to NMEA200 bus as instance 10 + if(!isnan(sensors.batteryVoltage)){ + SetN2kDCBatStatus(N2kMsg, 10, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 0); + api->sendN2kMessage(N2kMsg); + } + #endif + #ifdef BOARD_OBP60S3 // Send to NMEA200 bus if(!isnan(sensors.batteryVoltage)){ SetN2kDCBatStatus(N2kMsg, 0, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 1); api->sendN2kMessage(N2kMsg); } + #endif } // Send data from environment sensor all 2s diff --git a/lib/obp60task/PageVoltage.cpp b/lib/obp60task/PageVoltage.cpp index d05c903..fe1070b 100644 --- a/lib/obp60task/PageVoltage.cpp +++ b/lib/obp60task/PageVoltage.cpp @@ -205,6 +205,18 @@ public: getdisplay().setCursor(20, 100); getdisplay().print(name1); // Value name + #ifdef BOARD_OBP40S3 + // Show charge status + getdisplay().setFont(&Ubuntu_Bold8pt7b); + getdisplay().setCursor(185, 100); + if(commonData->data.BatteryChargeStatus == true){ + getdisplay().print("Charge"); + } + else{ + getdisplay().print("Discharge"); + } + #endif + // Show unit getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setCursor(270, 100); @@ -213,7 +225,12 @@ public: // Show battery type getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(295, 100); + #ifdef BOARD_OBP60S3 getdisplay().print(batType); + #endif + #ifdef BOARD_OBP40S3 + getdisplay().print("LiPo"); + #endif // Show average settings printAvg(average, 320, 84, true); diff --git a/lib/obp60task/config_obp40.json b/lib/obp60task/config_obp40.json index 3a4b6bf..888c746 100644 --- a/lib/obp60task/config_obp40.json +++ b/lib/obp60task/config_obp40.json @@ -609,10 +609,10 @@ "label": "Undervoltage", "type": "boolean", "default": "false", - "description": "Switch off device if voltage drops below 9V [on|off]", + "description": "Switch off device if LiPo voltage drops below 3.65V [on|off]", "category": "OBP40 Hardware", "capabilities": { - "obp40": "false" + "obp40":"true" } }, { diff --git a/lib/obp60task/obp60task.cpp b/lib/obp60task/obp60task.cpp index 51828e4..cad4867 100644 --- a/lib/obp60task/obp60task.cpp +++ b/lib/obp60task/obp60task.cpp @@ -309,30 +309,28 @@ void registerAllPages(PageList &list){ // Undervoltage detection for shutdown display void underVoltageDetection(GwApi *api, CommonData &common){ - float actVoltage = 0; - float minVoltage = 0; // Read settings float vslope = uint(api->getConfig()->getConfigItem(api->getConfig()->vSlope,true)->asFloat()); float voffset = uint(api->getConfig()->getConfigItem(api->getConfig()->vOffset,true)->asFloat()); // Read supply voltage #if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200 - actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 - minVoltage = 3.65; // Absolut minimum volatge for 3,7V LiPo accu + float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.53) * 2; // Vin = 1/2 for OBP40 + float minVoltage = 3.65; // Absolut minimum volatge for 3,7V LiPo accu #else - actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 - minVoltage = MIN_VOLTAGE; + float actVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 + float minVoltage = MIN_VOLTAGE; #endif - actVoltage = actVoltage * vslope + voffset; - if(actVoltage < minVoltage){ + float corrVoltage = actVoltage * vslope + voffset; // Calibration + if(corrVoltage < minVoltage){ #if defined VOLTAGE_SENSOR && defined LIPO_ACCU_1200 // Switch off all power lines setPortPin(OBP_BACKLIGHT_LED, false); // Backlight Off setFlashLED(false); // Flash LED Off buzzer(TONE4, 20); // Buzzer tone 4kHz 20ms // Shutdown EInk display - getdisplay().setFullWindow(); // Set full Refresh + getdisplay().setFullWindow(); // Set full Refresh //getdisplay().setPartialWindow(0, 0, getdisplay().width(), getdisplay().height()); // Set partial update - getdisplay().fillScreen(common.bgcolor); // Clear screen + getdisplay().fillScreen(common.bgcolor);// Clear screen getdisplay().setTextColor(common.fgcolor); getdisplay().setFont(&Ubuntu_Bold20pt7b); getdisplay().setCursor(65, 150); From 9dc857056b1d1dd1762e3e92178aba14144346a5 Mon Sep 17 00:00:00 2001 From: norbert-walter <norbert-walter@web.de> Date: Sat, 25 Jan 2025 18:04:58 +0100 Subject: [PATCH 17/17] Fix LiPo battery level and sensor pad --- lib/obp60task/OBP60Keypad.h | 4 ++-- lib/obp60task/OBPSensorTask.cpp | 22 ++++++++++------------ lib/obp60task/PageVoltage.cpp | 4 ++-- 3 files changed, 14 insertions(+), 16 deletions(-) diff --git a/lib/obp60task/OBP60Keypad.h b/lib/obp60task/OBP60Keypad.h index 937f44e..eafe3a2 100644 --- a/lib/obp60task/OBP60Keypad.h +++ b/lib/obp60task/OBP60Keypad.h @@ -277,8 +277,8 @@ void initKeys(CommonData &commonData) { starttime = millis(); // Start key pressed keycodeold = keycode; } - // If key pressed longer than 200ms - if(millis() > starttime + 200 && keycode == keycodeold) { + // If key pressed longer than 100ms + if(millis() > starttime + 100 && keycode == keycodeold) { if (use_syspage and keycode == 3) { keystatus = 12; } else { diff --git a/lib/obp60task/OBPSensorTask.cpp b/lib/obp60task/OBPSensorTask.cpp index 9fb6d90..cbbfa15 100644 --- a/lib/obp60task/OBPSensorTask.cpp +++ b/lib/obp60task/OBPSensorTask.cpp @@ -473,9 +473,15 @@ void sensorTask(void *param){ float rawVoltage = (float(analogRead(OBP_ANALOG0)) * 3.3 / 4096 + 0.17) * 20; // Vin = 1/20 for OBP60 #endif sensors.batteryVoltage = rawVoltage * vslope + voffset; // Calibration - #ifdef LIPO_ACCU_1200 + // Save new data in average array + batV.reading(int(sensors.batteryVoltage * 100)); + // Calculate the average values for different time lines from integer values + sensors.batteryVoltage10 = batV.getAvg(10) / 100.0; + sensors.batteryVoltage60 = batV.getAvg(60) / 100.0; + sensors.batteryVoltage300 = batV.getAvg(300) / 100.0; + #if defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR // Polynomfit for LiPo capacity calculation for 3,7V LiPo accus, 0...100% - sensors.batteryLevelLiPo = sensors.batteryVoltage * sensors.batteryVoltage * 174.9513 + sensors.batteryVoltage * 1147.7686 + 1868.5120; + sensors.batteryLevelLiPo = sensors.batteryVoltage60 * 203.8312 -738.1635; // Limiter if(sensors.batteryLevelLiPo > 100){ sensors.batteryLevelLiPo = 100; @@ -483,22 +489,14 @@ void sensorTask(void *param){ if(sensors.batteryLevelLiPo < 0){ sensors.batteryLevelLiPo = 0; } - #endif - // Save new data in average array - batV.reading(int(sensors.batteryVoltage * 100)); - // Calculate the average values for different time lines from integer values - sensors.batteryVoltage10 = batV.getAvg(10) / 100.0; - sensors.batteryVoltage60 = batV.getAvg(60) / 100.0; - sensors.batteryVoltage300 = batV.getAvg(300) / 100.0; // Charging detection float deltaV = sensors.batteryVoltage - sensors.batteryVoltage10; - if(deltaV > 0.03){ + if(deltaV > 0.045){ sensors.BatteryChargeStatus = 1; // Charging active } - if(deltaV < -0.03){ + if(deltaV < -0.04){ sensors.BatteryChargeStatus = 0; // Discharging } - #ifdef BOARD_OBP40S3 // Send to NMEA200 bus as instance 10 if(!isnan(sensors.batteryVoltage)){ SetN2kDCBatStatus(N2kMsg, 10, sensors.batteryVoltage, N2kDoubleNA, N2kDoubleNA, 0); diff --git a/lib/obp60task/PageVoltage.cpp b/lib/obp60task/PageVoltage.cpp index fe1070b..c98bc96 100644 --- a/lib/obp60task/PageVoltage.cpp +++ b/lib/obp60task/PageVoltage.cpp @@ -205,7 +205,7 @@ public: getdisplay().setCursor(20, 100); getdisplay().print(name1); // Value name - #ifdef BOARD_OBP40S3 + #if defined BOARD_OBP40S3 && defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR // Show charge status getdisplay().setFont(&Ubuntu_Bold8pt7b); getdisplay().setCursor(185, 100); @@ -228,7 +228,7 @@ public: #ifdef BOARD_OBP60S3 getdisplay().print(batType); #endif - #ifdef BOARD_OBP40S3 + #if defined BOARD_OBP40S3 && defined LIPO_ACCU_1200 && defined VOLTAGE_SENSOR getdisplay().print("LiPo"); #endif