Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for CCS811 sensor #992

Open
wants to merge 3 commits into
base: beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions airrohr-firmware/airrohr-cfg.h
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ enum ConfigShapeId {
Config_sps30_read,
Config_bmp_read,
Config_bmx280_read,
Config_ccs811_read,
Config_sht3x_read,
Config_scd30_read,
Config_ds18b20_read,
Expand Down Expand Up @@ -117,6 +118,7 @@ static constexpr char CFG_KEY_IPS_READ[] PROGMEM = "ips_read";
static constexpr char CFG_KEY_SPS30_READ[] PROGMEM = "sps30_read";
static constexpr char CFG_KEY_BMP_READ[] PROGMEM = "bmp_read";
static constexpr char CFG_KEY_BMX280_READ[] PROGMEM = "bmx280_read";
static constexpr char CFG_KEY_CCS811_READ[] PROGMEM = "ccs811_read";
static constexpr char CFG_KEY_SHT3X_READ[] PROGMEM = "sht3x_read";
static constexpr char CFG_KEY_SCD30_READ[] PROGMEM = "scd30_read";
static constexpr char CFG_KEY_DS18B20_READ[] PROGMEM = "ds18b20_read";
Expand Down Expand Up @@ -189,6 +191,7 @@ static constexpr ConfigShapeEntry configShape[] PROGMEM = {
{ Config_Type_Bool, 0, CFG_KEY_SPS30_READ, &cfg::sps30_read },
{ Config_Type_Bool, 0, CFG_KEY_BMP_READ, &cfg::bmp_read },
{ Config_Type_Bool, 0, CFG_KEY_BMX280_READ, &cfg::bmx280_read },
{ Config_Type_Bool, 0, CFG_KEY_CCS811_READ, &cfg::ccs811_read },
{ Config_Type_Bool, 0, CFG_KEY_SHT3X_READ, &cfg::sht3x_read },
{ Config_Type_Bool, 0, CFG_KEY_SCD30_READ, &cfg::scd30_read },
{ Config_Type_Bool, 0, CFG_KEY_DS18B20_READ, &cfg::ds18b20_read },
Expand Down
141 changes: 125 additions & 16 deletions airrohr-firmware/airrohr-firmware.ino
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ String SOFTWARE_VERSION(SOFTWARE_VERSION_STR);
#include "./DHT.h"
#include <Adafruit_HTU21DF.h>
#include <Adafruit_BMP085.h>
#include "Adafruit_CCS811.h"
#include <Adafruit_SHT31.h>
#include <StreamString.h>
#include <DallasTemperature.h>
Expand Down Expand Up @@ -170,6 +171,7 @@ namespace cfg
bool sps30_read = SPS30_READ;
bool bmp_read = BMP_READ;
bool bmx280_read = BMX280_READ;
bool ccs811_read = CCS811_READ;
char height_above_sealevel[8] = "0";
bool sht3x_read = SHT3X_READ;
bool scd30_read = SCD30_READ;
Expand Down Expand Up @@ -253,6 +255,7 @@ long int sample_count = 0;
bool htu21d_init_failed = false;
bool bmp_init_failed = false;
bool bmx280_init_failed = false;
bool ccs811_init_failed = false;
bool sht3x_init_failed = false;
bool scd30_init_failed = false;
bool dnms_init_failed = false;
Expand Down Expand Up @@ -335,6 +338,11 @@ BMX280 bmx280;
const uint8_t bmx280_default_i2c_address = 0x77;
const uint8_t bmx280_alternate_i2c_address = 0x76;

/*****************************************************************
* CCS811 declaration *
*****************************************************************/
Adafruit_CCS811 ccs811;

/*****************************************************************
* SHT3x declaration *
*****************************************************************/
Expand Down Expand Up @@ -450,6 +458,8 @@ float last_value_BMP_P = -1.0;
float last_value_BMX280_T = -128.0;
float last_value_BMX280_P = -1.0;
float last_value_BME280_H = -1.0;
float last_value_CCS811_C = -1.0;
float last_value_CCS811_T = -1.0;
float last_value_DHT_T = -128.0;
float last_value_DHT_H = -1.0;
float last_value_DS18B20_T = -1.0;
Expand Down Expand Up @@ -1190,6 +1200,11 @@ static void readConfig(bool oldconfig = false)
cfg::bmx280_read = true;
rewriteConfig = true;
}
if (boolFromJSON(json, F("ccs811_read")))
{
cfg::ccs811_read = true;
rewriteConfig = true;
}
}
else
{
Expand Down Expand Up @@ -1746,6 +1761,7 @@ static void webserver_config_send_body_get(String &page_content)
add_form_checkbox_sensor(Config_dht_read, FPSTR(INTL_DHT22));
add_form_checkbox_sensor(Config_htu21d_read, FPSTR(INTL_HTU21D));
add_form_checkbox_sensor(Config_bmx280_read, FPSTR(INTL_BMX280));
add_form_checkbox_sensor(Config_ccs811_read, FPSTR(INTL_CCS811));
add_form_checkbox_sensor(Config_sht3x_read, FPSTR(INTL_SHT3X));
add_form_checkbox_sensor(Config_scd30_read, FPSTR(INTL_SCD30));

Expand Down Expand Up @@ -2204,6 +2220,12 @@ static void webserver_values()
}
page_content += FPSTR(EMPTY_ROW);
}
if (cfg::ccs811_read)
{
add_table_value(FPSTR(SENSORS_CCS811), FPSTR(INTL_CO2), check_display_value(last_value_CCS811_C, -1, 1, 6), "ppm");
add_table_value(FPSTR(SENSORS_CCS811), FPSTR(INTL_TVOC), check_display_value(last_value_CCS811_T, -1, 1, 6), "ppb");
page_content += FPSTR(EMPTY_ROW);
}
if (cfg::sht3x_read)
{
add_table_t_value(FPSTR(SENSORS_SHT3X), FPSTR(INTL_TEMPERATURE), last_value_SHT3X_T);
Expand Down Expand Up @@ -3399,6 +3421,38 @@ static void fetchSensorBMX280(String &s)
debug_outln_verbose(FPSTR(DBG_TXT_END_READING), FPSTR(sensor_name));
}

