Commit ef911533 authored by Eric Duminil's avatar Eric Duminil
Browse files

Merge branch 'refactor/fixstartup' into develop

parents 701ac714 79f137e8
......@@ -3,10 +3,12 @@
namespace config {
// Values should be defined in config.h
uint16_t measurement_timestep = MEASUREMENT_TIMESTEP; // [s] Value between 2 and 1800 (range for SCD30 sensor)
const uint16_t measurement_timestep_bootup = 2; // [s] Measurement timestep during acclimatization
const uint16_t altitude_above_sea_level = ALTITUDE_ABOVE_SEA_LEVEL; // [m]
uint16_t co2_calibration_level = ATMOSPHERIC_CO2_CONCENTRATION; // [ppm]
int8_t max_deviation_during_calibration = 30; // [ppm]
int8_t enough_stable_measurements = 60;
const uint8_t max_deviation_during_bootup = 20; // [%]
#ifdef TEMPERATURE_OFFSET
// Residual heat from CO2 sensor seems to be high enough to change the temperature reading. How much should it be offset?
// NOTE: Sign isn't relevant. The returned temperature will always be shifted down.
......@@ -28,31 +30,27 @@ namespace sensor {
/**
* Define sensor states
* INITIAL -> initial state
* BOOTUP -> state after initializing the sensor, i.e. after scd.begin()
* BOOTUP -> initial state, until first >0 ppm values are returned
* READY -> sensor does output valid information (> 0 ppm) and no other condition takes place
* NEEDS_CALIBRATION -> sensor measurements are too low (< 250 ppm)
* PREPARE_CALIBRATION -> forced calibration was initiated, waiting for stable measurements
* CALIBRATION -> the sensor does calibrate itself
* PREPARE_CALIBRATION_UNSTABLE -> forced calibration was initiated, last measurements were too far apart
* PREPARE_CALIBRATION_STABLE -> forced calibration was initiated, last measurements were close to each others
*/
enum state {
INITIAL,
BOOTUP,
READY,
NEEDS_CALIBRATION,
PREPARE_CALIBRATION_UNSTABLE,
PREPARE_CALIBRATION_STABLE,
CALIBRATION
PREPARE_CALIBRATION_STABLE
};
const char *state_names[] = {
"INITIAL",
"BOOTUP",
"READY",
"NEEDS_CALIBRATION",
"PREPARE_CALIBRATION_UNSTABLE",
"PREPARE_CALIBRATION_STABLE",
"CALIBRATION" };
state current_state = INITIAL;
"PREPARE_CALIBRATION_STABLE" };
state current_state = BOOTUP;
void switchState(state);
void initialize() {
......@@ -78,28 +76,33 @@ namespace sensor {
ESP.restart();
}
switchState(BOOTUP);
// SCD30 has its own timer.
//NOTE: The timer seems to be inaccurate, though, possibly depending on voltage. Should it be offset?
Serial.print(F("Setting SCD30 timestep to "));
Serial.print(config::measurement_timestep);
Serial.println(" s.");
scd30.setMeasurementInterval(config::measurement_timestep); // [s]
// Changes of the SCD30's measurement timestep do not come into effect
// before the next measurement takes place. That means that after a hard reset
// of the ESP the SCD30 sometimes needs a long time until switching back to 2 s
// for acclimatization. Resetting it after startup seems to fix this behaviour.
scd30.reset();
Serial.print(F("Setting temperature offset to -"));
Serial.print(abs(config::temperature_offset));
Serial.println(" K.");
Serial.println(F(" K."));
scd30.setTemperatureOffset(abs(config::temperature_offset)); // setTemperatureOffset only accepts positive numbers, but shifts the temperature down.
delay(100);
Serial.print(F("Temperature offset is : -"));
Serial.print(scd30.getTemperatureOffset());
Serial.println(" K");
Serial.println(F(" K"));
Serial.print(F("Auto-calibration is "));
Serial.println(config::auto_calibrate_sensor ? "ON." : "OFF.");
// SCD30 has its own timer.
//NOTE: The timer seems to be inaccurate, though, possibly depending on voltage. Should it be offset?
Serial.println();
Serial.print(F("Setting SCD30 timestep to "));
Serial.print(config::measurement_timestep_bootup);
Serial.println(F(" s during acclimatization."));
scd30.setMeasurementInterval(config::measurement_timestep_bootup); // [s]
sensor_console::defineIntCommand("co2", setCO2forDebugging, F(" 1500 (Sets co2 level, for debugging purposes)"));
sensor_console::defineIntCommand("timer", setTimer, F(" 30 (Sets measurement interval, in s)"));
sensor_console::defineCommand("calibrate", startCalibrationProcess, F(" (Starts calibration process)"));
......@@ -117,10 +120,20 @@ namespace sensor {
int32_t now = millis();
Serial.print(F("Measurement time offset : "));
Serial.print(now - previous_measurement_at - config::measurement_timestep * 1000);
Serial.println(" ms.");
Serial.println(F(" ms."));
previous_measurement_at = now;
}
bool hasSensorSettled() {
static uint16_t last_co2 = 0;
uint16_t delta;
delta = abs(co2 - last_co2);
last_co2 = co2;
// We assume the sensor has acclimated to the environment if measurements
// change less than a specified percentage of the current value.
return (co2 > 0 && delta < ((uint32_t) co2 * config::max_deviation_during_bootup / 100));
}
bool countStableMeasurements() {
// Returns true, if a sufficient number of stable measurements has been observed.
static int16_t previous_co2 = 0;
......@@ -151,7 +164,6 @@ namespace sensor {
}
void calibrateAndRestart() {
switchState(CALIBRATION);
Serial.print(F("Calibrating SCD30 now..."));
scd30.setAltitudeCompensation(config::altitude_above_sea_level);
scd30.setForcedRecalibrationFactor(config::co2_calibration_level);
......@@ -177,19 +189,25 @@ namespace sensor {
if (config::debug_sensor_states) {
Serial.print(F("Changing sensor state: "));
Serial.print(state_names[current_state]);
Serial.print(" -> ");
Serial.print(F(" -> "));
Serial.println(state_names[new_state]);
}
current_state = new_state;
}
void switchStateForCurrentPPM() {
if (co2 == 0) {
// NOTE: Data is available, but it's sometimes erroneous: the sensor outputs
// zero ppm but non-zero temperature and non-zero humidity.
Serial.println(F("Invalid sensor data - CO2 concentration supposedly 0 ppm"));
switchState(BOOTUP);
} else if ((current_state == PREPARE_CALIBRATION_UNSTABLE) || (current_state == PREPARE_CALIBRATION_STABLE)) {
if (current_state == BOOTUP) {
if (!hasSensorSettled()) {
return;
}
switchState(READY);
Serial.println(F("Sensor acclimatization finished."));
Serial.print(F("Setting SCD30 timestep to "));
Serial.print(config::measurement_timestep);
Serial.println(F(" s."));
scd30.setMeasurementInterval(config::measurement_timestep); // [s]
}
if ((current_state == PREPARE_CALIBRATION_UNSTABLE) || (current_state == PREPARE_CALIBRATION_STABLE)) {
// Check for pre-calibration states first, because we do not want to
// leave them before calibration is done.
bool ready_for_calibration = countStableMeasurements();
......@@ -236,8 +254,6 @@ namespace sensor {
case PREPARE_CALIBRATION_STABLE:
led_effects::showWaitingLED(color::green);
break;
case CALIBRATION: // Nothing to do, will restart soon.
break;
default:
Serial.println(F("Encountered unknown sensor state")); // This should not happen.
}
......@@ -264,7 +280,9 @@ namespace sensor {
showState();
return freshData;
// Report data for further processing only if the data is reliable
// (state 'READY') or manual calibration is necessary (state 'NEEDS_CALIBRATION').
return freshData && (current_state == READY || current_state == NEEDS_CALIBRATION);
}
/*****************************************************************
......@@ -288,7 +306,7 @@ namespace sensor {
if (timestep >= 2 && timestep <= 1800) {
Serial.print(F("Setting Measurement Interval to : "));
Serial.print(timestep);
Serial.println("s.");
Serial.println(F("s."));
sensor::scd30.setMeasurementInterval(timestep);
config::measurement_timestep = timestep;
led_effects::showKITTWheel(color::green, 1);
......@@ -300,7 +318,7 @@ namespace sensor {
Serial.print(F("Force calibration, at "));
config::co2_calibration_level = calibrationLevel;
Serial.print(config::co2_calibration_level);
Serial.println(" ppm.");
Serial.println(F(" ppm."));
sensor::startCalibrationProcess();
}
}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment