Created
March 13, 2025 15:06
-
-
Save rdlauer/8be390f39462117631d8e1b215b4d359 to your computer and use it in GitHub Desktop.
Indoor Air Quality Monitor Sketch using Blues, Adafruit IO, and IFTTT
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <Arduino.h> | |
#include <Notecard.h> | |
#include <SensirionI2cScd4x.h> | |
#include <Wire.h> | |
#include "Adafruit_SGP40.h" | |
#include <Adafruit_GFX.h> | |
#include "Adafruit_LEDBackpack.h" | |
#define usbSerial Serial | |
#define PRODUCT_UID "your-product-uid" | |
#define NO_SCD40_ERROR 0 | |
#define IS_USB 0 | |
Notecard notecard; | |
SensirionI2cScd4x scd40; | |
Adafruit_SGP40 sgp; | |
Adafruit_7segment matrix = Adafruit_7segment(); | |
unsigned long currentMillis, startMillis; | |
unsigned long sensorReadPeriod = 1000 * 60 * 1; // read sensors every [x] mins | |
float temp, humid, voltage; | |
uint16_t co2, sraw; | |
int32_t vocIndex; | |
static int16_t scd40Error; | |
static char scd40ErrorMessage[64]; | |
void printError(const char *message) | |
{ | |
if (IS_USB) | |
{ | |
usbSerial.println(message); | |
} | |
else | |
{ | |
matrix.print("ERR"); | |
matrix.writeDisplay(); | |
} | |
} | |
void setup() | |
{ | |
delay(2500); | |
if (IS_USB) | |
{ | |
usbSerial.begin(115200); | |
while (!usbSerial) | |
; | |
} | |
Wire.begin(); | |
// ####################### | |
// Notecard Initialization | |
// ####################### | |
notecard.begin(); | |
if (IS_USB) | |
{ | |
notecard.setDebugOutputStream(usbSerial); | |
} | |
{ | |
J *req = notecard.newRequest("hub.set"); | |
if (req != NULL) | |
{ | |
JAddStringToObject(req, "product", PRODUCT_UID); | |
JAddStringToObject(req, "mode", "continuous"); | |
notecard.sendRequest(req); | |
} | |
} | |
{ | |
J *req = notecard.newRequest("note.template"); | |
if (req != NULL) | |
{ | |
JAddStringToObject(req, "file", "sensors.qo"); | |
JAddBoolToObject(req, "sync", true); | |
J *body = JAddObjectToObject(req, "body"); | |
if (body) | |
{ | |
JAddNumberToObject(body, "temp", 12.1); | |
JAddNumberToObject(body, "humid", 12.1); | |
JAddNumberToObject(body, "co2", 12); | |
JAddNumberToObject(body, "raw", 12); | |
JAddNumberToObject(body, "voc", 12); | |
JAddNumberToObject(body, "voltage", 12.1); | |
} | |
notecard.sendRequest(req); | |
} | |
} | |
// #################### | |
// SCD40 Initialization | |
// #################### | |
scd40.begin(Wire, SCD41_I2C_ADDR_62); | |
uint64_t scd40SerialNumber = 0; | |
// Ensure sensor is in clean state | |
scd40Error = scd40.wakeUp(); | |
if (scd40Error != NO_SCD40_ERROR) | |
{ | |
printError("Error trying to execute wakeUp(): "); | |
errorToString(scd40Error, scd40ErrorMessage, sizeof scd40ErrorMessage); | |
printError(scd40ErrorMessage); | |
} | |
scd40Error = scd40.stopPeriodicMeasurement(); | |
if (scd40Error != NO_SCD40_ERROR) | |
{ | |
printError("Error trying to execute stopPeriodicMeasurement(): "); | |
errorToString(scd40Error, scd40ErrorMessage, sizeof scd40ErrorMessage); | |
printError(scd40ErrorMessage); | |
} | |
scd40Error = scd40.reinit(); | |
if (scd40Error != NO_SCD40_ERROR) | |
{ | |
printError("Error trying to execute reinit(): "); | |
errorToString(scd40Error, scd40ErrorMessage, sizeof scd40ErrorMessage); | |
printError(scd40ErrorMessage); | |
} | |
// Read out information about the sensor | |
scd40Error = scd40.getSerialNumber(scd40SerialNumber); | |
if (scd40Error != NO_SCD40_ERROR) | |
{ | |
printError("Error trying to execute getSerialNumber(): "); | |
errorToString(scd40Error, scd40ErrorMessage, sizeof scd40ErrorMessage); | |
printError(scd40ErrorMessage); | |
return; | |
} | |
// #################### | |
// SGP40 Initialization | |
// #################### | |
if (!sgp.begin()) | |
{ | |
printError("SGP40 sensor not found :("); | |
while (1) | |
; | |
} | |
// ###################### | |
// 7 segment display Init | |
// ###################### | |
matrix.begin(0x70); | |
matrix.setBrightness(15); | |
matrix.print(8888); | |
matrix.writeDisplay(); | |
// ########################################## | |
// Warm up the SGP40 by executing 50 readings | |
// ########################################## | |
for (int i = 0; i < 50; i++) | |
{ | |
sgp.measureVocIndex(); | |
matrix.print(i + 1); | |
matrix.writeDisplay(); | |
delay(250); | |
} | |
matrix.print(8888); | |
matrix.writeDisplay(); | |
startMillis = millis(); | |
} | |
void loop() | |
{ | |
currentMillis = millis(); | |
if (currentMillis - startMillis >= sensorReadPeriod) | |
{ | |
temp = 0.0; | |
humid = 0.0; | |
voltage = 0.0; | |
co2 = 0; | |
sraw = 0; | |
vocIndex = 0; | |
// Wake the SCD40 sensor up from sleep mode | |
scd40Error = scd40.wakeUp(); | |
if (scd40Error != NO_SCD40_ERROR) | |
{ | |
printError("Error trying to execute wakeUp(): "); | |
errorToString(scd40Error, scd40ErrorMessage, sizeof scd40ErrorMessage); | |
printError(scd40ErrorMessage); | |
return; | |
} | |
// Ignore first measurement after wake up. | |
scd40Error = scd40.measureSingleShot(); | |
if (scd40Error != NO_SCD40_ERROR) | |
{ | |
printError("Error trying to execute measureSingleShot(): "); | |
errorToString(scd40Error, scd40ErrorMessage, sizeof scd40ErrorMessage); | |
printError(scd40ErrorMessage); | |
return; | |
} | |
// Perform single shot measurement and read data. | |
scd40Error = scd40.measureAndReadSingleShot(co2, temp, humid); | |
if (scd40Error != NO_SCD40_ERROR) | |
{ | |
printError("Error trying to execute measureAndReadSingleShot(): "); | |
errorToString(scd40Error, scd40ErrorMessage, sizeof scd40ErrorMessage); | |
printError(scd40ErrorMessage); | |
return; | |
} | |
// Get VOC index from SGP40 sensor | |
sraw = sgp.measureRaw(temp, humid); | |
vocIndex = sgp.measureVocIndex(temp, humid); | |
// Get the power supply voltage from the Notecard | |
{ | |
J *req = notecard.newRequest("card.voltage"); | |
if (J *rsp = notecard.requestAndResponse(req)) | |
{ | |
voltage = JGetNumber(rsp, "value"); | |
} | |
else | |
{ | |
voltage = 0.0; | |
} | |
} | |
// print out VOC Index to display | |
matrix.print(vocIndex); | |
matrix.writeDisplay(); | |
// Send data to Notehub and Adafruit.io! | |
{ | |
J *req = notecard.newRequest("note.add"); | |
if (req != NULL) | |
{ | |
JAddStringToObject(req, "file", "sensors.qo"); | |
JAddBoolToObject(req, "sync", true); | |
J *body = JAddObjectToObject(req, "body"); | |
if (body) | |
{ | |
JAddNumberToObject(body, "temp", temp); | |
JAddNumberToObject(body, "humid", humid); | |
JAddNumberToObject(body, "co2", co2); | |
JAddNumberToObject(body, "raw", sraw); | |
JAddNumberToObject(body, "voc", vocIndex); | |
JAddNumberToObject(body, "voltage", voltage); | |
} | |
notecard.sendRequest(req); | |
} | |
} | |
startMillis = currentMillis; | |
} | |
delay(20); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment