Home

Awesome

PlatformIO Build Status ViewCount

Air Quality Sensors Library

Generic sensor manager, abstractions and bindings of multiple sensors libraries: Honeywell, Plantower, Panasonic, Sensirion, etc. and CO2 sensors. Also it's handling others environment sensors. This library is for general purpose, but also is the sensors library base of CanAirIO project.

For developers also you can check the complete library documentation here

<table> <tr> <td> Don't forget to star ⭐ this repository </td> </tr> </table>

Supported sensors

PM sensors

Sensor modelUARTI2CDetection modeStatus
Honeywell HPMA115S0Yes---AutoDEPRECATED
Panasonic SN-GCJA5LYesYesAutoSTABLE
Plantower modelsYes---AutoSTABLE
Nova SDS011Yes---AutoSTABLE
IKEA VindriktningYes---SelectSTABLE
Sensirion SPS30YesYesSelect / AutoSTABLE

NOTE:
Panasonic via UART in ESP8266 maybe needs select in detection.

CO2 sensors

Sensor modelUARTI2CDetection modeStatus
Sensirion SCD30---YesAutoSTABLE
Sensirion SCD4x---YesAutoTESTING
MHZ19Yes---SelectSTABLE
CM1106Yes---SelectSTABLE
SenseAir S8Yes---SelectSTABLE

Environmental sensors

Sensor modelProtocolDetection modeStatus
AM2320i2cAutoSTABLE
SHT31i2cAutoSTABLE
AHT10i2cAutoSTABLE
BME280i2cAutoSTABLE
BMP280i2cAutoSTABLE
BME680i2cAutoSTABLE
DfRobot SEN0469 NH3i2cAutoTESTING
DFRobot SEN0466 COi2cAutoTESTING
DFRobot SEN0471 NO2i2cAutoTESTING
Geiger CAJOEGPIOSelectTESTING
DHTxxTwoWireSelectDISABLED

NOTE:
DHT22 is supported but is not recommended. Please see the documentation.

Platforms supported

PlatformVariantsNotesStatus
ESP32WROVER*ESP32Devkit and similar (recommended)STABLE
ESP32S3LilyGo TDisplayIn testingSTABLE
ESP32C3Devkit v3In testingSTABLE
ESP826612D1MINI tested and similar (old)STABLE
Atmelsamseeed_wio_terminalOnly works via i2c on left portSTABLE
ArduinoAtmelSome third party libraries failsIN PROGRESS

Features

Full list of all sub libraries supported here

Quick implementation

sensors.setOnDataCallBack(&onSensorDataOk);   // all data read callback
sensors.init();                               // start all sensors and

Full implementation

You can review a full implementation on CanAirIO project firmware, but a little brief is the next:

/// sensors data callback
void onSensorDataOk() {
    Serial.print("PM2.5: " + String(sensors.getPM25()));
    Serial.print(" CO2: "  + String(sensors.getCO2()));
    Serial.print(" CO2H: " + String(sensors.getCO2humi()));
    Serial.print(" CO2T: " + String(sensors.getCO2temp()));
    Serial.print(" H: "    + String(sensors.getHumidity()));
    Serial.println(" T: "  + String(sensors.getTemperature()));
}

/// sensors error callback
void onSensorDataError(const char * msg){
    Serial.println("Sensor read error: "+String(msg));
}

void setup() {

    sensors.setOnDataCallBack(&onSensorDataOk);     // all data read callback
    sensors.setOnErrorCallBack(&onSensorDataError); // [optional] error callback
    sensors.setSampleTime(15);                      // [optional] sensors sample time (default 5s)
    sensors.setTempOffset(cfg.toffset);             // [optional] temperature compensation
    sensors.setCO2AltitudeOffset(cfg.altoffset);    // [optional] CO2 altitude compensation
    sensors.setSeaLevelPressure(1036.25);           // [optional] Set sea level pressure in hpa
    sensors.setDebugMode(false);                    // [optional] debug mode to get detailed msgs
    sensors.detectI2COnly(true);                    // [optional] force to only i2c sensors
    sensors.setTemperatureUnit(TEMPUNIT::KELVIN);   // comment it for Celsius or set Fahrenheit
    sensors.init();                                 // Auto detection to UART and i2c sensors

    // Alternatives only for UART sensors (TX/RX):

    // sensors.init(SENSORS::Auto);                 // Auto detection to UART sensors (Honeywell, Plantower, Panasonic)
    // sensors.init(SENSORS::SGCJA5);               // Force UART detection to Panasonic sensor
    // sensors.init(SENSORS::SSPS30);               // Force UART detection to Sensirion sensor
    // sensors.init(SENSORS::SMHZ19);               // Force UART detection to Mhz14 or Mhz19 CO2 sensor
    // sensors.init(SENSORS::SDS011);               // Force UART detection to SDS011 sensor
    // sensors.init(SENSORS::IKEAVK);               // Force UART detection to IKEA Vindriktning sensor
    // sensors.init(SENSORS::SCM1106);              // Force UART detection to CM1106 CO2 sensor
    // sensors.init(SENSORS::SAIRS8);               // Force UART detection to SenseAirS8 CO2 sensor
    // sensors.init(SENSORS::Auto,PMS_RX,PMS_TX);   // Auto detection on custom RX,TX
  
    // Also you can access to sub-library objects, and perform for example calls like next:

    // sensors.sps30.sleep()
    // sensors.bme.readPressure();
    // sensors.mhz19.getRange();
    // sensors.scd30.getTemperatureOffset();
    // sensors.aht10.readRawData();
    // sensors.s8.set_ABC_period(period)
    // ...

    delay(500);
}

void loop() {
    sensors.loop();  // read sensor data and showed it
}

Multivariable demo

