Commit 1600799a authored by Eric Duminil's avatar Eric Duminil
Browse files

Merge branch 'develop'

parents 6412c4ea cb136628
Pipeline #4025 passed with stage
in 1 minute and 47 seconds
...@@ -17,12 +17,13 @@ The *CO<sub>2</sub> Ampel* can: ...@@ -17,12 +17,13 @@ The *CO<sub>2</sub> Ampel* can:
* Send data over [LoRaWAN](https://en.wikipedia.org/wiki/LoRa#LoRaWAN). * Send data over [LoRaWAN](https://en.wikipedia.org/wiki/LoRa#LoRaWAN).
* Display measurements and configuration on a small website. * Display measurements and configuration on a small website.
* Log data to a [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) file, directly on the ESP flash memory. * Log data to a [CSV](https://en.wikipedia.org/wiki/Comma-separated_values) file, directly on the ESP flash memory.
* Accept many interactive commands.
## Hardware Requirements ## Hardware Requirements
* [ESP8266](https://en.wikipedia.org/wiki/ESP8266) or [ESP32](https://en.wikipedia.org/wiki/ESP32) microcontroller (this project has been tested with *ESP8266 ESP-12 WIFI* and *TTGO ESP32 SX1276 LoRa*) * [ESP8266](https://en.wikipedia.org/wiki/ESP8266) or [ESP32](https://en.wikipedia.org/wiki/ESP32) microcontroller (this project has been tested with *ESP8266 ESP-12 WIFI* and *TTGO ESP32 SX1276 LoRa*)
* [Sensirion SCD30](https://www.sensirion.com/en/environmental-sensors/carbon-dioxide-sensors/carbon-dioxide-sensors-co2/) "Sensor Module for HVAC and Indoor Air Quality Applications" * [Sensirion SCD30](https://www.sensirion.com/en/environmental-sensors/carbon-dioxide-sensors/carbon-dioxide-sensors-co2/) "Sensor Module for HVAC and Indoor Air Quality Applications"
* [NeoPixel Ring - 12](https://www.adafruit.com/product/1643) * [NeoPixel Ring - 12](https://www.adafruit.com/product/1643), or [NeoPixel Ring - 16](https://www.adafruit.com/product/1463) (experimental)
See the [documentation](https://transfer.hft-stuttgart.de/gitlab/co2ampel/ampel-documentation) for more info. See the [documentation](https://transfer.hft-stuttgart.de/gitlab/co2ampel/ampel-documentation) for more info.
...@@ -67,6 +68,33 @@ make upload board=esp32 && make monitor # For ESP32 ...@@ -67,6 +68,33 @@ make upload board=esp32 && make monitor # For ESP32
* *Upload* * *Upload*
* *Tools > Serial Monitor* * *Tools > Serial Monitor*
## Available commands
In Arduino IDE *Serial Monitor* or PlatformIO *Monitor*, type `help` + <kbd>Enter</kbd> in order to list the available commands:
* `auto_calibrate 0/1` (Disables/enables autocalibration).
* `calibrate` (Starts calibration process).
* `calibrate 600` (Starts calibration process, to given ppm).
* `calibrate! 600` (Calibrates right now, to given ppm).
* `co2 1500` (Sets co2 level, for debugging purposes).
* `color 0xFF0015` (Shows color, specified as RGB, for debugging).
* `csv 60` (Sets CSV writing interval, in s).
* `format_filesystem` (Deletes the whole filesystem).
* `free` (Displays available heap space).
* `local_ip` (Displays local IP and current SSID).
* `lora 300` (Sets LoRaWAN sending interval, in s).
* `mqtt 60` (Sets MQTT sending interval, in s).
* `night_mode` (Toggles night mode on/off).
* `reset` (Restarts the sensor).
* `reset_scd` (Resets SCD30).
* `send_local_ip` (Sends local IP and SSID via MQTT. Can be useful to find sensor).
* `set_time 1618829570` (Sets time to the given UNIX time).
* `show_csv` (Displays the complete CSV file on Serial).
* `timer 30` (Sets measurement interval, in s).
* `wifi_scan` (Scans available WiFi networks).
The commands can be sent via the Serial interface, from the webpage or via MQTT.
## Authors ## Authors
* Eric Duminil (HfT Stuttgart) * Eric Duminil (HfT Stuttgart)
......
...@@ -113,6 +113,7 @@ namespace sensor { ...@@ -113,6 +113,7 @@ namespace sensor {
sensor_console::defineIntCommand("calibrate!", calibrateSensorRightNow, sensor_console::defineIntCommand("calibrate!", calibrateSensorRightNow,
F("600 (Calibrates right now, to given ppm)")); F("600 (Calibrates right now, to given ppm)"));
sensor_console::defineIntCommand("auto_calibrate", setAutoCalibration, F("0/1 (Disables/enables autocalibration)")); sensor_console::defineIntCommand("auto_calibrate", setAutoCalibration, F("0/1 (Disables/enables autocalibration)"));
sensor_console::defineCommand("reset_scd", resetSCD, F("(Resets SCD30)"));
} }
bool hasSensorSettled() { bool hasSensorSettled() {
...@@ -157,13 +158,14 @@ namespace sensor { ...@@ -157,13 +158,14 @@ namespace sensor {
switchState(PREPARE_CALIBRATION_UNSTABLE); switchState(PREPARE_CALIBRATION_UNSTABLE);
} }
void calibrateAndRestart() { void calibrate() {
Serial.print(F("Calibrating SCD30 now...")); Serial.print(F("Calibrating SCD30 now..."));
scd30.setAltitudeCompensation(config::altitude_above_sea_level); scd30.setAltitudeCompensation(config::altitude_above_sea_level);
scd30.setForcedRecalibrationFactor(config::co2_calibration_level); scd30.setForcedRecalibrationFactor(config::co2_calibration_level);
Serial.println(F(" Done!")); Serial.println(F(" Done!"));
Serial.println(F("Sensor calibrated.")); Serial.println(F("Sensor calibrated."));
ESP.restart(); // softer than ESP.reset //WARNING: Do not reset the ampel or the SCD30!
//At least one measurement needs to happen in order for the calibration to be correctly applied.
} }
void logToSerial() { void logToSerial() {
...@@ -209,7 +211,7 @@ namespace sensor { ...@@ -209,7 +211,7 @@ namespace sensor {
// leave them before calibration is done. // leave them before calibration is done.
bool ready_for_calibration = countStableMeasurements(); bool ready_for_calibration = countStableMeasurements();
if (ready_for_calibration) { if (ready_for_calibration) {
calibrateAndRestart(); calibrate();
} }
} else if (co2 < 250) { } else if (co2 < 250) {
// Sensor should be calibrated. // Sensor should be calibrated.
...@@ -325,7 +327,13 @@ namespace sensor { ...@@ -325,7 +327,13 @@ namespace sensor {
config::co2_calibration_level = calibrationLevel; config::co2_calibration_level = calibrationLevel;
Serial.print(config::co2_calibration_level); Serial.print(config::co2_calibration_level);
Serial.println(F(" ppm.")); Serial.println(F(" ppm."));
calibrateAndRestart(); calibrate();
} }
} }
void resetSCD() {
Serial.print(F("Resetting SCD30..."));
scd30.reset();
Serial.println(F("done."));
}
} }
...@@ -33,5 +33,6 @@ namespace sensor { ...@@ -33,5 +33,6 @@ namespace sensor {
void calibrateSensorToSpecificPPM(int32_t calibrationLevel); void calibrateSensorToSpecificPPM(int32_t calibrationLevel);
void calibrateSensorRightNow(int32_t calibrationLevel); void calibrateSensorRightNow(int32_t calibrationLevel);
void setAutoCalibration(int32_t autoCalibration); void setAutoCalibration(int32_t autoCalibration);
void resetSCD();
} }
#endif #endif
...@@ -30,10 +30,9 @@ namespace mqtt { ...@@ -30,10 +30,9 @@ namespace mqtt {
void initialize(const char *sensorId) { void initialize(const char *sensorId) {
json_sensor_format = PSTR("{\"time\":\"%s\", \"co2\":%d, \"temp\":%.1f, \"rh\":%.1f}"); json_sensor_format = PSTR("{\"time\":\"%s\", \"co2\":%d, \"temp\":%.1f, \"rh\":%.1f}");
snprintf(publish_topic, sizeof(publish_topic), "CO2sensors/%s", sensorId); snprintf(publish_topic, sizeof(publish_topic), "CO2sensors/%s", sensorId);
#if defined(ESP8266) // The sensor doesn't check the fingerprint of the MQTT broker, because otherwise this fingerprint should be updated
espClient.setInsecure(); // Sorry, we don't want to flash the sensors every 3 months. // on the sensor every 3 months. The connection can still be encrypted, though:
#endif espClient.setInsecure(); // If not available for ESP32, please update Arduino IDE / PlatformIO
// mqttClient.setSocketTimeout(config::mqtt_timeout); //NOTE: somehow doesn't seem to have any effect on connect()
mqttClient.setServer(config::mqtt_server, config::mqtt_port); mqttClient.setServer(config::mqtt_server, config::mqtt_port);
sensor_console::defineIntCommand("mqtt", setMQTTinterval, F("60 (Sets MQTT sending interval, in s)")); sensor_console::defineIntCommand("mqtt", setMQTTinterval, F("60 (Sets MQTT sending interval, in s)"));
......
...@@ -34,7 +34,7 @@ Code ...@@ -34,7 +34,7 @@ Code
The MIT License (MIT) The MIT License (MIT)
Copyright (c) 2016 SparkFun Electronics Copyright (c) 2020 SparkFun Electronics
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
...@@ -24,6 +24,7 @@ Thanks to! ...@@ -24,6 +24,7 @@ Thanks to!
* [awatterott](https://github.com/awatterott) for adding [getAltitudeCompensation()](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/18) * [awatterott](https://github.com/awatterott) for adding [getAltitudeCompensation()](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/18)
* [jogi-k](https://github.com/jogi-k) for adding [teensy i2clib](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/19) support * [jogi-k](https://github.com/jogi-k) for adding [teensy i2clib](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/19) support
* [paulvha](https://github.com/paulvha) for the suggestions and corrections in [his version of the library](https://github.com/paulvha/scd30) * [paulvha](https://github.com/paulvha) for the suggestions and corrections in [his version of the library](https://github.com/paulvha/scd30)
* [yamamaya](https://github.com/yamamaya) for the [3ms delay](https://github.com/sparkfun/SparkFun_SCD30_Arduino_Library/pull/24)
Repository Contents Repository Contents
------------------- -------------------
...@@ -43,8 +44,6 @@ License Information ...@@ -43,8 +44,6 @@ License Information
This product is _**open source**_! This product is _**open source**_!
Various bits of the code have different licenses applied. Anything SparkFun wrote is beerware; if you see me (or any other SparkFun employee) at the local, and you've found our code helpful, please buy us a round!
Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license. Please use, reuse, and modify these files as you see fit. Please maintain attribution to SparkFun Electronics and release anything derivative under the same license.
Distributed as-is; no warranty is given. Distributed as-is; no warranty is given.
......
name=SparkFun SCD30 Arduino Library name=SparkFun SCD30 Arduino Library
version=1.0.11 version=1.0.13
author=SparkFun Electronics author=SparkFun Electronics
maintainer=SparkFun Electronics <sparkfun.com> maintainer=SparkFun Electronics <sparkfun.com>
sentence=Library for the Sensirion SCD30 CO2 Sensor sentence=Library for the Sensirion SCD30 CO2 Sensor
......
...@@ -266,6 +266,8 @@ bool SCD30::readMeasurement() ...@@ -266,6 +266,8 @@ bool SCD30::readMeasurement()
if (_i2cPort->endTransmission() != 0) if (_i2cPort->endTransmission() != 0)
return (0); //Sensor did not ACK return (0); //Sensor did not ACK
delay(3);
const uint8_t receivedBytes = _i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)18); const uint8_t receivedBytes = _i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)18);
bool error = false; bool error = false;
if (_i2cPort->available()) if (_i2cPort->available())
...@@ -358,6 +360,8 @@ bool SCD30::getSettingValue(uint16_t registerAddress, uint16_t *val) ...@@ -358,6 +360,8 @@ bool SCD30::getSettingValue(uint16_t registerAddress, uint16_t *val)
if (_i2cPort->endTransmission() != 0) if (_i2cPort->endTransmission() != 0)
return (false); //Sensor did not ACK return (false); //Sensor did not ACK
delay(3);
_i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)3); // Request data and CRC _i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)3); // Request data and CRC
if (_i2cPort->available()) if (_i2cPort->available())
{ {
...@@ -389,6 +393,8 @@ uint16_t SCD30::readRegister(uint16_t registerAddress) ...@@ -389,6 +393,8 @@ uint16_t SCD30::readRegister(uint16_t registerAddress)
if (_i2cPort->endTransmission() != 0) if (_i2cPort->endTransmission() != 0)
return (0); //Sensor did not ACK return (0); //Sensor did not ACK
delay(3);
_i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)2); _i2cPort->requestFrom((uint8_t)SCD30_ADDRESS, (uint8_t)2);
if (_i2cPort->available()) if (_i2cPort->available())
{ {
......
...@@ -57,9 +57,10 @@ ...@@ -57,9 +57,10 @@
#define COMMAND_STOP_MEAS 0x0104 #define COMMAND_STOP_MEAS 0x0104
#define COMMAND_READ_FW_VER 0xD100 #define COMMAND_READ_FW_VER 0xD100
typedef union { typedef union
byte array[4]; {
float value; byte array[4];
float value;
} ByteToFl; // paulvha } ByteToFl; // paulvha
class SCD30 class SCD30
...@@ -69,9 +70,9 @@ public: ...@@ -69,9 +70,9 @@ public:
bool begin(bool autoCalibrate) { return begin(Wire, autoCalibrate); } bool begin(bool autoCalibrate) { return begin(Wire, autoCalibrate); }
#ifdef USE_TEENSY3_I2C_LIB #ifdef USE_TEENSY3_I2C_LIB
bool begin(i2c_t3 &wirePort = Wire, bool autoCalibrate=true, bool measBegin=true); //By default use Wire port bool begin(i2c_t3 &wirePort = Wire, bool autoCalibrate = false, bool measBegin = true); //By default use Wire port
#else #else
bool begin(TwoWire &wirePort = Wire, bool autoCalibrate=true, bool measBegin=true); //By default use Wire port bool begin(TwoWire &wirePort = Wire, bool autoCalibrate = false, bool measBegin = true); //By default use Wire port
#endif #endif
void enableDebugging(Stream &debugPort = Serial); //Turn on debug printing. If user doesn't specify then Serial will be used. void enableDebugging(Stream &debugPort = Serial); //Turn on debug printing. If user doesn't specify then Serial will be used.
...@@ -82,11 +83,11 @@ public: ...@@ -82,11 +83,11 @@ public:
// based on paulvha // based on paulvha
bool getSettingValue(uint16_t registerAddress, uint16_t *val); bool getSettingValue(uint16_t registerAddress, uint16_t *val);
bool getForcedRecalibration(uint16_t *val) {return(getSettingValue(COMMAND_SET_FORCED_RECALIBRATION_FACTOR, val));} bool getForcedRecalibration(uint16_t *val) { return (getSettingValue(COMMAND_SET_FORCED_RECALIBRATION_FACTOR, val)); }
bool getMeasurementInterval(uint16_t *val) {return(getSettingValue(COMMAND_SET_MEASUREMENT_INTERVAL, val));} bool getMeasurementInterval(uint16_t *val) { return (getSettingValue(COMMAND_SET_MEASUREMENT_INTERVAL, val)); }
bool getTemperatureOffset(uint16_t *val) {return(getSettingValue(COMMAND_SET_TEMPERATURE_OFFSET, val));} bool getTemperatureOffset(uint16_t *val) { return (getSettingValue(COMMAND_SET_TEMPERATURE_OFFSET, val)); }
bool getAltitudeCompensation(uint16_t *val) {return(getSettingValue(COMMAND_SET_ALTITUDE_COMPENSATION, val));} bool getAltitudeCompensation(uint16_t *val) { return (getSettingValue(COMMAND_SET_ALTITUDE_COMPENSATION, val)); }
bool getFirmwareVersion(uint16_t *val) {return(getSettingValue(COMMAND_READ_FW_VER, val));} bool getFirmwareVersion(uint16_t *val) { return (getSettingValue(COMMAND_READ_FW_VER, val)); }
uint16_t getCO2(void); uint16_t getCO2(void);
float getHumidity(void); float getHumidity(void);
...@@ -115,12 +116,11 @@ public: ...@@ -115,12 +116,11 @@ public:
uint8_t computeCRC8(uint8_t data[], uint8_t len); uint8_t computeCRC8(uint8_t data[], uint8_t len);
private: private:
//Variables //Variables
#ifdef USE_TEENSY3_I2C_LIB #ifdef USE_TEENSY3_I2C_LIB
i2c_t3 *_i2cPort; //The generic connection to user's chosen I2C hardware i2c_t3 *_i2cPort; //The generic connection to user's chosen I2C hardware
#else #else
TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware TwoWire *_i2cPort; //The generic connection to user's chosen I2C hardware
#endif #endif
//Global main datums //Global main datums
float co2 = 0; float co2 = 0;
...@@ -136,6 +136,5 @@ private: ...@@ -136,6 +136,5 @@ private:
//Debug //Debug
Stream *_debugPort; //The stream to send debug messages to if enabled. Usually Serial. Stream *_debugPort; //The stream to send debug messages to if enabled. Usually Serial.
boolean _printDebug = false; //Flag to print debugging variables boolean _printDebug = false; //Flag to print debugging variables
}; };
#endif #endif
...@@ -38,7 +38,7 @@ class Ampel { ...@@ -38,7 +38,7 @@ class Ampel {
private: private:
static void showFreeSpace(); static void showFreeSpace();
public: public:
const char *version = "v0.1.1"; // Update manually after significant changes. const char *version = "v0.2.0"; // Update manually after significant changes.
const char *board; const char *board;
const char *sensorId; const char *sensorId;
uint32_t max_loop_duration; uint32_t max_loop_duration;
......
Markdown is supported
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