From 25f31c7811ce98dbf4d41cf7af0e8ac9299de9c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Kolac=C3=AD?= Date: Mon, 28 Dec 2020 13:10:49 +0100 Subject: [PATCH] SleepMode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin KolacĂ­ --- Board320_240.cpp | 146 ++++++++++++++++++++++++++++++++++++++------ Board320_240.h | 5 ++ BoardInterface.cpp | 4 +- CarHyundaiIoniq.cpp | 8 +-- CarKiaEniro.cpp | 11 ++-- CommInterface.cpp | 5 ++ CommObd2Can.cpp | 1 + LiveData.cpp | 1 - LiveData.h | 4 +- SIM800L.cpp | 13 ++++ SIM800L.h | 2 + config.h | 2 +- evDash.ino | 6 +- menu.h | 2 +- 14 files changed, 170 insertions(+), 40 deletions(-) diff --git a/Board320_240.cpp b/Board320_240.cpp index c7dbd0c..6a3a145 100644 --- a/Board320_240.cpp +++ b/Board320_240.cpp @@ -11,6 +11,8 @@ #include #include "SIM800L.h" +RTC_DATA_ATTR int bootCount = 0; + /** Init board */ @@ -29,6 +31,29 @@ void Board320_240::initBoard() { getLocalTime(&now, 0); liveData->params.chargingStartTime = liveData->params.currentTime = mktime(&now); + ++bootCount; + syslog->print("Boot count: "); + syslog->println(bootCount); +} + +/** + After setup device +*/ +void Board320_240::afterSetup() { + + if (digitalRead(pinButtonRight) == LOW) { + loadTestData(); + } + + // Init from parent class + syslog->println("BoardInterface::afterSetup"); + BoardInterface::afterSetup(); + + // Check if bard was sleeping + if(bootCount > 1) { + afterSleep(); + } + // Init display syslog->println("Init tft display"); tft.begin(); @@ -44,12 +69,6 @@ void Board320_240::initBoard() { #endif spr.setColorDepth((psramUsed) ? 16 : 8); spr.createSprite(320, 240); -} - -/** - After setup device -*/ -void Board320_240::afterSetup() { // Show test data on right button during boot device displayScreen = liveData->settings.defaultScreen; @@ -63,7 +82,6 @@ void Board320_240::afterSetup() { /*syslog->print("memReport(): MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM bytes free. "); syslog->println(heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM)); - syslog->println("WiFi init..."); WiFi.enableSTA(true); WiFi.mode(WIFI_STA); @@ -96,10 +114,73 @@ void Board320_240::afterSetup() { if (liveData->settings.gprsHwSerialPort <= 2) { sim800lSetup(); } +} - // Init from parent class - syslog->println("BoardInterface::afterSetup"); - BoardInterface::afterSetup(); +/** + Go to Sleep for TIME_TO_SLEEP seconds +*/ +void Board320_240::goToSleep() { + //Sleep MCP2515 + commInterface->disconnectDevice(); + + //Sleep SIM800L + if(liveData->params.sim800l_enabled) { + if (sim800l->isConnectedGPRS()) { + bool disconnected = sim800l->disconnectGPRS(); + for(uint8_t i = 0; i < 5 && !disconnected; i++) { + delay(1000); + disconnected = sim800l->disconnectGPRS(); + } + } + + if(sim800l->getPowerMode() == NORMAL) { + sim800l->setPowerMode(SLEEP); + delay(1000); + } + sim800l->enterSleepMode(); + } + + syslog->println("Going to sleep for " + String(TIME_TO_SLEEP) + " seconds!"); + syslog->flush(); + + delay(1000); + + //Sleep ESP32 + esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * 1000000ULL); + esp_deep_sleep_start(); +} + +/* + Wake up board from sleep + Iterate thru commands and determine if car is charging or ignition is on +*/ +void Board320_240::afterSleep() { + syslog->println("Waking up from sleep mode!"); + + bool firstRun = true; + + while(liveData->commandQueueIndex -1 > liveData->commandQueueLoopFrom || firstRun) { + if(liveData->commandQueueIndex -1 == liveData->commandQueueLoopFrom) { + firstRun = false; + } + + if(millis() > 5000) { + syslog->println("Time's up (5s timeout)..."); + goToSleep(); + } + + commInterface->mainLoop(); + } + + if(liveData->params.auxVoltage < 12) { + syslog->println("AuxBATT too low!"); + goToSleep(); + } else if(!liveData->params.ignitionOn && !liveData->params.chargingOn) { + syslog->println("Not started & Not charging."); + goToSleep(); + } else { + syslog->println("Wake up conditions satisfied... Good morning!"); + } } /** @@ -895,7 +976,7 @@ String Board320_240::menuItemCaption(int16_t menuItemId, String title) { case MENU_SCREEN_BRIGHTNESS: sprintf(tmpStr1, "[%d%%]", liveData->settings.lcdBrightness); suffix = (liveData->settings.lcdBrightness == 0) ? "[auto]" : tmpStr1; break; case MENU_PREDRAWN_GRAPHS: suffix = (liveData->settings.predrawnChargingGraphs == 1) ? "[on]" : "[off]"; break; case MENU_HEADLIGHTS_REMINDER: suffix = (liveData->settings.headlightsReminder == 1) ? "[on]" : "[off]"; break; - case MENU_DEBUG_SCREEN: suffix = (liveData->settings.debugScreen == 1) ? "[on]" : "[off]"; break; + case MENU_SLEEP_MODE: suffix = (liveData->settings.sleepModeEnabled == 1) ? "[on]" : "[off]"; break; case MENU_GPS: sprintf(tmpStr1, "[HW UART=%d]", liveData->settings.gpsHwSerialPort); suffix = (liveData->settings.gpsHwSerialPort == 255) ? "[off]" : tmpStr1; break; // case MENU_SDCARD_ENABLED: sprintf(tmpStr1, "[%s]", (liveData->settings.sdcardEnabled == 1) ? "on" : "off"); suffix = tmpStr1; break; @@ -1045,7 +1126,7 @@ void Board320_240::menuItemClick() { case 3064: liveData->settings.defaultScreen = 4; showParentMenu = true; break; case 3065: liveData->settings.defaultScreen = 5; showParentMenu = true; break; // Debug screen off/on - case MENU_DEBUG_SCREEN: liveData->settings.debugScreen = (liveData->settings.debugScreen == 1) ? 0 : 1; showMenu(); return; break; + case MENU_SLEEP_MODE: liveData->settings.sleepModeEnabled = (liveData->settings.sleepModeEnabled == 1) ? 0 : 1; showMenu(); return; break; case MENU_SCREEN_BRIGHTNESS: liveData->settings.lcdBrightness += 20; if (liveData->settings.lcdBrightness > 100) liveData->settings.lcdBrightness = 0; setBrightness((liveData->settings.lcdBrightness == 0) ? 100 : liveData->settings.lcdBrightness); showMenu(); return; break; // Pre-drawn charg.graphs off/on @@ -1300,7 +1381,7 @@ void Board320_240::mainLoop() { menuMove(false); } else { displayScreen++; - if (displayScreen > displayScreenCount - (liveData->settings.debugScreen == 0) ? 1 : 0) + if (displayScreen > displayScreenCount - 1) displayScreen = 0; // rotate screens // Turn off display on screen 0 setBrightness((displayScreen == SCREEN_BLANK) ? 0 : (liveData->settings.lcdBrightness == 0) ? 100 : liveData->settings.lcdBrightness); @@ -1392,9 +1473,21 @@ void Board320_240::mainLoop() { } } - // Shutdown when car is off - if (liveData->params.automaticShutdownTimer != 0 && liveData->params.currentTime - liveData->params.automaticShutdownTimer > 5) - shutdownDevice(); + // Turn off display if Ignition is off for more than 10s + if(liveData->params.currentTime - liveData->params.lastIgnitionOnTime > 10 + && liveData->params.lastIgnitionOnTime != 0 + && liveData->settings.sleepModeEnabled) { + setBrightness(0); + } else { + setBrightness((liveData->settings.lcdBrightness == 0) ? 100 : liveData->settings.lcdBrightness); + } + + // Go to sleep when car is off for more than 10s and not charging + if (liveData->params.currentTime - liveData->params.lastIgnitionOnTime > 10 + && !liveData->params.chargingOn + && liveData->params.lastIgnitionOnTime != 0 + && liveData->settings.sleepModeEnabled) + goToSleep(); // Read data from BLE/CAN commInterface->mainLoop(); @@ -1534,9 +1627,9 @@ bool Board320_240::sim800lSetup() { gprsHwUart = new HardwareSerial(liveData->settings.gprsHwSerialPort); gprsHwUart->begin(9600); - sim800l = new SIM800L((Stream *)gprsHwUart, SIM800L_RST, 512 , 512); + sim800l = new SIM800L((Stream *)gprsHwUart, SIM800L_RST, 768 , 128); // SIM800L DebugMode: - //sim800l = new SIM800L((Stream *)gprsHwUart, SIM800L_RST, 512 , 512, (Stream *)&Serial); + //sim800l = new SIM800L((Stream *)gprsHwUart, SIM800L_RST, 768 , 128, (Stream *)&Serial); bool sim800l_ready = sim800l->isReady(); for (uint8_t i = 0; i < 5 && !sim800l_ready; i++) { @@ -1550,6 +1643,17 @@ bool Board320_240::sim800lSetup() { } else { syslog->println("SIM800L module initialized"); + sim800l->exitSleepMode(); + + if(sim800l->getPowerMode() != NORMAL) { + syslog->println("SIM800L module in sleep mode - Waking up"); + if(sim800l->setPowerMode(NORMAL)) { + syslog->println("SIM800L in normal power mode"); + } else { + syslog->println("Failed to switch SIM800L to normal power mode"); + } + } + syslog->print("Setting GPRS APN to: "); syslog->println(liveData->settings.gprsApn); @@ -1606,10 +1710,12 @@ bool Board320_240::sendDataViaGPRS() { syslog->println("Start HTTP POST..."); - StaticJsonDocument<512> jsonData; + StaticJsonDocument<768> jsonData; jsonData["apikey"] = liveData->settings.remoteApiKey; jsonData["carType"] = liveData->settings.carType; + jsonData["ignitionOn"] = liveData->params.ignitionOn; + jsonData["chargingOn"] = liveData->params.chargingOn; jsonData["socPerc"] = liveData->params.socPerc; jsonData["sohPerc"] = liveData->params.sohPerc; jsonData["batPowerKw"] = liveData->params.batPowerKw; @@ -1626,7 +1732,7 @@ bool Board320_240::sendDataViaGPRS() { jsonData["cumulativeEnergyChargedKWh"] = liveData->params.cumulativeEnergyChargedKWh; jsonData["cumulativeEnergyDischargedKWh"] = liveData->params.cumulativeEnergyDischargedKWh; - char payload[512]; + char payload[768]; serializeJson(jsonData, payload); syslog->print("Sending payload: "); diff --git a/Board320_240.h b/Board320_240.h index 1d7377d..3cd563b 100644 --- a/Board320_240.h +++ b/Board320_240.h @@ -11,6 +11,9 @@ #define SMOOTH_FONT #define GFXFF 1 // TFT FOnts +// DEEP SLEEP +#define TIME_TO_SLEEP 60 // Sleep time in secs + // #include #include @@ -49,6 +52,8 @@ class Board320_240 : public BoardInterface { void afterSetup() override; void mainLoop() override; bool skipAdapterScan() override; + void goToSleep(); + void afterSleep(); // SD card bool sdcardMount() override; void sdcardToggleRecording() override; diff --git a/BoardInterface.cpp b/BoardInterface.cpp index 158566e..c710f78 100644 --- a/BoardInterface.cpp +++ b/BoardInterface.cpp @@ -112,7 +112,7 @@ void BoardInterface::loadSettings() { liveData->settings.pressureUnit = 'b'; liveData->settings.defaultScreen = 1; liveData->settings.lcdBrightness = 0; - liveData->settings.debugScreen = 0; + liveData->settings.sleepModeEnabled = 0; liveData->settings.predrawnChargingGraphs = 1; liveData->settings.commType = COMM_TYPE_OBD2BLE4; // BLE4 liveData->settings.wifiEnabled = 0; @@ -161,7 +161,7 @@ void BoardInterface::loadSettings() { liveData->tmpSettings.settingsVersion = 2; liveData->tmpSettings.defaultScreen = liveData->settings.defaultScreen; liveData->tmpSettings.lcdBrightness = liveData->settings.lcdBrightness; - liveData->tmpSettings.debugScreen = liveData->settings.debugScreen; + liveData->tmpSettings.sleepModeEnabled = liveData->settings.sleepModeEnabled; } if (liveData->tmpSettings.settingsVersion == 2) { liveData->tmpSettings.settingsVersion = 3; diff --git a/CarHyundaiIoniq.cpp b/CarHyundaiIoniq.cpp index cb95d9d..68b680d 100644 --- a/CarHyundaiIoniq.cpp +++ b/CarHyundaiIoniq.cpp @@ -106,9 +106,7 @@ void CarHyundaiIoniq::parseRowMerged() { if (liveData->params.ignitionOn) { liveData->params.lastIgnitionOnTime = liveData->params.currentTime; } - int32_t secDiff = liveData->params.currentTime - liveData->params.currentTime; - if (liveData->commConnected && secDiff > 30 && secDiff < MONTH_SEC && !liveData->params.ignitionOn && !liveData->params.chargingOn) - liveData->params.automaticShutdownTimer = liveData->params.currentTime; + tempByte = liveData->hexToDecFromResponse(18, 20, 1, false); liveData->params.headLights = (bitRead(tempByte, 5) == 1); liveData->params.dayLights = (bitRead(tempByte, 3) == 1); @@ -185,8 +183,8 @@ void CarHyundaiIoniq::parseRowMerged() { //liveData->params.batMaxC = liveData->hexToDecFromResponse(32, 34, 1, true); //liveData->params.batMinC = liveData->hexToDecFromResponse(34, 36, 1, true); - tempByte = liveData->hexToDecFromResponse(104, 106, 1, false); - liveData->params.chargingOn = (bitRead(tempByte, 2) == 0); + tempByte = liveData->hexToDecFromResponse(22, 24, 1, false); + liveData->params.chargingOn = (bitRead(tempByte, 5) == 1 || bitRead(tempByte, 6) == 1); // bit 5 = AC; bit 6 = DC // This is more accurate than min/max from BMS. It's required to detect kona/eniro cold gates (min 15C is needed > 43kW charging, min 25C is needed > 58kW charging) liveData->params.batInletC = liveData->hexToDecFromResponse(48, 50, 1, true); diff --git a/CarKiaEniro.cpp b/CarKiaEniro.cpp index 6cdc2d9..8355f9f 100644 --- a/CarKiaEniro.cpp +++ b/CarKiaEniro.cpp @@ -128,9 +128,6 @@ void CarKiaEniro::parseRowMerged() { liveData->params.lastIgnitionOnTime = liveData->params.currentTime; } - int32_t secDiff = liveData->params.currentTime - liveData->params.currentTime; - if (liveData->commConnected && secDiff > 30 && secDiff < MONTH_SEC && !liveData->params.ignitionOn && !liveData->params.chargingOn) - liveData->params.automaticShutdownTimer = liveData->params.currentTime; tempByte = liveData->hexToDecFromResponse(18, 20, 1, false); liveData->params.headLights = (bitRead(tempByte, 5) == 1); liveData->params.dayLights = (bitRead(tempByte, 3) == 1); @@ -234,8 +231,12 @@ void CarKiaEniro::parseRowMerged() { //liveData->params.batTempC = liveData->hexToDecFromResponse(36, 38, 1, true); //liveData->params.batMaxC = liveData->hexToDecFromResponse(34, 36, 1, true); //liveData->params.batMinC = liveData->hexToDecFromResponse(36, 38, 1, true); - tempByte = liveData->hexToDecFromResponse(106, 108, 1, false); - liveData->params.chargingOn = (bitRead(tempByte, 2) == 1); + + // Ignition Off/on + // tempByte = liveData->hexToDecFromResponse(106, 108, 1, false); + // liveData->params.chargingOn = (bitRead(tempByte, 2) == 1); + tempByte = liveData->hexToDecFromResponse(24, 26, 1, false); + liveData->params.chargingOn = (bitRead(tempByte, 5) == 1 || bitRead(tempByte, 6) == 1); // bit 5 = AC; bit 6 = DC // This is more accurate than min/max from BMS. It's required to detect kona/eniro cold gates (min 15C is needed > 43kW charging, min 25C is needed > 58kW charging) liveData->params.batMinC = liveData->params.batMaxC = liveData->params.batModuleTempC[0]; diff --git a/CommInterface.cpp b/CommInterface.cpp index eaf7bd9..b91fbfd 100644 --- a/CommInterface.cpp +++ b/CommInterface.cpp @@ -32,6 +32,11 @@ void CommInterface::mainLoop() { } } + // Drop ChargingOn when status was not updated for more than 10 seconds + if(liveData->params.currentTime - liveData->params.lastChargingOnTime > 10 && liveData->params.chargingOn) { + liveData->params.chargingOn = false; + } + // Can send next command from queue to OBD if (liveData->canSendNextAtCommand) { liveData->canSendNextAtCommand = false; diff --git a/CommObd2Can.cpp b/CommObd2Can.cpp index 6910baa..650b119 100644 --- a/CommObd2Can.cpp +++ b/CommObd2Can.cpp @@ -60,6 +60,7 @@ void CommObd2Can::connectDevice() { void CommObd2Can::disconnectDevice() { liveData->commConnected = false; + CAN->setMode(MCP_SLEEP); syslog->println("COMM disconnectDevice"); } diff --git a/LiveData.cpp b/LiveData.cpp index 87e1a7e..172709a 100644 --- a/LiveData.cpp +++ b/LiveData.cpp @@ -15,7 +15,6 @@ void debug(String msg, uint8_t debugLevel) { */ void LiveData::initParams() { - params.automaticShutdownTimer = 0; // SIM params.lastDataSent = 0; params.sim800l_enabled = false; diff --git a/LiveData.h b/LiveData.h index a392484..dfb801f 100644 --- a/LiveData.h +++ b/LiveData.h @@ -45,7 +45,6 @@ typedef struct { // System time_t currentTime; time_t chargingStartTime; - time_t automaticShutdownTimer; // SIM time_t lastDataSent; bool sim800l_enabled; @@ -63,6 +62,7 @@ typedef struct { bool ignitionOn; bool chargingOn; time_t lastIgnitionOnTime; + time_t lastChargingOnTime; uint64_t operationTimeSec; bool sdcardCanNotify; bool forwardDriveMode; @@ -175,7 +175,7 @@ typedef struct { // ================================= byte defaultScreen; // 1 .. 6 byte lcdBrightness; // 0 - auto, 1 .. 100% - byte debugScreen; // 0 - off, 1 - on + byte sleepModeEnabled; // 0 - off, 1 - on byte predrawnChargingGraphs; // 0 - off, 1 - on // === settings version 4 // ================================= diff --git a/SIM800L.cpp b/SIM800L.cpp index d79eda8..e17e4f2 100644 --- a/SIM800L.cpp +++ b/SIM800L.cpp @@ -45,6 +45,9 @@ const char AT_CMD_CFUN0[] PROGMEM = "AT+CFUN=0"; // const char AT_CMD_CFUN1[] PROGMEM = "AT+CFUN=1"; // Switch normal power mode const char AT_CMD_CFUN4[] PROGMEM = "AT+CFUN=4"; // Switch sleep power mode +const char AC_CMD_CSCLK0[] PROGMEM = "AT+CSCLK=0"; // AT+CSCLK=0 command +const char AC_CMD_CSCLK2[] PROGMEM = "AT+CSCLK=2"; // AT+CSCLK=2 command + const char AT_CMD_CREG_TEST[] PROGMEM = "AT+CREG?"; // Check the network registration status const char AT_CMD_SAPBR_GPRS[] PROGMEM = "AT+SAPBR=3,1,\"Contype\",\"GPRS\""; // Configure the GPRS bearer const char AT_CMD_SAPBR_APN[] PROGMEM = "AT+SAPBR=3,1,\"APN\","; // Configure the APN for the GPRS @@ -721,6 +724,16 @@ bool SIM800L::setPowerMode(PowerMode powerMode) { return currentPowerMode == powerMode; } +void SIM800L::exitSleepMode() { + sendCommand_P(AC_CMD_CSCLK0); + purgeSerial(); +} + +void SIM800L::enterSleepMode() { + sendCommand_P(AC_CMD_CSCLK2); + purgeSerial(); +} + /** * Status function: Check the strengh of the signal */ diff --git a/SIM800L.h b/SIM800L.h index d49597c..8845855 100644 --- a/SIM800L.h +++ b/SIM800L.h @@ -66,6 +66,8 @@ class SIM800L { // Define the power mode (for parameter: see PowerMode enum) bool setPowerMode(PowerMode powerMode); + void enterSleepMode(); + void exitSleepMode(); // Enable/disable GPRS bool setupGPRS(const char *apn); diff --git a/config.h b/config.h index c23500b..bb68689 100644 --- a/config.h +++ b/config.h @@ -79,7 +79,7 @@ typedef struct { #define MENU_PREDRAWN_GRAPHS 308 #define MENU_REMOTE_UPLOAD 309 #define MENU_HEADLIGHTS_REMINDER 310 -#define MENU_DEBUG_SCREEN 311 +#define MENU_SLEEP_MODE 311 #define MENU_GPS 312 #define MENU_SERIAL_CONSOLE 313 #define MENU_DEBUG_LEVEL 314 diff --git a/evDash.ino b/evDash.ino index 7488245..9c8ff5b 100644 --- a/evDash.ino +++ b/evDash.ino @@ -117,12 +117,12 @@ void setup(void) { car->activateCommandQueue(); board->attachCar(car); - // Redraw screen - board->redrawScreen(); - // Finish board setup board->afterSetup(); + // Redraw screen + board->redrawScreen(); + // End syslog->println("Device setup completed"); } diff --git a/menu.h b/menu.h index 7fe7ad1..8bf67cb 100644 --- a/menu.h +++ b/menu.h @@ -45,7 +45,7 @@ MENU_ITEM menuItemsSource[100] = { {MENU_SCREEN_BRIGHTNESS, 3, -1, "LCD brightness"}, {MENU_PREDRAWN_GRAPHS, 3, -1, "Pre-drawn ch.graphs"}, {MENU_HEADLIGHTS_REMINDER, 3, -1, "Headlight reminder"}, -// {MENU_DEBUG_SCREEN, 3, -1, "Debug screen"}, + {MENU_SLEEP_MODE, 3, -1, "Debug screen"}, /* // NTP