Skip to content

Commit 8743452

Browse files
committed
v6.0 increase batterylife
New default to low energy mode with a smart algorithm to only measure CO2, if the temperature changed by more than 0.5°C or the humidity by 2% or 5 minutes passed. Increase battery runtime to 11+ weeks. Bugfix: LED color fixed on HWSubRev < 3
1 parent ca87e23 commit 8743452

File tree

4 files changed

+37
-59
lines changed

4 files changed

+37
-59
lines changed

OpenCO2_Sensor.ino

Lines changed: 31 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,12 @@
1010
- WiFiManager: https://github.com/tzapu/WiFiManager
1111
- ArduinoMqttClient (if MQTT is defined)
1212
*/
13-
#define VERSION "v5.9"
13+
#define VERSION "v6.0"
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
1818
#define DEEP_SLEEP_TIME 29124 // 30 sec
19-
#define LOW_ENERGY_DEEP_SLEEP_TIME 287924 // 5 min
2019
#define DEEP_SLEEP_TIME_NO_DISPLAY_UPDATE DEEP_SLEEP_TIME + 965 // offset for no display update
2120
static unsigned long lastMeasurementTimeMs = 0;
2221

@@ -88,7 +87,7 @@ SensirionI2cScd4x scd4x;
8887
USBMSC usbmsc;
8988

9089
RTC_DATA_ATTR bool USB_ACTIVE = false, initDone = false, BatteryMode = false, comingFromDeepSleep = false;
91-
RTC_DATA_ATTR bool LEDonBattery, LEDonUSB, useSmoothLEDcolor, invertDisplay, useFahrenheit, useWiFi, lowEnergyMode, english, limitMaxBattery;
90+
RTC_DATA_ATTR bool LEDonBattery, LEDonUSB, useSmoothLEDcolor, invertDisplay, useFahrenheit, useWiFi, english, limitMaxBattery;
9291
RTC_DATA_ATTR uint8_t ledbrightness, HWSubRev, font;
9392
RTC_DATA_ATTR float maxBatteryVoltage;
9493

@@ -327,8 +326,7 @@ float getTempOffset() {
327326
if (useWiFi) return 12.2;
328327
return 4.4;
329328
} else {
330-
if (lowEnergyMode) return 0.0;
331-
return 0.8;
329+
return 0.0; // was with periodic measurment 0.8
332330
}
333331
}
334332