/*****************************************************************
* read CCS811 sensor values *
*****************************************************************/
static void fetchSensorCCS811(String& s) {
debug_outln_verbose(FPSTR(DBG_TXT_START_READING), FPSTR(SENSORS_CCS811));

if(ccs811.available()){
if (!ccs811.readData()) {
const auto c = ccs811.geteCO2();
const auto t = ccs811.getTVOC();

if (isnan(c) || isnan(t)) {
last_value_CCS811_C = -1.0;
last_value_CCS811_T = -1.0;
debug_outln_error(F("CCS811 read failed"));
} else {
last_value_CCS811_C = c;
last_value_CCS811_T = t;
add_Value2Json(s, F("CCS811_co2"), F("CO2: "), last_value_CCS811_C);
add_Value2Json(s, F("CCS811_tvoc"), F("TVOC: "), last_value_CCS811_T);
}
} else {
last_value_CCS811_C = -1.0;
last_value_CCS811_T = -1.0;
debug_outln_error(F("CCS811 read failed"));
}
}

debug_outln_info(FPSTR(DBG_TXT_SEP));
debug_outln_verbose(FPSTR(DBG_TXT_END_READING), FPSTR(SENSORS_CCS811));
}

/*****************************************************************
* read DS18B20 sensor values *
*****************************************************************/
Expand Down Expand Up @@ -4844,6 +4898,9 @@ static void display_values()
float h_value = -1.0;
float p_value = -1.0;
String t_sensor, h_sensor, p_sensor;
float co2_value = -1.0;
float tvoc_value = -1.0;
String co2_sensor, tvoc_sensor;
float pm001_value = -1.0;
float pm003_value = -1.0;
float pm005_value = -1.0;
Expand Down Expand Up @@ -4878,7 +4935,7 @@ static void display_values()
String display_header;
String display_lines[3] = {"", "", ""};
uint8_t screen_count = 0;
uint8_t screens[8];
uint8_t screens[12];
int line_count = 0;
debug_outln_info(F("output values to display..."));
if (cfg::ppd_read)
Expand Down Expand Up @@ -4993,6 +5050,12 @@ static void display_values()
h_value = last_value_BME280_H;
}
}
if (cfg::ccs811_read)
{
co2_sensor = tvoc_sensor = FPSTR(SENSORS_CCS811);
co2_value = last_value_CCS811_C;
tvoc_value = last_value_CCS811_T;
}
if (cfg::sht3x_read)
{
h_sensor = t_sensor = FPSTR(SENSORS_SHT3X);
Expand All @@ -5018,12 +5081,12 @@ static void display_values()
}
if (cfg::npm_read)
{
screens[screen_count++] = 9;
screens[screen_count++] = 10;
screens[screen_count++] = 10;
screens[screen_count++] = 11;
}
if (cfg::ips_read)
{
screens[screen_count++] = 11; //A VOIR POUR AJOUTER DES ÈCRANS
screens[screen_count++] = 12; //A VOIR POUR AJOUTER DES ÈCRANS
}
if (cfg::sps30_read)
{
Expand All @@ -5033,25 +5096,29 @@ static void display_values()
{
screens[screen_count++] = 3;
}
if (cfg::scd30_read)
if (cfg::ccs811_read)
{
screens[screen_count++] = 4;
}
if (cfg::gps_read)
if (cfg::scd30_read)
{
screens[screen_count++] = 5;
}
if (cfg::dnms_read)
if (cfg::gps_read)
{
screens[screen_count++] = 6;
}
if (cfg::dnms_read)
{
screens[screen_count++] = 7;
}
if (cfg::display_wifi_info)
{
screens[screen_count++] = 7; // Wifi info
screens[screen_count++] = 8; // Wifi info
}
if (cfg::display_device_info)
{
screens[screen_count++] = 8; // chipID, firmware and count of measurements
screens[screen_count++] = 9; // chipID, firmware and count of measurements
}
// update size of "screens" when adding more screens!
if (cfg::has_display || cfg::has_sh1106 || lcd_2004)
Expand Down Expand Up @@ -5108,6 +5175,11 @@ static void display_values()
}
break;
case 4:
display_header = co2_sensor;
display_lines[0] = "CO2: "; check_display_value(co2_value, -1, 1, 6); display_lines[line_count++] += " ppm";
display_lines[1] = "TVOC: "; check_display_value(tvoc_value, -1, 1, 6); display_lines[line_count++] += " ppb";
break;
case 5:
display_header = "SCD30";
display_lines[0] = "Temp.: ";
display_lines[0] += check_display_value(last_value_SCD30_T, -128, 1, 5);
Expand All @@ -5119,7 +5191,7 @@ static void display_values()
display_lines[2] += check_display_value(last_value_SCD30_CO2, 0, 0, 5);
display_lines[2] += " ppm";
break;
case 5:
case 6:
display_header = "NEO6M";
display_lines[0] = "Lat: ";
display_lines[0] += check_display_value(lat_value, -200.0, 6, 10);
Expand All @@ -5128,21 +5200,21 @@ static void display_values()
display_lines[2] = "Alt: ";
display_lines[2] += check_display_value(alt_value, -1000.0, 2, 10);
break;
case 6:
case 7:
display_header = FPSTR(SENSORS_DNMS);
display_lines[0] = std::move(tmpl(F("LAeq: {v} db(A)"), check_display_value(la_eq_value, -1, 1, 6)));
display_lines[1] = std::move(tmpl(F("LA_max: {v} db(A)"), check_display_value(la_max_value, -1, 1, 6)));
display_lines[2] = std::move(tmpl(F("LA_min: {v} db(A)"), check_display_value(la_min_value, -1, 1, 6)));
break;
case 7:
case 8:
display_header = F("Wifi info");
display_lines[0] = "IP: ";
display_lines[0] += WiFi.localIP().toString();
display_lines[1] = "SSID: ";
display_lines[1] += WiFi.SSID();
display_lines[2] = std::move(tmpl(F("Signal: {v} %"), String(calcWiFiSignalQuality(last_signal_strength))));
break;
case 8:
case 9:
display_header = F("Device Info");
display_lines[0] = "ID: ";
display_lines[0] += esp_chipid;
Expand All @@ -5151,19 +5223,19 @@ static void display_values()
display_lines[2] = F("Measurements: ");
display_lines[2] += String(count_sends);
break;
case 9:
case 10:
display_header = F("Tera Next PM");
display_lines[0] = std::move(tmpl(F("PM1: {v} µg/m³"), check_display_value(pm01_value, -1, 1, 6)));
display_lines[1] = std::move(tmpl(F("PM2.5: {v} µg/m³"), check_display_value(pm25_value, -1, 1, 6)));
display_lines[2] = std::move(tmpl(F("PM10: {v} µg/m³"), check_display_value(pm10_value, -1, 1, 6)));
break;
case 10:
case 11:
display_header = F("Tera Next PM");
display_lines[0] = current_state_npm;
display_lines[1] = F("T_NPM / RH_NPM");
display_lines[2] = current_th_npm;
break;
case 11:
case 12:
display_header = F("Piera IPS-7100");
display_lines[0] = std::move(tmpl(F("PM1: {v} µg/m³"), check_display_value(pm01_value, -1, 1, 6)));
display_lines[1] = std::move(tmpl(F("PM2.5: {v} µg/m³"), check_display_value(pm25_value, -1, 1, 6)));
Expand Down Expand Up @@ -5384,6 +5456,24 @@ static bool initBMX280(char addr)
}
}

