Skip to content

Commit 67e9cec

Browse files
committed
v5.2 WiFi reconnect & rewrite values save
The OpenCO2 Sensor now auto reconnects if the WiFi connection is lost (for example a router reboot). Code refactoring: Rewrite how values are stored. Now up to 24h of measurements are stored in a ring buffer with automatic overflow handling. This replaces the more complex handling of 24 separate arrays containing measurements for 1h each.
1 parent e3f5f07 commit 67e9cec

File tree

2 files changed

+115
-123
lines changed

2 files changed

+115
-123
lines changed

OpenCO2_Sensor.ino

Lines changed: 60 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
- WiFiManager: https://github.com/tzapu/WiFiManager
1111
- ArduinoMqttClient (if MQTT is defined)
1212
*/
13-
#define VERSION "v5.1"
13+
#define VERSION "v5.2"
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
@@ -94,10 +94,11 @@ RTC_DATA_ATTR uint16_t sensorStatus, serial0, serial1, serial2;
9494
RTC_DATA_ATTR uint16_t co2 = 400;
9595
RTC_DATA_ATTR float temperature = 0.0f, humidity = 0.0f;
9696

97-
RTC_DATA_ATTR uint8_t hour = 0;
98-
RTC_DATA_ATTR uint8_t halfminute = 0;
99-
RTC_DATA_ATTR uint16_t co2measurements[24][120]; // every 30 sec
100-
RTC_DATA_ATTR tempHumData tempHumMeasurements[24][40]; // every 1.5 minutes
97+
RTC_DATA_ATTR uint16_t currentIndex = 0;
98+
RTC_DATA_ATTR bool overflow = false;
99+
#define NUM_MEASUREMENTS (24*120)
100+
RTC_DATA_ATTR uint16_t co2measurements[NUM_MEASUREMENTS]; // every 30 sec
101+
RTC_DATA_ATTR tempHumData tempHumMeasurements[NUM_MEASUREMENTS / 3]; // every 1.5 minutes
101102

