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

1.2.0 #3

Merged
merged 5 commits into from
Jun 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
"datasheet",
"EEPROM",
"LOGI",
"selftest",
"Sensirion"
]
}
76 changes: 55 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,26 +1,46 @@
# SCD4x Library

This is a library to interface with the Sensirion SCD4x true CO2 sensors in Arduino using the I2C protocol.
The SCD4x Library provides an interface to interact with Sensirion SCD4x true CO2 sensors using the I2C protocol in Arduino.

## Warning
These sensors by default have an auto-calibrate mode that takes the lowest CO2 level from the last week and assumes it is 400ppm. This can cause the sensor to read hundreds of ppm off if it is in a room that doesn't get to 400ppm of CO2 in a week. It's important to be aware of this issue, as some scientific papers are even using this sensor and haven't noticed the problem. Here is the code that you need to permanently set them to not auto calibrate. To avoid unnecessary wear of the EEPROM, the saveSettings command should only be used sparingly. The EEPROM is guaranteed to endure at least 2000 write cycles before failure.
## Warning: Auto-Calibration Issue and Recommended Actions

```c++
The SCD4x CO2 sensors come with a default auto-calibrate mode that assumes the lowest CO2 level from the past week as 400ppm. However, it's crucial to be aware that this auto-calibration can result in inaccurate readings if the sensor is placed in an environment that doesn't reach 400ppm CO2 within a week. This issue is particularly important to note when using the sensor for scientific purposes.

To address this issue, it is recommended to permanently disable the auto-calibration mode by using the provided code snippet:

```cpp
#include "scd4x.h"

Wire.begin();
co2.begin(Wire);
co2.setCalibrationMode(false);
co2.saveSettings();
SCD4X co2;

void setup() {
// Initialize the SCD4x library
co2.begin();

// Disable auto-calibration
co2.setCalibrationMode(false);

// Save the settings to EEPROM
co2.saveSettings();
}