@@ -348,7 +346,7 @@ void initOnce() {
348346
if (HWSubRev < 3) {
349347
Wire.begin(33, 34); // green, yellow
350348
digitalWrite(LED_POWER, LOW); // LED on
351-
FastLED.addLeds<APA102, 40, 39, RGB>(leds, 1);
349+
FastLED.addLeds<APA102, 40, 39, BRG>(leds, 1);
352350
} else {
353351
Wire.begin(3, 2);
354352
digitalWrite(LED_POWER, HIGH); // LED on
@@ -370,7 +368,6 @@ void initOnce() {
370368
preferences.begin("co2-sensor", true);
371369
maxBatteryVoltage = preferences.getFloat("MBV", 3.95);
372370
useWiFi = preferences.getBool("WiFi", false);
373-
lowEnergyMode = preferences.getBool("lowEnergy", false);
374371
LEDonBattery = preferences.getBool("LEDonBattery", false);
375372
LEDonUSB = preferences.getBool("LEDonUSB", true);
376373
ledbrightness = preferences.getInt("ledbrightness", 5);
@@ -389,7 +386,7 @@ void initOnce() {
389386
scd4x.setSensorAltitude(HEIGHT_ABOVE_SEA_LEVEL);
390387
scd4x.setAutomaticSelfCalibrationEnabled(1); // Or use setAutomaticSelfCalibrationTarget if needed
391388
scd4x.setTemperatureOffset(getTempOffset());
392-
if (!(BatteryMode && lowEnergyMode)) scd4x.startPeriodicMeasurement();
389+
if (!BatteryMode) scd4x.startPeriodicMeasurement();
393390

394391
displayInit();
395392
delay(3000); // Wait for co2 measurement
@@ -789,7 +786,7 @@ void setup() {
789786
/* scd4x */
790787
if (HWSubRev < 3) {
791788
Wire.begin(33, 34); // green, yellow
792-
FastLED.addLeds<APA102, 40, 39, RGB>(leds, 1);
789+
FastLED.addLeds<APA102, 40, 39, BRG>(leds, 1);
793790
} else {
794791
Wire.begin(3, 2);
795792
FastLED.addLeds<WS2812, LED_PIN, GRB>(leds, 1);
@@ -830,7 +827,7 @@ void setup() {
830827

831828

832829
void loop() {
833-
if ((!useWiFi || (lowEnergyMode && BatteryMode)) && esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_GPIO) handleButtonPress();
830+
if ((!useWiFi || BatteryMode) && esp_sleep_get_wakeup_cause() == ESP_SLEEP_WAKEUP_GPIO) handleButtonPress();
834831
updateBatteryMode(); // check again in USB Power mode
835832
updateCharging();
836833
measureESP32temperature();
@@ -856,7 +853,7 @@ void loop() {
856853
goto_light_sleep(5000 - (millis() - lastMeasurementTimeMs));
857854
}
858855

859-
if (!(BatteryMode && lowEnergyMode) && !TEST_MODE) {
856+
if (!BatteryMode && !TEST_MODE) {
860857
bool isDataReady = false;
861858
uint16_t ready_error = scd4x.getDataReadyStatus(isDataReady);
862859
if (ready_error || !isDataReady) {
@@ -870,11 +867,27 @@ void loop() {
870867
uint16_t new_co2 = 420;
871868
float new_temperature = 0.0f;
872869
uint16_t error;
873-
if (BatteryMode && lowEnergyMode) {
870+
if (BatteryMode) {
874871
scd4x.stopPeriodicMeasurement();
875872
scd4x.wakeUp();
876873
scd4x.setTemperatureOffset(getTempOffset());
877-
//delay(10);
874+
875+
/* check if temp/humidity changed */
876+
scd4x.measureSingleShotRhtOnly();
877+
uint16_t dummyCo2; // CO2 output is returned as 0 ppm
878+
float new_humidity = 0.0f;
879+
error = scd4x.readMeasurement(dummyCo2, new_temperature, new_humidity);
880+
extern uint16_t refreshes;
881+
if (!error
882+
&& (refreshes % 10 != 1) //force update every 5 minutes
883+
&& (fabs(new_temperature - temperature) < 0.5)
884+
&& (fabs(humidity - temperature) < 2.0)) {
885+
scd4x.powerDown();
886+
refreshes++;
887+
saveMeasurement(co2, new_temperature, new_humidity);
888+
goto_deep_sleep(DEEP_SLEEP_TIME_NO_DISPLAY_UPDATE);
889+
}
890+
878891
if (HWSubRev < 3) scd4x.measureSingleShot(); // Ignore first measurement after wake up.
879892
error = scd4x.measureAndReadSingleShot(new_co2, new_temperature, humidity);
880893
scd4x.powerDown();
@@ -895,19 +908,12 @@ void loop() {
895908
extern uint16_t refreshes;
896909
if (BatteryMode || (refreshes % 6 == 1)) {
897910
saveMeasurement(new_co2, new_temperature, humidity);
898-
899-
if (BatteryMode && lowEnergyMode) { // fill measurements of past 5 min
900-
for (int i=0; i<9; i++) {
901-
saveMeasurement(new_co2, new_temperature, humidity);
902-
}
903-
}
904911
}
905912

906-
/* don't update in Battery mode, unless CO2 has changed by 4% or temperature by 0.5°C */
913+
/* don't update in Battery mode, unless CO2 has changed by 4% */
907914
if (!TEST_MODE && BatteryMode && comingFromDeepSleep) {
908-
if ((abs(new_co2 - co2) < (0.04 * co2)) && (fabs(new_temperature - temperature) < 0.5)) {
909-
if (lowEnergyMode) goto_deep_sleep(LOW_ENERGY_DEEP_SLEEP_TIME);
910-
else goto_deep_sleep(DEEP_SLEEP_TIME_NO_DISPLAY_UPDATE);
915+
if (abs(new_co2 - co2) < (0.04 * co2)) {
916+
goto_deep_sleep(DEEP_SLEEP_TIME_NO_DISPLAY_UPDATE);
911917
}
912918
}
913919

@@ -958,10 +964,9 @@ void loop() {
958964
if (!comingFromDeepSleep) {
959965
scd4x.stopPeriodicMeasurement();
960966
scd4x.setTemperatureOffset(getTempOffset());
961-
if (!lowEnergyMode) scd4x.startLowPowerPeriodicMeasurement();
967+
//if (!lowEnergyMode) scd4x.startLowPowerPeriodicMeasurement();
962968
}
963-
if (lowEnergyMode) goto_deep_sleep(LOW_ENERGY_DEEP_SLEEP_TIME);
964-
else goto_deep_sleep(DEEP_SLEEP_TIME);
969+
goto_deep_sleep(DEEP_SLEEP_TIME);
965970
}
966971

967972
goto_light_sleep(LIGHT_SLEEP_TIME);

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ OpenCO2 Sensor is an Arduino IDE compatible Repository for an E-Ink Indoor air q
88

99
## Buy it [here on Tindie](https://www.tindie.com/products/davidkreidler/open-co2-sensor/)
1010

11-
Especially in winter, when windows are closed, a reminder to ventilate regularly is useful for health, comfort and well-being. Poor indoor air quality can lead to decreased productivity and learning disabilities. Therefore, I developed an Open-source ESP32 project that uses an E-Ink display and a LED to show the indoor CO2 content. Take the small Sensor anywhere you go to monitor the Air Quality, with Battery life of 11+ days.
11+
Especially in winter, when windows are closed, a reminder to ventilate regularly is useful for health, comfort and well-being. Poor indoor air quality can lead to decreased productivity and learning disabilities. Therefore, I developed an Open-source ESP32 project that uses an E-Ink display and a LED to show the indoor CO2 content. Take the small Sensor anywhere you go to monitor the Air Quality, with Battery life of 11+ weeks.
1212

1313
# CO2 Sensor
1414

epd_abstraction.h

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ enum LEDMenuOptions {
2222
NUM_LED_OPTIONS
2323
};
2424
enum DisplayMenuOptions {
25-
UPDATE,
2625
MAX_BATTERY,
2726
INVERT,
2827
TEMP_UNIT,
@@ -57,7 +56,6 @@ const char* EnglishLEDmenuItems[NUM_LED_OPTIONS] = {
5756
"Exit"
5857
};
5958
const char* EnglishOptionsMenuItems[NUM_DISPLAY_OPTIONS] = {
60-
"Update",
6159
"Battery",
6260
"Invert",
6361
"Unit",
@@ -90,7 +88,6 @@ const char* GermanLEDmenuItems[NUM_LED_OPTIONS] = {
9088
"Beenden"
9189
};
9290
const char* GermanOptionsMenuItems[NUM_DISPLAY_OPTIONS] = {
93-
"Update",
9491
"Battery",
9592
"Invert",
9693
"Einheit",

epd_abstraction.ino

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -210,18 +210,6 @@ void OptionsMenu() {
210210
}
211211
if (mspressed > 1000) { // long press
212212
switch (selectedOption) {
213-
case UPDATE:
214-
lowEnergyMode = !lowEnergyMode;
215-
preferences.begin("co2-sensor", false);
216-
preferences.putBool("lowEnergy", lowEnergyMode);
217-
preferences.end();
218-
219-
if (BatteryMode) {
220-
scd4x.stopPeriodicMeasurement();
221-
scd4x.setTemperatureOffset(getTempOffset());
222-
if (!lowEnergyMode) scd4x.startPeriodicMeasurement();
223-
}
224-
break;
225213
case MAX_BATTERY:
226214
toggleMaxBattery();
227215
break;
@@ -806,15 +794,13 @@ void displayOptionsMenu(uint8_t selectedOption) {
806794
else OptionsMenuItem = GermanOptionsMenuItems[i];
807795
Paint_DrawString_EN(5, 25*(i+1), OptionsMenuItem, &Font24, WHITE, BLACK);
808796
}
809-
if (lowEnergyMode) Paint_DrawString_EN(200-17*4, 25, "5min", &Font24, WHITE, BLACK);
810-
else Paint_DrawString_EN(200-17*5, 25, "30sec", &Font24, WHITE, BLACK);
811797

812-
if (limitMaxBattery && HWSubRev > 2) Paint_DrawString_EN(200-17*4, 25*2, "~80%", &Font24, WHITE, BLACK);
813-
else Paint_DrawString_EN(200-17*4, 25*2, "100%", &Font24, WHITE, BLACK);
798+
if (limitMaxBattery && HWSubRev > 2) Paint_DrawString_EN(200-17*4, 25, "~80%", &Font24, WHITE, BLACK);
799+
else Paint_DrawString_EN(200-17*4, 25, "100%", &Font24, WHITE, BLACK);
814800

815-
Paint_DrawString_EN(166, 25*4, (useFahrenheit? "*F":"*C"), &Font24, WHITE, BLACK);
816-
Paint_DrawNum(149, 25*6, (int32_t)(font+1), &Font24, BLACK, WHITE);
817-
Paint_DrawString_EN(166, 25*6, "/2", &Font24, WHITE, BLACK);
801+
Paint_DrawString_EN(166, 25*3, (useFahrenheit? "*F":"*C"), &Font24, WHITE, BLACK);
802+
Paint_DrawNum(149, 25*5, (int32_t)(font+1), &Font24, BLACK, WHITE);
803+
Paint_DrawString_EN(166, 25*5, "/2", &Font24, WHITE, BLACK);
818804

819805
invertSelected(selectedOption);
820806
updateDisplay();
@@ -1252,7 +1238,6 @@ void displayinfo() {
12521238
delay(10);
12531239
scd4x.getTemperatureOffset(tOffset);
12541240
if (!BatteryMode) scd4x.startPeriodicMeasurement();
1255-
else if (!lowEnergyMode) scd4x.startLowPowerPeriodicMeasurement();
12561241
Paint_DrawString_EN(1, 145, "T_offset:", &Font16, WHITE, BLACK);
12571242
char offset[20];
12581243
snprintf(offset, sizeof(offset), "%.2f", tOffset);
@@ -1336,15 +1321,6 @@ void displayBattery(uint8_t percentage) {
13361321
BlackImage[y+x*25] = ~BlackImage[y+x*25];
13371322
}
13381323
}
1339-
1340-
/* low Energy Mode */
1341-
if (lowEnergyMode) {
1342-
Paint_DrawRectangle(97, 13, 115, 47, BLACK, DOT_PIXEL_2X2, DRAW_FILL_EMPTY); //case
1343-
Paint_DrawLine(103, 10, 109, 10, BLACK, DOT_PIXEL_3X3, LINE_STYLE_SOLID);//nippel
1344-
Paint_DrawLine(106, 25, 106, 35, BLACK, DOT_PIXEL_2X2, LINE_STYLE_SOLID);//+
1345-
Paint_DrawLine(102, 30, 110, 30, BLACK, DOT_PIXEL_2X2, LINE_STYLE_SOLID);//+
1346-
//Xstart, Ystart, Xend, Yend
1347-
}
13481324
#endif /* EINK_1IN54V2 */
13491325

13501326
#ifdef EINK_4IN2

0 commit comments

Comments
 (0)