In this demo on two different devices with multiple sensors, you can choose the possible sub sensors units or variables:

CanAirIO multivariable demo

In this demo on a simple sketch you could have a dinamyc list of variables of multiple sensors brands:

CanAirIO Sensors Lib DEMO with M5CoreInk

Multivariable alternative implementation

The last version added new getters to have the current status of each unit of each sensor connected to the device in real time. Also you can retrieve the list of device names and other stuff:

For example:

#include <Arduino.h>
#include <Sensors.hpp>

void printSensorsDetected() {
    uint16_t sensors_count =  sensors.getSensorsRegisteredCount();
    uint16_t units_count   =  sensors.getUnitsRegisteredCount();
    Serial.println("-->[MAIN] Sensors detected count\t: " + String(sensors_count));
    Serial.println("-->[MAIN] Sensors units count  \t: "  + String(units_count));
    Serial.print(  "-->[MAIN] Sensors devices names\t: ");
    int i = 0;
    while (sensors.getSensorsRegistered()[i++] != 0) {
        Serial.print(sensors.getSensorName((SENSORS)sensors.getSensorsRegistered()[i - 1]));
        Serial.print(",");
    }
    Serial.println();
}

void printSensorsValues() {
    Serial.println("\n-->[MAIN] Preview sensor values:");
    UNIT unit = sensors.getNextUnit();
    while(unit != UNIT::NUNIT) {
        String uName = sensors.getUnitName(unit);
        float uValue = sensors.getUnitValue(unit);
        String uSymb = sensors.getUnitSymbol(unit);
        Serial.print("-->[MAIN] " + uName + ": " + String(uValue) + " " + uSymb);
        unit = sensors.getNextUnit();
    }
}

void onSensorDataOk() {
    Serial.println("======= E X A M P L E   T E S T =========");
    printSensorsDetected();
    printSensorsValues(); 
    Serial.println("=========================================");
}

/******************************************************************************
*  M A I N
******************************************************************************/

void setup() {
    Serial.begin(115200);
    delay(100);
    sensors.setSampleTime(5);                       // config sensors sample time interval
    sensors.setOnDataCallBack(&onSensorDataOk);     // all data read callback
    sensors.setDebugMode(true);                     // [optional] debug mode
    sensors.detectI2COnly(false);                   // disable force to only i2c sensors
    sensors.init();                                 // Auto detection to UART and i2c sensors
}

void loop() {
    sensors.loop();  // read sensor data and showed it
}

UART detection demo

CanAirIO auto configuration demo

CanAirIO sensorlib auto configuration demo on Youtube

Wiring

The current version of library supports 3 kinds of wiring connection, UART, i2c and TwoWire, in the main boards the library using the defaults pins of each board, but in some special cases the pins are:

UART

Predefined UART

The library has pre-defined some UART pin configs, these are selected on compiling time. Maybe you don't need change anything with your board, and maybe the nexts alternatives works for you:

Board modelTXRXNotes
ESP32GENERIC13ESP32 Pio defaults
TTGOT7 / ESP32DEVKIT / D1MINI / NODEFINED1617CanAirIO devices **
TTGO_TDISPLAY1213
M5COREINK1413
TTGO TQ1813
HELTEC1817
WEMOSOLED1513
ESP32PICOD431

** This pines are when you compile your project without specific any build variable or you board isn't in the list.

Custom UART

Also you could define a custom UART pins in the init() method and select specific sensors model, like this:

sensors.init(SENSORS::SDS011,yourRX,yourTX); // custom RX, custom TX pines.

I2C (recommended)

We are using the default pins for each board, some times it's pins are 21,22, please check your board schematic.

TwoWire (deprecated soon)

For now we are using it only for DHT sensors in PIN 23. For more info please review the next lines here.

Examples

PlatformIO (recommended)

We recommended PlatformIO because is more easy than Arduino IDE. For that, please install first PlatformIO and its command line tools (Windows, MacOs and Linux), pio command, then connect your compatible board to the USB and run the next command:

pio run -e esp32 --target upload

Also you can see some examples than have platformio.ini files for your project.

Arduino IDE

Only import the ino file of the sample and install the libraries listed on library.json and this library. Complete list of libraries used here

Arduino CLI

For run the examples, you first need to install arduino-cli or the Arduino IDE with the libraries referenced in lib_deps on the file platformio.ini, becuase Arduino don't install it automatically like PlatformIO. Then put CanAirIO sensor library in your library directory, you can download it from releases section.

Also you need to add the alternative links for supporting the ESP32 boards:

arduino-cli config init

in the .arduino15/arduino-cli.yaml file add:

board_manager:
  additional_urls:
    - https://arduino.esp8266.com/stable/package_esp8266com_index.json
    - https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json

From arduino-cli you can run the basic example in a ESP32 board following these steps:

arduino-cli core update-index
arduino-cli core install esp32:esp32:lolin32
arduino-cli compile --fqbn esp32:esp32:lolin32 basic
arduino-cli upload --fqbn esp32:esp32:lolin32:UploadSpeed=115200 -p /dev/ttyUSB0 basic

where basic is the basic example on examples directory.

Supporting the project

If you want to contribute to the code or documentation, consider posting a bug report, feature request or a pull request.

When creating a pull request, we recommend that you do the following:

Also you can make a donation, be a patreon or buy a device:

<a href="https://raw.githubusercontent.com/kike-canaries/canairio_firmware/master/images/ethereum_donation_address.png" target="_blank"><img src="https://raw.githubusercontent.com/kike-canaries/canairio_firmware/master/images/ethereum_donation_address.png" align="right" width="220" margin-left="10px" ></a>

TODO

Projects using this Library

Credits

Thanks to all collaborators and CanAirIO community for testing and reports. Visit us on Telegram