void loop() {
// Your code here
}
```

Despite this issue with the auto-calibration mode, I still believe that the Sensirion SCD4x CO2 Sensors are a great choice for measuring indoor air quality. In my experience, they have proven to be much more accurate than other popular sensors such as eCO2 sensors. It's important to be aware of this particular limitation and take the necessary steps to disable the auto-calibration mode, but overall, these sensors are a reliable and effective tool for monitoring CO2 levels.
Please exercise caution when using the `saveSettings()` command as it writes to the EEPROM, which has a limited lifespan of approximately 2000 write cycles before potential failure.

Despite the auto-calibration issue, the Sensirion SCD4x CO2 Sensors remain an excellent choice for monitoring indoor air quality, as they have proven to be more accurate than other popular eCO2 sensors.

## Factory Calibration with Auto-Calibration Off
![Co Location Calibration](/images/cal.png)

## Features
- use multiple I2C Busses -> scd4x.begin(Wire1);
- no extra dependencies
- only implements necessary functions
- uses doubles (64bit floating point numbers) for proper accurate data calculations
* Supports multiple I2C busses: scd4x.begin(Wire1);
* No extra dependencies required
* Implements only necessary functions
* Uses doubles (64-bit floating-point numbers) for accurate data calculations

## Warnings
- not all functions are implemented
Expand Down Expand Up @@ -51,14 +71,28 @@ vTaskDelay(4750 / portTICK_PERIOD_MS); //new data available after approx 5 secon

## 🖼️ Schematic
![Schematic](/images/schematic.png)
- the scd4x sensor can draw up to 205ma peaks at 3.3V (only 18ma average) so make sure you have a robust power source (the above schematic has been tested to work)
- you only need to solder the 6 pins shown and the thermal pad on the underside to get it working
- unfortunately, I have not found a way to easily solder these sensors with a soldering iron, a oven or hotplate seems to be the only way
- look out for a temperature offset if you place the sensor in a case of sorts
* The SCD4x sensor can draw up to 205mA peaks at 3.3V (only 18mA average), so ensure you have a robust power source (the above schematic has been tested to work).
* You only need to solder the 6 shown pins and the thermal pad on the underside to get it working.
* Unfortunately, soldering these sensors with a soldering iron is not easy; an oven or hotplate seems to be the only way.
* Watch out for a temperature offset if you place the sensor in a case or enclosure.

## Based on the awesome work of Raphael Nestler and everyone at Sensirion AG
Origin created by Raphael Nestler in 2021
https://github.com/Sensirion/arduino-i2c-scd4x
## Function Refreence
| Function | Description |
| ---------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `begin()` | Initializes the library. Must be called before any other library functions. |
| `isConnected()` | Checks if the device is correctly connected by verifying the response, manufacturer ID, and part ID. |
| `startPeriodicMeasurement()` | Starts periodic measurement, with new data available in approximately 5 seconds. |
| `stopPeriodicMeasurement()` | Stops periodic measurement. Wait at least 500ms before sending further commands. |
| `readMeasurement()` | Reads the sensor output, including CO₂ concentration in ppm, temperature in °C, and relative humidity in %RH. The measurement data can only be read out once per signal update interval as the buffer is emptied upon read-out. |
| `isDataReady()` | Checks whether new measurement data is available for read-out. |
| `setCalibrationMode()` | Sets the calibration mode and stores it in the EEPROM of the SCD4x. The automatic self-calibration algorithm assumes that the sensor is exposed to the atmospheric CO2 concentration of 400 ppm at least once per week. Use this function sparingly to avoid unnecessary wear of the EEPROM. |
| `getCalibrationMode()` | Gets the calibration mode. Returns `true` if auto calibration is enabled, `false` otherwise. |
| `saveSettings()` | Stores settings in the EEPROM of the SCD4x. Wait at least 800ms before sending further commands. EEPROM is guaranteed to endure at least 2000 write cycles before failure. |
| `getErrorText()` | Converts an error code into descriptive text. Returns a pointer to a constant character array containing the descriptive text of the error. If the error code is not recognized, "Unknown error" is returned. |

## Credits
Based on the work of Raphael Nestler and everyone at Sensirion AG.
Originally created by Raphael Nestler in 2021.
https://github.com/Sensirion/arduino-i2c-scd4x

To help support my work check out my store: https://keastudios.co.nz/
To help support my work, check out my store: https://keastudios.co.nz/
54 changes: 54 additions & 0 deletions examples/async_scd4x_measurement.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
SCD4X Measurement Task Example

This example demonstrates the usage of the SCD4X CO2 sensor library with FreeRTOS on an Arduino board,
specifically designed for the ESP32's version of Arduino with FreeRTOS.

Instructions:
- Install the SCD4X library in your Arduino IDE or add it to platformio.ini
- Connect the SCD4X CO2 sensor to the ESP32:
- SDA: GPIO 21
- SCL: GPIO 22
- VCC: 3V3 (3.3V)
- Optionally, you can add external 4.7k pull-up resistors on the SDA and SCL lines.
- Flash code
- Open the Serial Monitor in the Arduino IDE to view the measurement data.

Note: This example is specifically designed for the ESP32's version of Arduino with FreeRTOS.
*/

#include <scd4x.h>

SCD4X co2;
double co2Value = 0, temperature = 0, humidity = 0;
TaskHandle_t measurementTask;

void measurementTaskFunction(void* parameter) {
Wire.begin(); // SDA: GPIO 21, SCL: GPIO 22 by default on the ESP32
co2.begin(Wire);
co2.startPeriodicMeasurement();

while (true) {
if (co2.isDataReady()) {
if (co2.readMeasurement(co2Value, temperature, humidity) == 0) {
Serial.printf("CO2: %.0f ppm, Temperature: %.1f °C, Humidity: %.0f %%RH\n", co2Value, temperature, humidity);
vTaskDelay(pdMS_TO_TICKS(4750)); // New data available after approximately 5 seconds
}
}
vTaskDelay(pdMS_TO_TICKS(50)); // Check every 50ms
}
}

void setup() {
Serial.begin(115200);
while (!Serial) {
// Wait for serial port to connect
delay(100);
}

xTaskCreatePinnedToCore(measurementTaskFunction, "MeasurementTask", 2048, NULL, 1, &measurementTask, 0);
}

void loop() {
// Your other code here
}
96 changes: 96 additions & 0 deletions examples/basic_data_logger_SD_card.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
#include <SD.h>
#include <Wire.h>
#include <scd4x.h>

SCD4X co2;

const int chipSelectPin = 10; // Chip select pin for SD card module
const String logFileName = "co2_log.txt"; // Name of the log file

void setup() {
Serial.begin(115200);
while (!Serial) {
// Wait for serial port to connect
delay(100);
}

// Initialize SD card
if (!SD.begin(chipSelectPin)) {
Serial.println("SD card initialization failed.");
return;
}

// Initialize the I2C communication
Wire.begin();

// Initialize the SCD4x library
if (!co2.begin()) {
Serial.println("Failed to initialize SCD4X sensor.");
return;
}

// Check if the sensor is connected
if (!co2.isConnected()) {
Serial.println("Sensor not connected. Please check the wiring.");
return;
}

// Check if auto-calibration is enabled
if (co2.getCalibrationMode()) {
// Disable auto-calibration
co2.setCalibrationMode(false);

// Save the settings to EEPROM
co2.saveSettings();
}

// Start periodic measurement after updating settings
co2.startPeriodicMeasurement();

// Create or append to the log file
File logFile = SD.open(logFileName, FILE_WRITE);
if (logFile) {
logFile.println("CO2 (ppm), Temperature (°C), Humidity (%RH)");
logFile.close();
Serial.println("Data logging started. Press reset to start a new log.");
} else {
Serial.println("Failed to open log file.");
return;
}
}

void loop() {
double co2Value, temperature, humidity;

// Read measurement data from the sensor
uint8_t errorCode = co2.readMeasurement(co2Value, temperature, humidity);

// Check for errors
if (errorCode == 0) {
// Format the measurements into a string
char measurementString[50];
snprintf(measurementString, sizeof(measurementString), "%.0f, %.1f, %.0f", co2Value, temperature, humidity);

// Open the log file in append mode
File logFile = SD.open(logFileName, FILE_WRITE | FILE_APPEND);
if (logFile) {
// Write the measurement data to the log file
logFile.println(measurementString);
logFile.close();
Serial.println("Data logged: " + String(measurementString));
} else {
Serial.println("Failed to open log file.");
}

} else {
// Convert the error code to text
const char* errorText = co2.getErrorText(errorCode);

// Print the error message
Serial.print("Error reading measurement: ");
Serial.println(errorText);
}

// Delay for new measurement to be taken
delay(5000);
}
94 changes: 94 additions & 0 deletions examples/basic_scd4x.ino
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
SCD4x CO2 Sensor Example

This example demonstrates the usage of the SCD4x CO2 sensor library on an Arduino board.

Instructions:
- Install the SCD4x library in your Arduino IDE.
- Connect the SCD4X CO2 sensor to the following pins on your Arduino board:
- SDA: Default SDA pin
- SCL: Default SCL pin
- VCC: 3.3V or 5V (make sure you match this with your Arduino VCC voltage or otherwise you can damage it)
- Optionally, you can add external 4.7k pull-up resistors on the SDA and SCL lines.
- Flash code
- Open the Serial Monitor in the Arduino IDE to view the measurement data and any error messages.

Default I2C pins for some common Arduino boards:
- Arduino Uno, Nano: SDA - A4, SCL - A5 (VCC: 5V)
- Arduino Mega: SDA - 20, SCL - 21 (VCC: 5V)
- Arduino Leonardo: SDA - 2, SCL - 3 (VCC: 5V)
- Arduino Due: SDA - 20, SCL - 21 (VCC: 3.3V)
- ESP32: SDA - GPIO 21, SCL - GPIO 22 (VCC: 3.3V)
- ESP8266: SDA - GPIO 4, SCL - GPIO 5 (VCC: 3.3V)
- RP2040: SDA - GP5 (pin 4), SCL - GP4 (pin 3) (VCC: 3.3V)

Note: The default SDA and SCL pins may vary depending on the specific board or variant. Please refer to the board documentation for the correct pin mappings.

4.7k Pull-up Resistors:
- I2C communication requires pull-up resistors on the SDA and SCL lines to ensure proper signal levels.
- Some Arduino boards already have built-in pull-up resistors for the I2C pins, so external resistors may not be necessary.
- However, if you encounter communication issues or have long wire lengths, adding external 4.7k pull-up resistors between the SDA/SCL lines and VCC can help improve signal stability.
*/

#include <Wire.h>
#include <scd4x.h>

SCD4X co2;

void setup() {
// Initialize the I2C communication
Wire.begin();

// Initialize the SCD4x library
co2.begin();

// Check if the sensor is connected
if (!co2.isConnected()) {
while (true) {
Serial.println("Sensor not connected. Please check the wiring.");
delay(1000);
}
}

// Check if auto-calibration is enabled
if (co2.getCalibrationMode()) {
// Disable auto-calibration
co2.setCalibrationMode(false);

// Save the settings to EEPROM
co2.saveSettings();
}

// Start periodic measurement after updating settings
co2.startPeriodicMeasurement();

// Wait for the sensor to warm up and take the first reading
delay(5000);
}

void loop() {
double co2Value, temperature, humidity;

// Read measurement data from the sensor
uint8_t errorCode = co2.readMeasurement(co2Value, temperature, humidity);

// Check for errors
if (errorCode == 0) {
// Format the measurements into a string
char measurementString[100];
sprintf(measurementString, "CO2: %.0f ppm, Temperature: %.1f °C, Humidity: %.0f %%RH", co2Value, temperature, humidity);

// Print the measurements
Serial.println(measurementString);
} else {
// Convert the error code to text
const char* errorText = co2.getErrorText(errorCode);

// Print the error message
Serial.print("Error reading measurement: ");
Serial.println(errorText);
}

// Delay for new measurement to be taken
delay(5000);
}
Binary file added images/cal.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
36 changes: 20 additions & 16 deletions library.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,25 @@
{
"name": "scd4x-CO2",
"version": "1.1.0",
"description": "A library to interface esp chips with the SCD4x CO2 sensors in the Arduino (c++) Framework.",
"keywords": "co2, scd40, scd41, scd4x, i2c",
"repository": {
"type": "git",
"url": "https://github.com/CDFER/scd4x-CO2.git"
},
"authors": [
{
"name": "scd4x-CO2",
"version": "1.2.0",
"description": "An Arduino library for interfacing ESP chips with SCD4x CO2 sensors using the I2C protocol.",
"keywords": [
"co2",
"scd40",
"scd41",
"scd4x",
"i2c"
],
"repository": {
"type": "git",
"url": "https://github.com/CDFER/scd4x-CO2.git"
},
"author": {
"name": "Chris Dirks",
"url": "https://keastudios.co.nz/about.htm",
"maintainer": true
}
],
"license": "MIT",
"homepage": "https://github.com/CDFER/scd4x-CO2",
"frameworks": "arduino",
"platforms": "*"
},
"license": "Other",
"homepage": "https://github.com/CDFER/scd4x-CO2",
"frameworks": "arduino",
"platforms": "*"
}
Loading