mirror of
https://github.com/airgradienthq/arduino.git
synced 2025-06-27 00:31:32 +02:00
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
ab1f6c1ae7 | |||
63c7e9ca00 | |||
0b8408ef13 | |||
ff34d2c143 | |||
73498894e4 | |||
ed3b0ff53f | |||
07e1b5e97a | |||
348ddba048 | |||
a3c8054839 | |||
555693cda8 | |||
0a9f184946 | |||
7c02564ed4 | |||
c270cda600 | |||
0abc5629fc | |||
a40399d082 | |||
0753a4c9dd | |||
1a5ac64aa1 | |||
f170404c03 | |||
16a29b4646 | |||
bb3c57297e | |||
89e1d35a49 | |||
4f8bd0dbee | |||
ccfe271f0d |
@ -11,7 +11,7 @@
|
|||||||
#include <SoftwareSerial.h>
|
#include <SoftwareSerial.h>
|
||||||
#include "Arduino.h"
|
#include "Arduino.h"
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
#include <Math.h>
|
#include <math.h>
|
||||||
|
|
||||||
|
|
||||||
// Constructor /////////////////////////////////////////////////////////////////
|
// Constructor /////////////////////////////////////////////////////////////////
|
||||||
@ -303,7 +303,7 @@ TMP_RH AirGradient::periodicFetchData() //
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
returnError(error);
|
return returnError(error);
|
||||||
}
|
}
|
||||||
|
|
||||||
TMP_RH_ErrorCode AirGradient::periodicStop() {
|
TMP_RH_ErrorCode AirGradient::periodicStop() {
|
||||||
@ -607,47 +607,27 @@ const char* AirGradient::getCO2(int retryLimit) {
|
|||||||
return Char_CO2;
|
return Char_CO2;
|
||||||
}
|
}
|
||||||
int AirGradient::getCO2_Raw(){
|
int AirGradient::getCO2_Raw(){
|
||||||
int retry = 0;
|
const byte CO2Command[] = {0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25};
|
||||||
CO2_READ_RESULT result;
|
byte CO2Response[] = {0,0,0,0,0,0,0};
|
||||||
const byte CO2Command[] = {0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25};
|
|
||||||
byte CO2Response[] = {0,0,0,0,0,0,0};
|
|
||||||
|
|
||||||
while(!(_SoftSerial_CO2->available())) {
|
_SoftSerial_CO2->write(CO2Command, 7);
|
||||||
retry++;
|
delay(100); //give the sensor a bit of time to respond
|
||||||
// keep sending request until we start to get a response
|
|
||||||
_SoftSerial_CO2->write(CO2Command, 7);
|
|
||||||
delay(50);
|
|
||||||
if (retry > 10) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int timeout = 0;
|
|
||||||
|
|
||||||
while (_SoftSerial_CO2->available() < 7) {
|
|
||||||
timeout++;
|
|
||||||
if (timeout > 10) {
|
|
||||||
while(_SoftSerial_CO2->available())
|
|
||||||
_SoftSerial_CO2->read();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
delay(50);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
if (_SoftSerial_CO2->available()){
|
||||||
for (int i=0; i < 7; i++) {
|
for (int i=0; i < 7; i++) {
|
||||||
int byte = _SoftSerial_CO2->read();
|
int byte = _SoftSerial_CO2->read();
|
||||||
if (byte == -1) {
|
CO2Response[i] = byte;
|
||||||
result.success = false;
|
if (CO2Response[0] != 254) {
|
||||||
return -1;
|
return -1; //error code for debugging
|
||||||
}
|
}
|
||||||
CO2Response[i] = byte;
|
|
||||||
}
|
}
|
||||||
int valMultiplier = 1;
|
unsigned long val = CO2Response[3]*256 + CO2Response[4];
|
||||||
int high = CO2Response[3];
|
|
||||||
int low = CO2Response[4];
|
|
||||||
unsigned long val = high*256 + low;
|
|
||||||
|
|
||||||
return val;
|
return val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return -2; //error code for debugging
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//END CO2 FUNCTIONS //
|
//END CO2 FUNCTIONS //
|
||||||
|
BIN
AirGradient.zip
BIN
AirGradient.zip
Binary file not shown.
@ -1,6 +1,6 @@
|
|||||||
The MIT License (MIT)
|
The MIT License (MIT)
|
||||||
|
|
||||||
Copyright (c) 2020 AirGradient
|
Copyright (c) 2022 AirGradient
|
||||||
|
|
||||||
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
|
||||||
|
@ -3,6 +3,6 @@ AirGradient Arduino Library for ESP8266 (Wemos D1 MINI)
|
|||||||
|
|
||||||
Build your own low cost air quality sensor with optional display measuring PM2.5, CO2, Temperature and Humidity.
|
Build your own low cost air quality sensor with optional display measuring PM2.5, CO2, Temperature and Humidity.
|
||||||
|
|
||||||
This library makes it easy to read the sensor data from the Plantower PMS5003 PM2.5 sensor, the Senseair S8 and the SHT30/31 Temperature and Humidity sensor. Visit our blog for detailed build instructions and PCB layout.
|
This library makes it easy to read the sensor data from the Plantower PMS5003 PM2.5 sensor, the Senseair S8 and the SHT30/31 Temperature and Humidity sensor. Visit our DIY section for detailed build instructions and PCB layout.
|
||||||
|
|
||||||
https://www.airgradient.com/blog/
|
https://www.airgradient.com/diy/
|
||||||
|
BIN
examples/C02_PM_SHT/.DS_Store
vendored
BIN
examples/C02_PM_SHT/.DS_Store
vendored
Binary file not shown.
@ -1,26 +0,0 @@
|
|||||||
#include <AirGradient.h>
|
|
||||||
AirGradient ag = AirGradient();
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
Serial.begin(9600);
|
|
||||||
ag.PMS_Init();
|
|
||||||
ag.CO2_Init();
|
|
||||||
ag.TMP_RH_Init(0x44); //check for SHT sensor with address 0x44
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
|
||||||
|
|
||||||
Serial.print("PM2: ");
|
|
||||||
Serial.println(ag.getPM2());
|
|
||||||
|
|
||||||
|
|
||||||
Serial.print("CO2: ");
|
|
||||||
Serial.println(ag.getCO2());
|
|
||||||
|
|
||||||
TMP_RH result = ag.periodicFetchData();
|
|
||||||
Serial.print("Humidity: ");
|
|
||||||
Serial.print(result.rh);
|
|
||||||
Serial.print(" Temperature: ");
|
|
||||||
Serial.println(result.t);
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
@ -1,41 +0,0 @@
|
|||||||
#include <AirGradient.h>
|
|
||||||
#include <Adafruit_GFX.h>
|
|
||||||
#include <Adafruit_SSD1306.h>
|
|
||||||
|
|
||||||
AirGradient ag = AirGradient();
|
|
||||||
#define OLED_RESET 0
|
|
||||||
Adafruit_SSD1306 display(OLED_RESET);
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
Serial.begin(9600);
|
|
||||||
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
|
||||||
ag.PMS_Init();
|
|
||||||
ag.CO2_Init();
|
|
||||||
ag.TMP_RH_Init(0x44); //check for SHT sensor with address 0x44
|
|
||||||
showTextRectangle("Init", String(ESP.getChipId(),HEX),"AirGradient");
|
|
||||||
delay(2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
|
||||||
int PM2 = ag.getPM2_Raw();
|
|
||||||
int CO2 = ag.getCO2_Raw();
|
|
||||||
TMP_RH result = ag.periodicFetchData();
|
|
||||||
showTextRectangle(String(result.t)+"c "+String(result.rh)+"%", "PM2: "+ String(ag.getPM2()), "CO2: "+String(ag.getCO2())+"");
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
||||||
|
|
||||||
// DISPLAY
|
|
||||||
void showTextRectangle(String ln1, String ln2, String ln3) {
|
|
||||||
display.clearDisplay();
|
|
||||||
display.setTextColor(WHITE);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.setCursor(32,8);
|
|
||||||
display.println(ln1);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.setCursor(32,16);
|
|
||||||
display.println(ln2);
|
|
||||||
display.setTextSize(1);
|
|
||||||
display.setCursor(32,24);
|
|
||||||
display.println(ln3);
|
|
||||||
display.display();
|
|
||||||
}
|
|
@ -1,77 +1,182 @@
|
|||||||
|
/*
|
||||||
|
This is the code for the AirGradient DIY Air Quality Sensor with an ESP8266 Microcontroller.
|
||||||
|
|
||||||
|
It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.
|
||||||
|
|
||||||
|
For build instructions please visit https://www.airgradient.com/diy/
|
||||||
|
|
||||||
|
Compatible with the following sensors:
|
||||||
|
Plantower PMS5003 (Fine Particle Sensor)
|
||||||
|
SenseAir S8 (CO2 Sensor)
|
||||||
|
SHT30/31 (Temperature/Humidity Sensor)
|
||||||
|
|
||||||
|
Please install ESP8266 board manager (tested with version 3.0.0)
|
||||||
|
|
||||||
|
The codes needs the following libraries installed:
|
||||||
|
"WifiManager by tzapu, tablatronix" tested with Version 2.0.3-alpha
|
||||||
|
"ESP8266 and ESP32 OLED driver for SSD1306 displays by ThingPulse, Fabrice Weinberg" tested with Version 4.1.0
|
||||||
|
|
||||||
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
Please set in the code below which sensor you are using and if you want to connect it to WiFi.
|
||||||
|
You can also switch PM2.5 from ug/m3 to US AQI and Celcius to Fahrenheit
|
||||||
|
|
||||||
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
|
https://www.airgradient.com/schools/
|
||||||
|
|
||||||
|
Kits with all required components are available at https://www.airgradient.com/diyshop/
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
#include <AirGradient.h>
|
#include <AirGradient.h>
|
||||||
#include <Adafruit_GFX.h>
|
|
||||||
#include <Adafruit_SSD1306.h>
|
|
||||||
#include <WiFiManager.h>
|
#include <WiFiManager.h>
|
||||||
|
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
|
|
||||||
#include <ESP8266HTTPClient.h>
|
#include <ESP8266HTTPClient.h>
|
||||||
|
|
||||||
AirGradient ag = AirGradient();
|
#include <Wire.h>
|
||||||
#define OLED_RESET 0
|
|
||||||
Adafruit_SSD1306 display(OLED_RESET);
|
|
||||||
|
|
||||||
|
#include "SSD1306Wire.h"
|
||||||
|
|
||||||
|
AirGradient ag = AirGradient();
|
||||||
|
|
||||||
|
SSD1306Wire display(0x3c, SDA, SCL);
|
||||||
|
|
||||||
|
// set sensors that you do not use to false
|
||||||
|
boolean hasPM = true;
|
||||||
|
boolean hasCO2 = true;
|
||||||
|
boolean hasSHT = true;
|
||||||
|
|
||||||
|
// set to true to switch PM2.5 from ug/m3 to US AQI
|
||||||
|
boolean inUSaqi = false;
|
||||||
|
|
||||||
|
// set to true to switch from Celcius to Fahrenheit
|
||||||
|
boolean inF = false;
|
||||||
|
|
||||||
|
// set to true if you want to connect to wifi. The display will show values only when the sensor has wifi connection
|
||||||
|
boolean connectWIFI = false;
|
||||||
|
|
||||||
|
// change if you want to send the data to another server
|
||||||
String APIROOT = "http://hw.airgradient.com/";
|
String APIROOT = "http://hw.airgradient.com/";
|
||||||
|
|
||||||
void setup(){
|
void setup() {
|
||||||
Serial.begin(9600);
|
Serial.begin(9600);
|
||||||
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
|
|
||||||
ag.PMS_Init();
|
display.init();
|
||||||
ag.CO2_Init();
|
display.flipScreenVertically();
|
||||||
ag.TMP_RH_Init(0x44); //check for SHT sensor with address 0x44
|
showTextRectangle("Init", String(ESP.getChipId(), HEX), true);
|
||||||
showTextRectangle("Init", String(ESP.getChipId(),HEX),"AirGradient");
|
|
||||||
connectToWifi();
|
if (hasPM) ag.PMS_Init();
|
||||||
|
if (hasCO2) ag.CO2_Init();
|
||||||
|
if (hasSHT) ag.TMP_RH_Init(0x44);
|
||||||
|
|
||||||
|
if (connectWIFI) connectToWifi();
|
||||||
delay(2000);
|
delay(2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
void loop(){
|
void loop() {
|
||||||
int PM2 = ag.getPM2_Raw();
|
|
||||||
int CO2 = ag.getCO2_Raw();
|
// create payload
|
||||||
TMP_RH result = ag.periodicFetchData();
|
|
||||||
showTextRectangle(String(result.t)+"c "+String(result.rh)+"%", "PM2: "+ String(PM2), "CO2: "+String(CO2)+"");
|
String payload = "{\"wifi\":" + String(WiFi.RSSI()) + ",";
|
||||||
|
|
||||||
|
if (hasPM) {
|
||||||
|
int PM2 = ag.getPM2_Raw();
|
||||||
|
payload = payload + "\"pm02\":" + String(PM2);
|
||||||
|
|
||||||
|
if (inUSaqi) {
|
||||||
|
showTextRectangle("AQI", String(PM_TO_AQI_US(PM2)), false);
|
||||||
|
} else {
|
||||||
|
showTextRectangle("PM2", String(PM2), false);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(3000);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCO2) {
|
||||||
|
if (hasPM) payload = payload + ",";
|
||||||
|
int CO2 = ag.getCO2_Raw();
|
||||||
|
payload = payload + "\"rco2\":" + String(CO2);
|
||||||
|
showTextRectangle("CO2", String(CO2), false);
|
||||||
|
delay(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSHT) {
|
||||||
|
if (hasCO2 || hasPM) payload = payload + ",";
|
||||||
|
TMP_RH result = ag.periodicFetchData();
|
||||||
|
payload = payload + "\"atmp\":" + String(result.t) + ",\"rhum\":" + String(result.rh);
|
||||||
|
|
||||||
|
if (inF) {
|
||||||
|
showTextRectangle(String((result.t * 9 / 5) + 32), String(result.rh) + "%", false);
|
||||||
|
} else {
|
||||||
|
showTextRectangle(String(result.t), String(result.rh) + "%", false);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
payload = payload + "}";
|
||||||
|
|
||||||
// send payload
|
// send payload
|
||||||
String payload = "{\"pm02\":" + String(ag.getPM2()) + ",\"wifi\":" + String(WiFi.RSSI()) + ",\"rco2\":" + String(ag.getCO2()) + ",\"atmp\":" + String(result.t) + ",\"rhum\":" + String(result.rh) + "}";
|
if (connectWIFI) {
|
||||||
Serial.println(payload);
|
Serial.println(payload);
|
||||||
String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(),HEX) + "/measures";
|
String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(), HEX) + "/measures";
|
||||||
Serial.println(POSTURL);
|
Serial.println(POSTURL);
|
||||||
HTTPClient http;
|
WiFiClient client;
|
||||||
http.begin(POSTURL);
|
HTTPClient http;
|
||||||
http.addHeader("content-type", "application/json");
|
http.begin(client, POSTURL);
|
||||||
int httpCode = http.POST(payload);
|
http.addHeader("content-type", "application/json");
|
||||||
String response = http.getString();
|
int httpCode = http.POST(payload);
|
||||||
Serial.println(httpCode);
|
String response = http.getString();
|
||||||
Serial.println(response);
|
Serial.println(httpCode);
|
||||||
http.end();
|
Serial.println(response);
|
||||||
|
http.end();
|
||||||
delay(15000);
|
delay(21000);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// DISPLAY
|
// DISPLAY
|
||||||
void showTextRectangle(String ln1, String ln2, String ln3) {
|
void showTextRectangle(String ln1, String ln2, boolean small) {
|
||||||
display.clearDisplay();
|
display.clear();
|
||||||
display.setTextColor(WHITE);
|
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
display.setTextSize(1);
|
if (small) {
|
||||||
display.setCursor(32,8);
|
display.setFont(ArialMT_Plain_16);
|
||||||
display.println(ln1);
|
} else {
|
||||||
display.setTextSize(1);
|
display.setFont(ArialMT_Plain_24);
|
||||||
display.setCursor(32,16);
|
}
|
||||||
display.println(ln2);
|
display.drawString(32, 16, ln1);
|
||||||
display.setTextSize(1);
|
display.drawString(32, 36, ln2);
|
||||||
display.setCursor(32,24);
|
|
||||||
display.println(ln3);
|
|
||||||
display.display();
|
display.display();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wifi Manager
|
// Wifi Manager
|
||||||
void connectToWifi(){
|
void connectToWifi() {
|
||||||
WiFiManager wifiManager;
|
WiFiManager wifiManager;
|
||||||
//chWiFi.disconnect(); //to delete previous saved hotspot
|
//WiFi.disconnect(); //to delete previous saved hotspot
|
||||||
String HOTSPOT = "AIRGRADIENT-"+String(ESP.getChipId(),HEX);
|
String HOTSPOT = "AIRGRADIENT-" + String(ESP.getChipId(), HEX);
|
||||||
wifiManager.setTimeout(120);
|
wifiManager.setTimeout(120);
|
||||||
if(!wifiManager.autoConnect((const char*)HOTSPOT.c_str())) {
|
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
|
||||||
//Serial.println("failed to connect and hit timeout");
|
Serial.println("failed to connect and hit timeout");
|
||||||
delay(3000);
|
delay(3000);
|
||||||
ESP.restart();
|
ESP.restart();
|
||||||
delay(5000);
|
delay(5000);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Calculate PM2.5 US AQI
|
||||||
|
int PM_TO_AQI_US(int pm02) {
|
||||||
|
if (pm02 <= 12.0) return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0);
|
||||||
|
else if (pm02 <= 35.4) return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50);
|
||||||
|
else if (pm02 <= 55.4) return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100);
|
||||||
|
else if (pm02 <= 150.4) return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150);
|
||||||
|
else if (pm02 <= 250.4) return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200);
|
||||||
|
else if (pm02 <= 350.4) return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300);
|
||||||
|
else if (pm02 <= 500.4) return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400);
|
||||||
|
else return 500;
|
||||||
|
};
|
||||||
|
38
examples/C02_SIMPLE/C02_SIMPLE.ino
Normal file
38
examples/C02_SIMPLE/C02_SIMPLE.ino
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
/*
|
||||||
|
This is the code for the AirGradient DIY Air Quality Sensor with an ESP8266 Microcontroller.
|
||||||
|
|
||||||
|
It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.
|
||||||
|
|
||||||
|
For build instructions please visit https://www.airgradient.com/diy/
|
||||||
|
|
||||||
|
Compatible with the following sensors:
|
||||||
|
SenseAir S8 (CO2 Sensor)
|
||||||
|
|
||||||
|
Please install ESP8266 board manager (tested with version 3.0.0)
|
||||||
|
|
||||||
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
|
https://www.airgradient.com/schools/
|
||||||
|
|
||||||
|
Kits with all required components are available at https://www.airgradient.com/diyshop/
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AirGradient.h>
|
||||||
|
AirGradient ag = AirGradient();
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
Serial.begin(9600);
|
||||||
|
ag.CO2_Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
|
||||||
|
int CO2 = ag.getCO2_Raw();
|
||||||
|
Serial.print("C02: ");
|
||||||
|
Serial.println(ag.getCO2());
|
||||||
|
|
||||||
|
delay(5000);
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
#include <AirGradient.h>
|
|
||||||
AirGradient ag = AirGradient();
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
Serial.begin(9600);
|
|
||||||
ag.CO2_Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
|
||||||
|
|
||||||
int CO2 = ag.getCO2_Raw();
|
|
||||||
Serial.print("C02: ");
|
|
||||||
Serial.println(ag.getCO2());
|
|
||||||
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
134
examples/CO2_TRAFFIC_LIGHT_SIMPLE/CO2_TRAFFIC_LIGHT_SIMPLE.ino
Normal file
134
examples/CO2_TRAFFIC_LIGHT_SIMPLE/CO2_TRAFFIC_LIGHT_SIMPLE.ino
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
/*
|
||||||
|
This is the code for the AirGradient DIY CO2 Traffic light with an ESP8266 Microcontroller.
|
||||||
|
|
||||||
|
For build instructions please visit https://www.airgradient.com/diy-co2-traffic-light/
|
||||||
|
|
||||||
|
Compatible with the following sensors:
|
||||||
|
SenseAir S8 (CO2 Sensor)
|
||||||
|
|
||||||
|
Please install ESP8266 board manager (tested with version 3.0.0)
|
||||||
|
|
||||||
|
Please install the following libraries:
|
||||||
|
"Adafruit NeoMatrix" Library (tested with 1.2.0)
|
||||||
|
"WifiManager by tzapu, tablatronix" tested with Version 2.0.3-alpha
|
||||||
|
|
||||||
|
Kits with all required components are available at https://www.airgradient.com/diyshop/
|
||||||
|
|
||||||
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
|
https://www.airgradient.com/schools/
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Adafruit_NeoMatrix example for single NeoPixel Shield.
|
||||||
|
// Scrolls 'Howdy' across the matrix in a portrait (vertical) orientation.
|
||||||
|
// Adafruit_NeoMatrix example for single NeoPixel Shield.
|
||||||
|
// Scrolls 'Howdy' across the matrix in a portrait (vertical) orientation.
|
||||||
|
|
||||||
|
#include <AirGradient.h>
|
||||||
|
#include <WiFiManager.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
|
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
#include <Adafruit_NeoMatrix.h>
|
||||||
|
#include <Adafruit_NeoPixel.h>
|
||||||
|
#ifndef PSTR
|
||||||
|
#define PSTR // Make Arduino Due happy
|
||||||
|
#endif
|
||||||
|
|
||||||
|
AirGradient ag = AirGradient();
|
||||||
|
#define PIN D8
|
||||||
|
|
||||||
|
int co2 = 0;
|
||||||
|
String text = "AirGradient CO2";
|
||||||
|
// set to true if you want to connect to wifi. The display will show values only when the sensor has wifi connection
|
||||||
|
boolean connectWIFI=true;
|
||||||
|
int greenToOrange = 800;
|
||||||
|
int orangeToRed = 1200;
|
||||||
|
|
||||||
|
// change if you want to send the data to another server
|
||||||
|
String APIROOT = "http://hw.airgradient.com/";
|
||||||
|
|
||||||
|
Adafruit_NeoMatrix matrix = Adafruit_NeoMatrix(8, 8, PIN,
|
||||||
|
NEO_MATRIX_TOP + NEO_MATRIX_RIGHT +
|
||||||
|
NEO_MATRIX_COLUMNS + NEO_MATRIX_PROGRESSIVE,
|
||||||
|
NEO_GRB + NEO_KHZ800);
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
ag.CO2_Init();
|
||||||
|
matrix.begin();
|
||||||
|
matrix.setRotation(1); // change rotation
|
||||||
|
matrix.setTextWrap(false);
|
||||||
|
matrix.setBrightness(40);
|
||||||
|
matrix.setTextColor(matrix.Color(70,130,180));
|
||||||
|
|
||||||
|
Serial.println("Chip ID: "+String(ESP.getChipId(),HEX));
|
||||||
|
if (connectWIFI) connectToWifi();
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
showText();
|
||||||
|
}
|
||||||
|
|
||||||
|
int x = matrix.width();
|
||||||
|
|
||||||
|
void showText() {
|
||||||
|
Serial.println("in loop");
|
||||||
|
matrix.fillScreen(0);
|
||||||
|
matrix.setCursor(x, 0);
|
||||||
|
matrix.print(String(text));
|
||||||
|
if(--x < -100) {
|
||||||
|
x = matrix.width();
|
||||||
|
Serial.println("end text");
|
||||||
|
co2 = ag.getCO2_Raw();
|
||||||
|
text = String(co2)+"ppm";
|
||||||
|
if (co2>350) matrix.setTextColor(matrix.Color(0, 255, 0));
|
||||||
|
if (co2>greenToOrange) matrix.setTextColor(matrix.Color(255, 90, 0));
|
||||||
|
if (co2>orangeToRed) matrix.setTextColor(matrix.Color(255,0, 0));
|
||||||
|
|
||||||
|
// send payload
|
||||||
|
String payload = "{\"wifi\":" + String(WiFi.RSSI()) + ",";
|
||||||
|
payload = payload + "\"rco2\":" + String(co2);
|
||||||
|
payload = payload + "}";
|
||||||
|
|
||||||
|
if (connectWIFI) {
|
||||||
|
Serial.println(payload);
|
||||||
|
String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(), HEX) + "/measures";
|
||||||
|
Serial.println(POSTURL);
|
||||||
|
WiFiClient client;
|
||||||
|
HTTPClient http;
|
||||||
|
http.begin(client, POSTURL);
|
||||||
|
http.addHeader("content-type", "application/json");
|
||||||
|
int httpCode = http.POST(payload);
|
||||||
|
String response = http.getString();
|
||||||
|
Serial.println(httpCode);
|
||||||
|
Serial.println(response);
|
||||||
|
http.end();
|
||||||
|
delay(20000);
|
||||||
|
}
|
||||||
|
|
||||||
|
delay(10000);
|
||||||
|
}
|
||||||
|
|
||||||
|
matrix.show();
|
||||||
|
delay(100);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wifi Manager
|
||||||
|
void connectToWifi(){
|
||||||
|
WiFiManager wifiManager;
|
||||||
|
//WiFi.disconnect(); //to delete previous saved hotspot
|
||||||
|
String HOTSPOT = "AIRGRADIENT-"+String(ESP.getChipId(),HEX);
|
||||||
|
wifiManager.setTimeout(120);
|
||||||
|
if(!wifiManager.autoConnect((const char*)HOTSPOT.c_str())) {
|
||||||
|
Serial.println("failed to connect and hit timeout");
|
||||||
|
delay(3000);
|
||||||
|
ESP.restart();
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
#include <AirGradient.h>
|
|
||||||
AirGradient ag = AirGradient();
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
Serial.begin(9600);
|
|
||||||
ag.MHZ19_Init(MHZ19B);
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
|
||||||
|
|
||||||
int MHZ19_C02 = ag.readMHZ19();
|
|
||||||
Serial.print("C02: ");
|
|
||||||
Serial.println(MHZ19_C02);
|
|
||||||
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
381
examples/MINI_DISPLAY/MINI_DISPLAY.ino
Normal file
381
examples/MINI_DISPLAY/MINI_DISPLAY.ino
Normal file
@ -0,0 +1,381 @@
|
|||||||
|
/*
|
||||||
|
This is the code for the AirGradient DIY Mini Display with an ESP8266 Microcontroller.
|
||||||
|
It can be configures to show the outside air quality as well as one indoor location from the AirGradient platform.
|
||||||
|
|
||||||
|
For build instructions please visit
|
||||||
|
|
||||||
|
https://www.airgradient.com/resources/airgradient-diy-display/
|
||||||
|
|
||||||
|
|
||||||
|
The codes needs the following libraries installed:
|
||||||
|
"WifiManager by tzapu, tablatronix" tested with Version 2.0.5-alpha
|
||||||
|
"Adafruit_ILI9341" tested with Version 1.5.10
|
||||||
|
"Adafruit GFX library" tested with Version 1.10.12 (often automatically installed with above ILI9341 library)
|
||||||
|
"ArduinoJSON" by Benoit Blanchon tested with Version 6.18.5
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
Please set in the code below (line 90-) if you want to display the PM2.5 values in US AQI and temperature in F.
|
||||||
|
|
||||||
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
|
|
||||||
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
|
https://www.airgradient.com/schools/
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <WiFiManager.h>
|
||||||
|
|
||||||
|
#include <ArduinoJson.h>
|
||||||
|
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
|
|
||||||
|
#include <SPI.h>
|
||||||
|
|
||||||
|
#include <Adafruit_GFX.h>
|
||||||
|
|
||||||
|
#include <Adafruit_ILI9341.h>
|
||||||
|
|
||||||
|
#include <Fonts/FreeSans9pt7b.h>
|
||||||
|
|
||||||
|
#include <Fonts/FreeSans12pt7b.h>
|
||||||
|
|
||||||
|
#include <Fonts/FreeSans18pt7b.h>
|
||||||
|
|
||||||
|
#define TFT_CS D0
|
||||||
|
#define TFT_DC D8
|
||||||
|
#define TFT_RST - 1
|
||||||
|
#define TS_CS D3
|
||||||
|
|
||||||
|
Adafruit_ILI9341 tft = Adafruit_ILI9341(TFT_CS, TFT_DC, TFT_RST);
|
||||||
|
|
||||||
|
const char * locNameInside;
|
||||||
|
const char * locNameOutside;
|
||||||
|
|
||||||
|
const char * place_timezone;
|
||||||
|
const char * location;
|
||||||
|
bool outdoor_offline;
|
||||||
|
bool indoor_offline;
|
||||||
|
const char * outdoor_policy;
|
||||||
|
const char * outdoor_date;
|
||||||
|
const char * indoor_date;
|
||||||
|
boolean prodMode = true;
|
||||||
|
|
||||||
|
String deviceID;
|
||||||
|
const char * timex;
|
||||||
|
int pm02;
|
||||||
|
int pi02;
|
||||||
|
int pi02_outside;
|
||||||
|
int rco2;
|
||||||
|
float atmp;
|
||||||
|
float atmp_outside;
|
||||||
|
int rhum_outside;
|
||||||
|
int rhum;
|
||||||
|
int heat;
|
||||||
|
|
||||||
|
const char * pi02_color;
|
||||||
|
const char * pi02_color_outside;
|
||||||
|
const char * pi02_category;
|
||||||
|
const char * pm02_color;
|
||||||
|
const char * pm02_category;
|
||||||
|
const char * rco2_color;
|
||||||
|
const char * rco2_category;
|
||||||
|
const char * heat_color;
|
||||||
|
const char * heat_color_outside;
|
||||||
|
const char * heat_category;
|
||||||
|
|
||||||
|
// Configuration
|
||||||
|
#define API_ROOT "http://hw.airgradient.com/displays/"
|
||||||
|
boolean inUSaqi = false;
|
||||||
|
boolean inF = false;
|
||||||
|
|
||||||
|
String getDeviceId() {
|
||||||
|
return String(ESP.getChipId(), HEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Chip ID");
|
||||||
|
Serial.println(String(ESP.getChipId(), HEX));
|
||||||
|
|
||||||
|
tft.begin();
|
||||||
|
tft.setRotation(2);
|
||||||
|
while (!Serial && (millis() <= 1000));
|
||||||
|
welcomeMessage();
|
||||||
|
connectToWifi();
|
||||||
|
|
||||||
|
Serial.print("Connecting");
|
||||||
|
while (WiFi.status() != WL_CONNECTED) {
|
||||||
|
delay(500);
|
||||||
|
Serial.print(".");
|
||||||
|
}
|
||||||
|
Serial.println();
|
||||||
|
|
||||||
|
tft.fillScreen(ILI9341_BLACK);
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
WiFiClient client;
|
||||||
|
HTTPClient http;
|
||||||
|
http.begin(client, API_ROOT + getDeviceId());
|
||||||
|
|
||||||
|
int httpCode = http.GET();
|
||||||
|
if (httpCode == 200) {
|
||||||
|
String airData = http.getString();
|
||||||
|
payloadToDataInside(airData);
|
||||||
|
Serial.print("airData1 : ");
|
||||||
|
Serial.println(airData);
|
||||||
|
} else {
|
||||||
|
Serial.println("error");
|
||||||
|
Serial.println(httpCode);
|
||||||
|
}
|
||||||
|
http.end();
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
updateDisplay();
|
||||||
|
|
||||||
|
delay(120000);
|
||||||
|
tft.fillScreen(ILI9341_BLACK);
|
||||||
|
tft.setTextColor(ILI9341_WHITE);
|
||||||
|
tft.setFont( & FreeSans12pt7b);
|
||||||
|
tft.setCursor(5, 20);
|
||||||
|
tft.println("requesting data...");
|
||||||
|
}
|
||||||
|
|
||||||
|
void payloadToDataInside(String payload) {
|
||||||
|
const size_t capacity = JSON_ARRAY_SIZE(1) + 2 * JSON_OBJECT_SIZE(2) + 2 * JSON_OBJECT_SIZE(3) + JSON_OBJECT_SIZE(4) + JSON_OBJECT_SIZE(10) + JSON_OBJECT_SIZE(13) + 530;
|
||||||
|
DynamicJsonBuffer jsonBuffer(capacity);
|
||||||
|
JsonObject & root = jsonBuffer.parseObject(payload);
|
||||||
|
location = root["place"]["name"];
|
||||||
|
place_timezone = root["place"]["timezone"];
|
||||||
|
JsonObject & outdoor = root["outdoor"];
|
||||||
|
locNameOutside = outdoor["name"];
|
||||||
|
outdoor_offline = outdoor["offline"];
|
||||||
|
outdoor_policy = outdoor["guidelines"][0]["title"];
|
||||||
|
JsonObject & outdoor_current = outdoor["current"];
|
||||||
|
|
||||||
|
atmp_outside = outdoor_current["atmp"];
|
||||||
|
rhum_outside = outdoor_current["rhum"];
|
||||||
|
outdoor_date = outdoor_current["date"];
|
||||||
|
JsonObject & indoor = root["indoor"];
|
||||||
|
locNameInside = indoor["name"];
|
||||||
|
indoor_offline = indoor["offline"];
|
||||||
|
JsonObject & indoor_current = indoor["current"];
|
||||||
|
|
||||||
|
atmp = indoor_current["atmp"];
|
||||||
|
rhum = indoor_current["rhum"];
|
||||||
|
rco2 = indoor_current["rco2"];
|
||||||
|
indoor_date = indoor_current["date"];
|
||||||
|
rco2_color = indoor_current["rco2_clr"];
|
||||||
|
rco2_category = indoor_current["rco2_lbl"];
|
||||||
|
|
||||||
|
if (inUSaqi) {
|
||||||
|
pi02_outside = outdoor_current["pi02"];
|
||||||
|
pi02_color_outside = outdoor_current["pi02_clr"];
|
||||||
|
pi02_category = outdoor_current["pi02_lbl"];
|
||||||
|
pi02 = indoor_current["pi02"];
|
||||||
|
pi02_color = indoor_current["pi02_clr"];
|
||||||
|
pi02_category = indoor_current["pi02_lbl"];
|
||||||
|
} else {
|
||||||
|
pi02_outside = outdoor_current["pm02"];
|
||||||
|
pi02_color_outside = outdoor_current["pm02_clr"];
|
||||||
|
pi02_category = outdoor_current["pm02_lbl"];
|
||||||
|
pi02 = indoor_current["pm02"];
|
||||||
|
pi02_color = indoor_current["pm02_clr"];
|
||||||
|
pi02_category = indoor_current["pm02_lbl"];
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateDisplay() {
|
||||||
|
int y = 25;
|
||||||
|
int boxHeight = 75;
|
||||||
|
int boxWidth = 110;
|
||||||
|
int radius = 8;
|
||||||
|
tft.fillScreen(ILI9341_BLACK);
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
|
||||||
|
tft.setCursor(5, y);
|
||||||
|
tft.println(location);
|
||||||
|
|
||||||
|
tft.drawLine(0, 35, 250, 35, ILI9341_WHITE);
|
||||||
|
|
||||||
|
y = y + 50;
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
|
||||||
|
tft.setCursor(5, y);
|
||||||
|
tft.println(locNameOutside);
|
||||||
|
tft.setFont( & FreeSans12pt7b);
|
||||||
|
|
||||||
|
y = y + 12;
|
||||||
|
|
||||||
|
if (String(pi02_color_outside) == "green") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_GREEN);
|
||||||
|
} else if (String(pi02_color_outside) == "yellow") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_YELLOW);
|
||||||
|
} else if (String(pi02_color_outside) == "orange") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_ORANGE);
|
||||||
|
} else if (String(pi02_color_outside) == "red") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_RED);
|
||||||
|
} else if (String(pi02_color_outside) == "purple") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_PURPLE);
|
||||||
|
} else if (String(pi02_color_outside) == "brown") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_MAROON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String(heat_color_outside) == "green") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_GREEN);
|
||||||
|
} else if (String(heat_color_outside) == "yellow") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_YELLOW);
|
||||||
|
} else if (String(heat_color_outside) == "orange") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_ORANGE);
|
||||||
|
} else if (String(heat_color_outside) == "red") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_RED);
|
||||||
|
} else if (String(heat_color_outside) == "purple") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_PURPLE);
|
||||||
|
} else if (String(heat_color_outside) == "brown") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_MAROON);
|
||||||
|
}
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK);
|
||||||
|
tft.setCursor(20, y + boxHeight - 10);
|
||||||
|
|
||||||
|
if (inUSaqi) {
|
||||||
|
tft.println("US AQI");
|
||||||
|
} else {
|
||||||
|
tft.println("ug/m3");
|
||||||
|
}
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans18pt7b);
|
||||||
|
tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK);
|
||||||
|
tft.setCursor(20, y + 40);
|
||||||
|
tft.println(String(pi02_outside));
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
|
||||||
|
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
|
||||||
|
|
||||||
|
tft.setCursor(20 + boxWidth + 10, y + 20);
|
||||||
|
|
||||||
|
if (inF) {
|
||||||
|
tft.println(String((atmp_outside * 9 / 5) + 32) + "F");
|
||||||
|
} else {
|
||||||
|
tft.println(String(atmp_outside) + "C");
|
||||||
|
}
|
||||||
|
|
||||||
|
tft.setCursor(20 + boxWidth + 10, y + 40);
|
||||||
|
tft.println(String(rhum_outside) + "%");
|
||||||
|
|
||||||
|
tft.setTextColor(ILI9341_DARKGREY, ILI9341_BLACK);
|
||||||
|
tft.setCursor(20 + boxWidth + 10, y + 60);
|
||||||
|
tft.println(String(outdoor_date));
|
||||||
|
|
||||||
|
//inside
|
||||||
|
|
||||||
|
y = y + 110;
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
tft.setTextColor(ILI9341_WHITE, ILI9341_BLACK);
|
||||||
|
tft.setCursor(5, y);
|
||||||
|
tft.println(locNameInside);
|
||||||
|
tft.setFont( & FreeSans12pt7b);
|
||||||
|
|
||||||
|
y = y + 12;
|
||||||
|
|
||||||
|
if (String(pi02_color) == "green") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_GREEN);
|
||||||
|
} else if (String(pi02_color) == "yellow") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_YELLOW);
|
||||||
|
} else if (String(pi02_color) == "orange") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_ORANGE);
|
||||||
|
} else if (String(pi02_color) == "red") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_RED);
|
||||||
|
} else if (String(pi02_color) == "purple") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_PURPLE);
|
||||||
|
} else if (String(pi02_color) == "brown") {
|
||||||
|
tft.fillRoundRect(5, y, boxWidth, boxHeight, radius, ILI9341_MAROON);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (String(rco2_color) == "green") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_GREEN);
|
||||||
|
} else if (String(rco2_color) == "yellow") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_YELLOW);
|
||||||
|
} else if (String(rco2_color) == "orange") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_ORANGE);
|
||||||
|
} else if (String(rco2_color) == "red") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_RED);
|
||||||
|
} else if (String(rco2_color) == "purple") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_PURPLE);
|
||||||
|
} else if (String(rco2_color) == "brown") {
|
||||||
|
tft.fillRoundRect(5 + boxWidth + 10, y, boxWidth, boxHeight, radius, ILI9341_MAROON);
|
||||||
|
}
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK);
|
||||||
|
tft.setCursor(20, y + boxHeight - 10);
|
||||||
|
|
||||||
|
if (inUSaqi) {
|
||||||
|
tft.println("US AQI");
|
||||||
|
} else {
|
||||||
|
tft.println("ug/m3");
|
||||||
|
}
|
||||||
|
|
||||||
|
tft.setCursor(20 + boxWidth + 10, y + boxHeight - 10);
|
||||||
|
tft.println("CO2 ppm");
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans18pt7b);
|
||||||
|
tft.setTextColor(ILI9341_BLACK, ILI9341_BLACK);
|
||||||
|
tft.setCursor(20, y + 40);
|
||||||
|
tft.println(String(pi02));
|
||||||
|
tft.setCursor(20 + boxWidth + 10, y + 40);
|
||||||
|
tft.println(String(rco2));
|
||||||
|
|
||||||
|
y = y + 100;
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
tft.setTextColor(ILI9341_DARKGREY, ILI9341_BLACK);
|
||||||
|
tft.setCursor(boxWidth - 30, y);
|
||||||
|
tft.println(String(indoor_date));
|
||||||
|
}
|
||||||
|
|
||||||
|
void welcomeMessage() {
|
||||||
|
Serial.println("Welcome Message 2");
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
tft.fillScreen(ILI9341_BLACK);
|
||||||
|
tft.setTextColor(ILI9341_WHITE);
|
||||||
|
|
||||||
|
tft.setCursor(40, 24);
|
||||||
|
tft.setFont( & FreeSans12pt7b);
|
||||||
|
tft.setCursor(5, 20);
|
||||||
|
tft.println("AirGradient");
|
||||||
|
|
||||||
|
tft.setFont( & FreeSans9pt7b);
|
||||||
|
tft.setCursor(5, 100);
|
||||||
|
tft.println("id: " + String(ESP.getChipId(), HEX));
|
||||||
|
|
||||||
|
tft.setCursor(5, 140);
|
||||||
|
tft.println("connecting ...");
|
||||||
|
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void connectToWifi() {
|
||||||
|
delay(2000);
|
||||||
|
|
||||||
|
WiFiManager wifiManager;
|
||||||
|
//chWiFi.disconnect(); //to delete previous saved hotspot
|
||||||
|
String HOTSPOT = "AIRGRADIENT-DISPLAY-" + String(ESP.getChipId(), HEX);
|
||||||
|
wifiManager.setTimeout(120);
|
||||||
|
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
|
||||||
|
Serial.println("failed to connect and hit timeout");
|
||||||
|
delay(3000);
|
||||||
|
ESP.restart();
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
}
|
54
examples/PM2_SIMPLE/PM2_SIMPLE.ino
Normal file
54
examples/PM2_SIMPLE/PM2_SIMPLE.ino
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
/*
|
||||||
|
This is the code for the AirGradient DIY Air Quality Sensor with an ESP8266 Microcontroller.
|
||||||
|
|
||||||
|
It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.
|
||||||
|
|
||||||
|
For build instructions please visit https://www.airgradient.com/diy/
|
||||||
|
|
||||||
|
Compatible with the following sensors:
|
||||||
|
Plantower PMS5003 (Fine Particle Sensor)
|
||||||
|
|
||||||
|
Please install ESP8266 board manager (tested with version 3.0.0)
|
||||||
|
|
||||||
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
|
https://www.airgradient.com/schools/
|
||||||
|
|
||||||
|
Kits with all required components are available at https://www.airgradient.com/diyshop/
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AirGradient.h>
|
||||||
|
|
||||||
|
AirGradient ag = AirGradient();
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(9600);
|
||||||
|
ag.PMS_Init();
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
int PM2 = ag.getPM2_Raw();
|
||||||
|
|
||||||
|
Serial.print("PM2.5 in ug/m3: ");
|
||||||
|
Serial.println(String(PM2));
|
||||||
|
|
||||||
|
Serial.print("PM2.5 in US AQI: ");
|
||||||
|
Serial.println(String(PM_TO_AQI_US(PM2)));
|
||||||
|
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PM_TO_AQI_US(int pm02) {
|
||||||
|
if (pm02 <= 12.0) return ((50 - 0) / (12.0 - .0) * (pm02 - .0) + 0);
|
||||||
|
else if (pm02 <= 35.4) return ((100 - 50) / (35.4 - 12.0) * (pm02 - 12.0) + 50);
|
||||||
|
else if (pm02 <= 55.4) return ((150 - 100) / (55.4 - 35.4) * (pm02 - 35.4) + 100);
|
||||||
|
else if (pm02 <= 150.4) return ((200 - 150) / (150.4 - 55.4) * (pm02 - 55.4) + 150);
|
||||||
|
else if (pm02 <= 250.4) return ((300 - 200) / (250.4 - 150.4) * (pm02 - 150.4) + 200);
|
||||||
|
else if (pm02 <= 350.4) return ((400 - 300) / (350.4 - 250.4) * (pm02 - 250.4) + 300);
|
||||||
|
else if (pm02 <= 500.4) return ((500 - 400) / (500.4 - 350.4) * (pm02 - 350.4) + 400);
|
||||||
|
else return 500;
|
||||||
|
};
|
@ -1,16 +0,0 @@
|
|||||||
#include <AirGradient.h>
|
|
||||||
AirGradient ag = AirGradient();
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
Serial.begin(9600);
|
|
||||||
ag.PMS_Init();
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
|
||||||
|
|
||||||
int PM2 = ag.getPM2_Raw();
|
|
||||||
Serial.print("PM2: ");
|
|
||||||
Serial.println(ag.getPM2());
|
|
||||||
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
45
examples/SHT_SIMPLE/SHT_SIMPLE.ino
Normal file
45
examples/SHT_SIMPLE/SHT_SIMPLE.ino
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
This is the code for the AirGradient DIY Air Quality Sensor with an ESP8266 Microcontroller.
|
||||||
|
|
||||||
|
It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.
|
||||||
|
|
||||||
|
For build instructions please visit https://www.airgradient.com/diy/
|
||||||
|
|
||||||
|
Compatible with the following sensors:
|
||||||
|
SHT30/31 (Temperature/Humidity Sensor)
|
||||||
|
|
||||||
|
Please install ESP8266 board manager (tested with version 3.0.0)
|
||||||
|
|
||||||
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
|
https://www.airgradient.com/schools/
|
||||||
|
|
||||||
|
Kits with all required components are available at https://www.airgradient.com/diyshop/
|
||||||
|
|
||||||
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <AirGradient.h>
|
||||||
|
AirGradient ag = AirGradient();
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
Serial.begin(9600);
|
||||||
|
ag.TMP_RH_Init(0x44); //check for SHT sensor with address 0x44
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
|
||||||
|
TMP_RH result = ag.periodicFetchData();
|
||||||
|
|
||||||
|
Serial.print("Relative Humidity in %: ");
|
||||||
|
Serial.println(result.rh);
|
||||||
|
|
||||||
|
Serial.print(" Temperature in Celcius: ");
|
||||||
|
Serial.println(result.t);
|
||||||
|
|
||||||
|
Serial.print(" Temperature in Fahrenheit: ");
|
||||||
|
Serial.println((result.t * 9 / 5) + 32);
|
||||||
|
|
||||||
|
delay(5000);
|
||||||
|
}
|
@ -1,16 +0,0 @@
|
|||||||
#include <AirGradient.h>
|
|
||||||
AirGradient ag = AirGradient();
|
|
||||||
|
|
||||||
void setup(){
|
|
||||||
Serial.begin(9600);
|
|
||||||
ag.TMP_RH_Init(0x44); //check for SHT sensor with address 0x44
|
|
||||||
}
|
|
||||||
|
|
||||||
void loop(){
|
|
||||||
TMP_RH result = ag.periodicFetchData();
|
|
||||||
Serial.print("Humidity: ");
|
|
||||||
Serial.print(result.rh_char);
|
|
||||||
Serial.print(" Temperature: ");
|
|
||||||
Serial.println(result.t_char);
|
|
||||||
delay(5000);
|
|
||||||
}
|
|
158
examples/TVOC/TVOC.ino
Normal file
158
examples/TVOC/TVOC.ino
Normal file
@ -0,0 +1,158 @@
|
|||||||
|
/*
|
||||||
|
This is the code for the AirGradient DIY Air Quality Sensor with an ESP8266 Microcontroller.
|
||||||
|
|
||||||
|
It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.
|
||||||
|
|
||||||
|
For build instructions please visit https://www.airgradient.com/diy/
|
||||||
|
|
||||||
|
Instructions on using the TVOC sensor (SGP30) instead of the Temperature / Humidity sensor (SHT3x).
|
||||||
|
|
||||||
|
https://www.airgradient.com/resources/tvoc-on-airgradient-diy-sensor/
|
||||||
|
|
||||||
|
The codes needs the following libraries installed:
|
||||||
|
"WifiManager by tzapu, tablatronix" tested with Version 2.0.3-alpha
|
||||||
|
"ESP8266 and ESP32 OLED driver for SSD1306 displays by ThingPulse, Fabrice Weinberg" tested with Version 4.1.0
|
||||||
|
"SGP30" by Rob Tillaart tested with Version 0.1.4
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
Please set in the code below which sensor you are using and if you want to connect it to WiFi.
|
||||||
|
|
||||||
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
|
https://www.airgradient.com/schools/
|
||||||
|
|
||||||
|
MIT License
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "SGP30.h"
|
||||||
|
SGP30 SGP;
|
||||||
|
|
||||||
|
#include <AirGradient.h>
|
||||||
|
#include <WiFiManager.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
|
|
||||||
|
#include <Wire.h>
|
||||||
|
#include "SSD1306Wire.h"
|
||||||
|
|
||||||
|
AirGradient ag = AirGradient();
|
||||||
|
|
||||||
|
SSD1306Wire display(0x3c, SDA, SCL);
|
||||||
|
|
||||||
|
WiFiClient client;
|
||||||
|
|
||||||
|
// set sensors that you do not use to false
|
||||||
|
boolean hasPM=true;
|
||||||
|
boolean hasCO2=true;
|
||||||
|
boolean hasSHT=false;
|
||||||
|
boolean hasTVOC=true;
|
||||||
|
|
||||||
|
// set to true if you want to connect to wifi. The display will show values only when the sensor has wifi connection
|
||||||
|
boolean connectWIFI=true;
|
||||||
|
|
||||||
|
// change if you want to send the data to another server
|
||||||
|
String APIROOT = "http://hw.airgradient.com/";
|
||||||
|
|
||||||
|
void setup(){
|
||||||
|
Serial.begin(9600);
|
||||||
|
|
||||||
|
display.init();
|
||||||
|
display.flipScreenVertically();
|
||||||
|
showTextRectangle("Init", String(ESP.getChipId(),HEX),true);
|
||||||
|
|
||||||
|
if (hasTVOC) SGP.begin();
|
||||||
|
if (hasPM) ag.PMS_Init();
|
||||||
|
if (hasCO2) ag.CO2_Init();
|
||||||
|
if (hasSHT) ag.TMP_RH_Init(0x44);
|
||||||
|
|
||||||
|
if (connectWIFI) connectToWifi();
|
||||||
|
delay(2000);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop(){
|
||||||
|
|
||||||
|
if (hasTVOC) SGP.measure(false);
|
||||||
|
|
||||||
|
// create payload
|
||||||
|
|
||||||
|
String payload = "{\"wifi\":" + String(WiFi.RSSI()) + ",";
|
||||||
|
|
||||||
|
if (hasPM) {
|
||||||
|
int PM2 = ag.getPM2_Raw();
|
||||||
|
payload=payload+"\"pm02\":" + String(PM2);
|
||||||
|
showTextRectangle("PM2",String(PM2),false);
|
||||||
|
delay(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasTVOC) {
|
||||||
|
if (hasPM) payload=payload+",";
|
||||||
|
int TVOC = SGP.getTVOC();
|
||||||
|
payload=payload+"\"tvoc\":" + String(TVOC);
|
||||||
|
showTextRectangle("TVOC",String(TVOC),false);
|
||||||
|
delay(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasCO2) {
|
||||||
|
if (hasTVOC) payload=payload+",";
|
||||||
|
int CO2 = ag.getCO2_Raw();
|
||||||
|
payload=payload+"\"rco2\":" + String(CO2);
|
||||||
|
showTextRectangle("CO2",String(CO2),false);
|
||||||
|
delay(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasSHT) {
|
||||||
|
if (hasCO2 || hasPM) payload=payload+",";
|
||||||
|
TMP_RH result = ag.periodicFetchData();
|
||||||
|
payload=payload+"\"atmp\":" + String(result.t) + ",\"rhum\":" + String(result.rh);
|
||||||
|
showTextRectangle(String(result.t),String(result.rh)+"%",false);
|
||||||
|
delay(3000);
|
||||||
|
}
|
||||||
|
|
||||||
|
payload=payload+"}";
|
||||||
|
|
||||||
|
// send payload
|
||||||
|
if (connectWIFI){
|
||||||
|
Serial.println(payload);
|
||||||
|
String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(),HEX) + "/measures";
|
||||||
|
Serial.println(POSTURL);
|
||||||
|
WiFiClient client;
|
||||||
|
HTTPClient http;
|
||||||
|
http.begin(client, POSTURL);
|
||||||
|
http.addHeader("content-type", "application/json");
|
||||||
|
int httpCode = http.POST(payload);
|
||||||
|
String response = http.getString();
|
||||||
|
Serial.println(httpCode);
|
||||||
|
Serial.println(response);
|
||||||
|
http.end();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// DISPLAY
|
||||||
|
void showTextRectangle(String ln1, String ln2, boolean small) {
|
||||||
|
display.clear();
|
||||||
|
display.setTextAlignment(TEXT_ALIGN_LEFT);
|
||||||
|
if (small) {
|
||||||
|
display.setFont(ArialMT_Plain_16);
|
||||||
|
} else {
|
||||||
|
display.setFont(ArialMT_Plain_24);
|
||||||
|
}
|
||||||
|
display.drawString(32, 16, ln1);
|
||||||
|
display.drawString(32, 36, ln2);
|
||||||
|
display.display();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wifi Manager
|
||||||
|
void connectToWifi(){
|
||||||
|
WiFiManager wifiManager;
|
||||||
|
//WiFi.disconnect(); //to delete previous saved hotspot
|
||||||
|
String HOTSPOT = "AIRGRADIENT-"+String(ESP.getChipId(),HEX);
|
||||||
|
wifiManager.setTimeout(120);
|
||||||
|
if(!wifiManager.autoConnect((const char*)HOTSPOT.c_str())) {
|
||||||
|
Serial.println("failed to connect and hit timeout");
|
||||||
|
delay(3000);
|
||||||
|
ESP.restart();
|
||||||
|
delay(5000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
name=AirGradient Air Quality Sensor
|
name=AirGradient Air Quality Sensor
|
||||||
version=1.0.0
|
version=1.4.2
|
||||||
author=AirGradient <support@airgradient.com>
|
author=AirGradient <support@airgradient.com>
|
||||||
maintainer=AirGradient <support@airgradient.com>
|
maintainer=AirGradient <support@airgradient.com>
|
||||||
sentence=ESP8266 library for an air quality sensor featuring PM2.5, CO2, Temperature and Humidity with OLED display.
|
sentence=ESP8266 library for an air quality sensor featuring PM2.5, CO2, Temperature and Humidity with OLED display.
|
||||||
|
41
readme.txt
41
readme.txt
@ -1,39 +1,8 @@
|
|||||||
This is an example C++ library for Arduino 0004+, based on one created by
|
AirGradient Arduino Library for ESP8266 (Wemos D1 MINI)
|
||||||
Nicholas Zambetti for Wiring 0006+
|
=====================================================================================================
|
||||||
|
|
||||||
Installation
|
Build your own low cost air quality sensor with optional display measuring PM2.5, CO2, Temperature and Humidity.
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
To install this library, just place this entire folder as a subfolder in your
|
This library makes it easy to read the sensor data from the Plantower PMS5003 PM2.5 sensor, the Senseair S8 and the SHT30/31 Temperature and Humidity sensor. Visit our DIY section for detailed build instructions and PCB layout.
|
||||||
Arduino/lib/targets/libraries folder.
|
|
||||||
|
|
||||||
When installed, this library should look like:
|
|
||||||
|
|
||||||
Arduino/lib/targets/libraries/Test (this library's folder)
|
|
||||||
Arduino/lib/targets/libraries/Test/Test.cpp (the library implementation file)
|
|
||||||
Arduino/lib/targets/libraries/Test/Test.h (the library description file)
|
|
||||||
Arduino/lib/targets/libraries/Test/keywords.txt (the syntax coloring file)
|
|
||||||
Arduino/lib/targets/libraries/Test/examples (the examples in the "open" menu)
|
|
||||||
Arduino/lib/targets/libraries/Test/readme.txt (this file)
|
|
||||||
|
|
||||||
Building
|
|
||||||
--------------------------------------------------------------------------------
|
|
||||||
|
|
||||||
After this library is installed, you just have to start the Arduino application.
|
|
||||||
You may see a few warning messages as it's built.
|
|
||||||
|
|
||||||
To use this library in a sketch, go to the Sketch | Import Library menu and
|
|
||||||
select Test. This will add a corresponding line to the top of your sketch:
|
|
||||||
#include <Test.h>
|
|
||||||
|
|
||||||
To stop using this library, delete that line from your sketch.
|
|
||||||
|
|
||||||
Geeky information:
|
|
||||||
After a successful build of this library, a new file named "Test.o" will appear
|
|
||||||
in "Arduino/lib/targets/libraries/Test". This file is the built/compiled library
|
|
||||||
code.
|
|
||||||
|
|
||||||
If you choose to modify the code for this library (i.e. "Test.cpp" or "Test.h"),
|
|
||||||
then you must first 'unbuild' this library by deleting the "Test.o" file. The
|
|
||||||
new "Test.o" with your code will appear after the next press of "verify"
|
|
||||||
|
|
||||||
|
https://www.airgradient.com/diy/
|
||||||
|
Reference in New Issue
Block a user