1010 - WiFiManager: https://github.com/tzapu/WiFiManager
1111 - ArduinoMqttClient (if MQTT is defined)
1212*/
13- #define VERSION " v5.6 "
13+ #define VERSION " v5.7 "
1414
1515#define HEIGHT_ABOVE_SEA_LEVEL 50 // Berlin
1616#define TZ_DATA " CET-1CEST,M3.5.0,M10.5.0/3" // Europe/Berlin time zone from https://github.com/nayarsystems/posix_tz_db/blob/master/zones.csv
1717#define LIGHT_SLEEP_TIME 500
18- #define DEEP_SLEEP_TIME 29124
18+ #define DEEP_SLEEP_TIME 29124 // 30 sec
19+ #define LOW_ENERGY_DEEP_SLEEP_TIME 287924 // 5 min
1920#define DEEP_SLEEP_TIME_NO_DISPLAY_UPDATE DEEP_SLEEP_TIME + 965 // offset for no display update
2021static unsigned long lastMeasurementTimeMs = 0 ;
2122
@@ -86,7 +87,7 @@ SensirionI2cScd4x scd4x;
8687USBMSC usbmsc;
8788
8889RTC_DATA_ATTR bool USB_ACTIVE = false , initDone = false , BatteryMode = false , comingFromDeepSleep = false ;
89- RTC_DATA_ATTR bool LEDonBattery, LEDonUSB, useSmoothLEDcolor, invertDisplay, useFahrenheit, useWiFi, english;
90+ RTC_DATA_ATTR bool LEDonBattery, LEDonUSB, useSmoothLEDcolor, invertDisplay, useFahrenheit, useWiFi, lowEnergyMode, english;
9091RTC_DATA_ATTR uint8_t ledbrightness, HWSubRev, font;
9192RTC_DATA_ATTR float maxBatteryVoltage;
9293
@@ -196,7 +197,7 @@ void HandleRootClient() {
196197 message += " <div id='CO2Plot' style='width:100%;max-width:1400px'></div>\n " ;
197198 message += " <div id='TempHumPlot' style='width:100%;max-width:1400px'></div>\n " ;
198199
199- message += " <a href='https://github.com/davidkreidler/OpenCO2_Sensor/releases'>Installed Version: " ;
200+ message += " <a target='_blank' rel='noopener noreferrer' href='https://github.com/davidkreidler/OpenCO2_Sensor/releases'>Installed Version: " ;
200201 message += VERSION;
201202 message += " </a>\n " ;
202203 message += " <script>\n " ;
@@ -236,8 +237,8 @@ void HandleRootClient() {
236237 server.sendContent (Buffer);
237238
238239 message = " ];\n " ;
239- message += " const data = [{x:times, y:yValues, mode:'lines'}];\n " ;
240- message += " const layout = {yaxis: { title: 'CO2 (ppm)'} , title: 'History', plot_bgcolor:'black', paper_bgcolor:'black'};\n " ;
240+ message += " const data = [{x:times, y:yValues, mode:'lines', fill: 'tonexty', fillcolor: 'rgba(0, 100, 00, 0.3)', line: {color: '#006400'} }];\n " ;
241+ message += " const layout = {yaxis: {range: [Math.min(...data[0].y), Math.max(...data[0].y) * 1.05], title: {text: 'CO2 (ppm)', font: { color: '#006400',size: 20}}} , title: {text: 'History', font: { color: '#808080', size: 40}} , plot_bgcolor:'black', paper_bgcolor:'black'};\n " ;
241242 message += " Plotly.newPlot('CO2Plot', data, layout);\n " ;
242243 server.sendContent (message);
243244
@@ -268,10 +269,9 @@ void HandleRootClient() {
268269
269270 message = " ];\n const numPoints2 = " + String (index) + " ;\n " ;
270271 message += " let times2 = generateValues(startTime, endTime, numPoints2).map(time => new Date(time));\n " ;
271- message += " const data2 = [{x: times2, y: y1Values, name: 'Temperature', mode:'lines'}, " ;
272- message += " {x: times2, y: y2Values, name: 'Humidity', yaxis: 'y2', mode:'lines'}];\n " ;
273- message += " const layout2 = { showlegend: false, yaxis: {title: 'Temperature (" + String (useFahrenheit? " *F" : " *C" ) ;
274- message += " )'}, yaxis2: { title: 'Humidity (%)', overlaying: 'y', side: 'right'}, plot_bgcolor:'black', paper_bgcolor:'black'};\n " ;
272+ message += " const data2 = [{x: times2, y: y1Values, name: 'Temperature', line: { color: '#FF4500' }, mode:'lines'}, {x: times2, y: y2Values, name: 'Humidity', line: { color: '#1E90FF' }, yaxis: 'y2', mode:'lines'}];\n " ;
273+ message += " const layout2 = { showlegend: false, yaxis: {title: {text: 'Temperature (*" + String (useFahrenheit? " F" : " C" );
274+ message += " )', font: { color: '#FF4500',size: 20}}}, yaxis2: {title: {text: 'Humidity (%)', font: { color: '#1E90FF',size: 20}}, overlaying: 'y', side: 'right'}, plot_bgcolor:'black', paper_bgcolor:'black'};\n " ;
275275 message += " Plotly.newPlot('TempHumPlot', data2, layout2);\n " ;
276276
277277 message += " </script>\n </body>\n </html>\n " ;
@@ -322,8 +322,13 @@ void loadCredentials() {
322322#endif /* MQTT */
323323
324324float getTempOffset () {
325- if (useWiFi) return 12.2 ;
326- else return 4.4 ;
325+ if (!BatteryMode) {
326+ if (useWiFi) return 12.2 ;
327+ return 4.4 ;
328+ } else {
329+ if (lowEnergyMode) return 0.0 ;
330+ return 0.8 ;
331+ }
327332}
328333
329334void initOnce () {
@@ -358,6 +363,7 @@ void initOnce() {
358363 preferences.begin (" co2-sensor" , true );
359364 maxBatteryVoltage = preferences.getFloat (" MBV" , 3.95 );
360365 useWiFi = preferences.getBool (" WiFi" , false );
366+ lowEnergyMode = preferences.getBool (" lowEnergy" , false );
361367 LEDonBattery = preferences.getBool (" LEDonBattery" , false );
362368 LEDonUSB = preferences.getBool (" LEDonUSB" , true );
363369 ledbrightness = preferences.getInt (" ledbrightness" , 5 );
@@ -375,7 +381,7 @@ void initOnce() {
375381 scd4x.setSensorAltitude (HEIGHT_ABOVE_SEA_LEVEL);
376382 scd4x.setAutomaticSelfCalibrationEnabled (1 ); // Or use setAutomaticSelfCalibrationTarget if needed
377383 scd4x.setTemperatureOffset (getTempOffset ());
378- scd4x.startPeriodicMeasurement ();
384+ if (!(BatteryMode && lowEnergyMode)) scd4x.startPeriodicMeasurement ();
379385
380386 displayInit ();
381387 delay (3000 ); // Wait for co2 measurement
@@ -820,29 +826,56 @@ void loop() {
820826 goto_light_sleep (5000 - (millis () - lastMeasurementTimeMs));
821827 }
822828
823- bool isDataReady = false ;
824- uint16_t ready_error = scd4x.getDataReadyStatus (isDataReady);
825- if (ready_error || !isDataReady) {
826- if (BatteryMode && comingFromDeepSleep) goto_deep_sleep (DEEP_SLEEP_TIME/2 );
827- else goto_light_sleep (LIGHT_SLEEP_TIME/2 );
828- return ; // otherwise continues running!
829+ if (!(BatteryMode && lowEnergyMode)) {
830+ bool isDataReady = false ;
831+ uint16_t ready_error = scd4x.getDataReadyStatus (isDataReady);
832+ if (ready_error || !isDataReady) {
833+ if (BatteryMode && comingFromDeepSleep) goto_deep_sleep (DEEP_SLEEP_TIME/2 );
834+ else goto_light_sleep (LIGHT_SLEEP_TIME/2 );
835+ return ; // otherwise continues running!
836+ }
829837 }
830838
831839 // Read co2 measurement
832- uint16_t new_co2 = 400 ;
840+ uint16_t new_co2 = 420 ;
833841 float new_temperature = 0 .0f ;
834- uint16_t error = scd4x.readMeasurement (new_co2, new_temperature, humidity);
842+ uint16_t error;
843+ if (BatteryMode && lowEnergyMode) {
844+ scd4x.stopPeriodicMeasurement ();
845+ scd4x.wakeUp ();
846+ scd4x.setTemperatureOffset (getTempOffset ());
847+ // delay(10);
848+ scd4x.measureSingleShot (); // Ignore first measurement after wake up.
849+ error = scd4x.measureAndReadSingleShot (new_co2, new_temperature, humidity);
850+ scd4x.powerDown ();
851+ } else {
852+ error = scd4x.readMeasurement (new_co2, new_temperature, humidity);
853+ }
835854 lastMeasurementTimeMs = millis ();
836855 if (error) {
837- char errorMessage[256 ];
838- errorToString (error, errorMessage, 256 );
839- displayWriteError (errorMessage);
856+ if (TEST_MODE) {
857+ char errorMessage[256 ];
858+ errorToString (error, errorMessage, 256 );
859+ displayWriteError (errorMessage);
860+ } else { // retry
861+ goto_light_sleep (LIGHT_SLEEP_TIME/2 );
862+ return ;
863+ }
840864 } else {
841865 extern uint16_t refreshes;
842- if (BatteryMode || (refreshes % 6 == 1 )) saveMeasurement (new_co2, new_temperature, humidity);
843- /* don't update in Battery mode, unless CO2 has changed by 3% or temperature by 0.5°C */
866+ if (BatteryMode || (refreshes % 6 == 1 )) {
867+ saveMeasurement (new_co2, new_temperature, humidity);
868+
869+ if (BatteryMode && lowEnergyMode) { // fill measurements of past 5 min
870+ for (int i=0 ; i<9 ; i++) {
871+ saveMeasurement (new_co2, new_temperature, humidity);
872+ }
873+ }
874+ }
875+
876+ /* don't update in Battery mode, unless CO2 has changed by 4% or temperature by 0.5°C */
844877 if (!TEST_MODE && BatteryMode && comingFromDeepSleep) {
845- if ((abs (new_co2 - co2) < (0.03 * co2)) && (fabs (new_temperature - temperature) < 0.5 )) {
878+ if ((abs (new_co2 - co2) < (0.04 * co2)) && (fabs (new_temperature - temperature) < 0.5 )) {
846879 goto_deep_sleep (DEEP_SLEEP_TIME_NO_DISPLAY_UPDATE);
847880 }
848881 }
@@ -893,10 +926,11 @@ void loop() {
893926 if (BatteryMode) {
894927 if (!comingFromDeepSleep) {
895928 scd4x.stopPeriodicMeasurement ();
896- scd4x.setTemperatureOffset (0.8 );
897- scd4x.startLowPowerPeriodicMeasurement ();
929+ scd4x.setTemperatureOffset (getTempOffset () );
930+ if (!lowEnergyMode) scd4x.startLowPowerPeriodicMeasurement ();
898931 }
899- goto_deep_sleep (DEEP_SLEEP_TIME);
932+ if (lowEnergyMode) goto_deep_sleep (LOW_ENERGY_DEEP_SLEEP_TIME);
933+ else goto_deep_sleep (DEEP_SLEEP_TIME);
900934 }
901935
902936 goto_light_sleep (LIGHT_SLEEP_TIME);
0 commit comments