102103
/* WIFI */
103104
bool shouldSaveConfig = false;
@@ -195,12 +196,15 @@ void HandleRootClient() {
195196
strftime(time, 20, "%Y-%m-%dT%H:%M:%S", &timeinfo);
196197
message += "const endTime = new Date('" + String(time) + "').getTime();\n";
197198

199+
uint16_t index;
200+
if (overflow) index = NUM_MEASUREMENTS;
201+
else index = currentIndex;
198202
time_t now = mktime(&timeinfo);
199-
time_t timestamp = now - hour*60*60 - halfminute*30;
203+
time_t timestamp = now - index * 30;
200204
struct tm* timeinfo2 = localtime(&timestamp);
201205
strftime(time, 20, "%Y-%m-%dT%H:%M:%S", timeinfo2);
202206
message += "const startTime = new Date('" + String(time) + "').getTime();\n";
203-
message += "const numPoints = " + String(hour*120 + halfminute) + ";\n";
207+
message += "const numPoints = " + String(index) + ";\n";
204208

205209
message += "function generateValues(start, end, numPoints) { let values = []; let step = (end - start) / (numPoints - 1); for (let i = 0; i < numPoints; i++) { values.push(start + (step * i));} return values;}\n";
206210
message += "let times = generateValues(startTime, endTime, numPoints).map(time => new Date(time));\n";
@@ -210,18 +214,13 @@ void HandleRootClient() {
210214
const size_t bufferSize = 2048;
211215
String Buffer, Element;
212216
Buffer.reserve(bufferSize);
213-
int i, j, numEnties;
214-
for (i = 0; i <= hour; i++) {
215-
if (i != hour) numEnties = 120;
216-
else numEnties = halfminute;
217-
for (j = 0; j < numEnties; j++) {
218-
Element = String(co2measurements[i][j]) + ",";
219-
if (Buffer.length() + Element.length() > bufferSize) {
220-
server.sendContent(Buffer);
221-
Buffer = "";
222-
}
223-
Buffer += Element;
224-
}
217+
for (int i = 0; i < index; i++) {
218+
Element = String(getCO2Measurement(i)) + ",";
219+
if (Buffer.length() + Element.length() > bufferSize) {
220+
server.sendContent(Buffer);
221+
Buffer = "";
222+
}
223+
Buffer += Element;
225224
}
226225
server.sendContent(Buffer);
227226

@@ -232,39 +231,31 @@ void HandleRootClient() {
232231
server.sendContent(message);
233232

234233
Buffer = "const y1Values = [";
235-
for (i = 0; i <= hour; i++) {
236-
if (i != hour) numEnties = 40;
237-
else numEnties = ceil(halfminute / 3.0);
238-
for (j = 0; j < numEnties; j++) {
239-
float temp = tempHumMeasurements[i][j].temperature / 10.0;
240-
if (useFahrenheit) sprintf(tempString, "%.1f",(temp * 1.8f) + 32.0f); // convert to °F
241-
else sprintf(tempString, "%.1f", temp);
242-
Element = String(tempString) + ",";
243-
if (Buffer.length() + Element.length() > bufferSize) {
244-
server.sendContent(Buffer);
245-
Buffer = "";
246-
}
247-
Buffer += Element;
234+
index = index / 3.0;
235+
for (int i = 0; i < index; i++) {
236+
if (useFahrenheit) sprintf(tempString, "%.1f",(getTempMeasurement(i)/10.0 * 1.8f) + 32.0f); // convert to °F
237+
else sprintf(tempString, "%.1f", getTempMeasurement(i)/10.0);
238+
Element = String(tempString) + ",";
239+
if (Buffer.length() + Element.length() > bufferSize) {
240+
server.sendContent(Buffer);
241+
Buffer = "";
248242
}
243+
Buffer += Element;
249244
}
250245
server.sendContent(Buffer);
251246

252247
Buffer = "];\nconst y2Values = [";
253-
for (i = 0; i <= hour; i++) {
254-
if (i != hour) numEnties = 40;
255-
else numEnties = ceil(halfminute / 3.0);
256-
for (j = 0; j < numEnties; j++) {
257-
Element = String(tempHumMeasurements[i][j].humidity) + ",";
258-
if (Buffer.length() + Element.length() > bufferSize) {
259-
server.sendContent(Buffer);
260-
Buffer = "";
261-
}
262-
Buffer += Element;
248+
for (int i = 0; i < index; i++) {
249+
Element = String(getHumMeasurement(i)) + ",";
250+
if (Buffer.length() + Element.length() > bufferSize) {
251+
server.sendContent(Buffer);
252+
Buffer = "";
263253
}
254+
Buffer += Element;
264255
}
265256
server.sendContent(Buffer);
266257

267-
message = "];\nconst numPoints2 = " + String(int(hour*40 + ceil(halfminute/3.0))) + ";\n";
258+
message = "];\nconst numPoints2 = " + String(index) + ";\n";
268259
message += "let times2 = generateValues(startTime, endTime, numPoints2).map(time => new Date(time));\n";
269260
message += "const data2 = [{x: times2, y: y1Values, name: 'Temperature', mode:'lines'}, ";
270261
message += "{x: times2, y: y2Values, name: 'Humidity', yaxis: 'y2', mode:'lines'}];\n";
@@ -634,22 +625,30 @@ void rainbowMode() {
634625
}
635626

636627
void saveMeasurement(uint16_t co2, float temperature, float humidity) {
637-
if (halfminute == 120) {
638-
halfminute = 0;
639-
hour++;
640-
}
641-
if (hour == 24) {
642-
for (int i = 0; i < 23; ++i) memcpy(co2measurements[i], co2measurements[i + 1], sizeof(uint16_t) * 120); // destination, source
643-
for (int i = 0; i < 23; ++i) memcpy(tempHumMeasurements[i], tempHumMeasurements[i + 1], sizeof(tempHumData) * 40);
644-
hour = 23;
628+
co2measurements[currentIndex] = co2;
629+
if (!(currentIndex % 3)) { // every 1.5 minutes
630+
tempHumMeasurements[currentIndex / 3].temperature = (uint16_t)(temperature * 10);
631+
tempHumMeasurements[currentIndex / 3].humidity = (uint8_t) humidity;
645632
}
646633

647-
co2measurements[hour][halfminute] = co2;
648-
if (!(halfminute % 3)) { // every 1.5 minutes
649-
tempHumMeasurements[hour][halfminute / 3].temperature = (uint16_t)(temperature * 10);
650-
tempHumMeasurements[hour][halfminute / 3].humidity = (uint8_t)humidity;
634+
currentIndex++;
635+
if (currentIndex >= NUM_MEASUREMENTS) {
636+
currentIndex = 0;
637+
overflow = true;
651638
}
652-
halfminute++;
639+
}
640+
641+
uint16_t getCO2Measurement(uint16_t index) {
642+
if (!overflow) return co2measurements[index];
643+
else return co2measurements[(currentIndex + index) % NUM_MEASUREMENTS];
644+
}
645+
uint16_t getTempMeasurement(uint16_t index) {
646+
if (!overflow) return tempHumMeasurements[index].temperature;
647+
else return tempHumMeasurements[(int)(ceil(currentIndex/3.0) + index) % (NUM_MEASUREMENTS/3)].temperature;
648+
}
649+
uint8_t getHumMeasurement(uint16_t index) {
650+
if (!overflow) return tempHumMeasurements[index].humidity;
651+
else return tempHumMeasurements[(int)(ceil(currentIndex/3.0) + index) % (NUM_MEASUREMENTS/3)].humidity;
653652
}
654653

655654
void handleWiFiChange() {
@@ -718,6 +717,7 @@ void startWiFi() {
718717
WiFi.setHostname(Hostname); // hostname when connected to home network
719718

720719
wifiManager.setConfigPortalBlocking(false);
720+
wifiManager.setWiFiAutoReconnect(true);
721721
wifiManager.autoConnect("OpenCO2 Sensor"); // name of broadcasted SSID
722722

723723
#ifdef MQTT
@@ -803,7 +803,10 @@ void loop() {
803803
measureESP32temperature();
804804

805805
if (useWiFi && !BatteryMode) {
806-
if (WiFi.status() != WL_CONNECTED) wifiManager.process();
806+
if (WiFi.status() != WL_CONNECTED) {
807+
wifiManager.autoConnect("OpenCO2 Sensor"); // Attempt to reconnect
808+
wifiManager.process();
809+
}
807810
#ifdef airgradient
808811
if (WiFi.status() == WL_CONNECTED) server.handleClient();
809812
#endif /* airgradient */

0 commit comments

Comments
 (0)