/*****************************************************************
* Init CCS811 *
*****************************************************************/
static bool initCCS811() {
debug_out(String(F("Trying CCS811 sensor on 0X5A")), DEBUG_MIN_INFO);

if(ccs811.begin()) {
debug_outln_info(FPSTR(DBG_TXT_FOUND));
while(!ccs811.available()){
yield(); // Prevent WDT from resetting the ESP
}
return true;
} else {
debug_outln_info(FPSTR(DBG_TXT_NOT_FOUND));
return false;
}
}

/*****************************************************************
Init SPS30 PM Sensor
*****************************************************************/
Expand Down Expand Up @@ -5625,6 +5715,15 @@ static void powerOnTestSensors()
}
}

if (cfg::ccs811_read)
{
debug_outln_info(F("Read CCS811..."));
if (!initCCS811()) {
debug_outln_error(F("Check CCS811 wiring"));
ccs811_init_failed = true;
}
}

if (cfg::sht3x_read)
{
debug_outln_info(F("Read SHT3x..."));
Expand Down Expand Up @@ -6163,6 +6262,16 @@ void loop(void)
}
result = emptyString;
}
if (cfg::ccs811_read && (! ccs811_init_failed))
{
// getting co2 and tvoc (optional)
fetchSensorCCS811(result);
data += result;
// TODO: uncomment once sensor community amend their API to receive ccs811 data...
// sum_send_time += sendSensorCommunity(result, CCS811_API_PIN, FPSTR(SENSORS_CCS811), "CCS811_");

result = emptyString;
}
if (cfg::sht3x_read && (!sht3x_init_failed))
{
// getting temperature and humidity (optional)
Expand Down
4 changes: 4 additions & 0 deletions airrohr-firmware/ext_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,10 @@ static const char MEASUREMENT_NAME_INFLUX[] PROGMEM = "feinstaub";
#define BMP280_API_PIN 3
#define BME280_API_PIN 11

// CCS811, CO2, TVOC
#define CCS811_READ 0
#define CCS811_API_PIN 4

// SHT3x, temperature, pressure
#define SHT3X_READ 0
#define SHT3X_API_PIN 7
Expand Down
1 change: 1 addition & 0 deletions airrohr-firmware/html-content.h
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ const char SENSORS_SCD30[] PROGMEM = "SCD30";
const char SENSORS_BMP180[] PROGMEM = "BMP180";
const char SENSORS_BME280[] PROGMEM = "BME280";
const char SENSORS_BMP280[] PROGMEM = "BMP280";
const char SENSORS_CCS811[] PROGMEM = "CCS811";
const char SENSORS_DNMS[] PROGMEM = "DNMS";

const char WEB_PAGE_HEADER[] PROGMEM = "<!DOCTYPE html><html lang='" INTL_LANG "'>\
Expand Down
3 changes: 3 additions & 0 deletions airrohr-firmware/intl_en.h
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const char INTL_DHT22[] PROGMEM = "DHT22 ({t}, {h})";
const char INTL_HTU21D[] PROGMEM = "HTU21D ({t}, {h})";
const char INTL_BMP180[] PROGMEM = "BMP180 ({t}, {p})";
const char INTL_BMX280[] PROGMEM = "BME280 ({t}, {h}, {p}), BMP280 ({t}, {p})";
const char INTL_CCS811[] PROGMEM = "CCS811 ({co}, {tv})";
const char INTL_SHT3X[] PROGMEM = "SHT3X ({t}, {h})";
const char INTL_SCD30[] PROGMEM = "SCD30 ({t}, {h}, CO₂)";
const char INTL_DS18B20[] PROGMEM = "DS18B20 ({t})";
Expand Down Expand Up @@ -112,6 +113,8 @@ const char INTL_PARTICULATE_MATTER[] PROGMEM = "particulate matter";
const char INTL_TEMPERATURE[] PROGMEM = "temperature";
const char INTL_HUMIDITY[] PROGMEM = "humidity";
const char INTL_PRESSURE[] PROGMEM = "air pressure";
const char INTL_TVOC[] PROGMEM = "TVOC";
const char INTL_CO2[] PROGMEM = "CO₂";
const char INTL_DEW_POINT[] PROGMEM = "dew point";
const char INTL_CO2_PPM[] PROGMEM = "ppm CO₂";
const char INTL_LEQ_A[] PROGMEM = "LAeq";
Expand Down