mirror of
https://github.com/airgradienthq/arduino.git
synced 2025-06-27 16:50:58 +02:00
Compare commits
11 Commits
Author | SHA1 | Date | |
---|---|---|---|
c53517cadf | |||
6314e52770 | |||
43f599a0a7 | |||
cfc37d2d96 | |||
693d1f78aa | |||
ef802593a6 | |||
8ec543e9c1 | |||
9722eda5fa | |||
253d8a6810 | |||
6101429d30 | |||
47c55ae0dd |
@ -725,48 +725,6 @@ void AirGradient::CO2_Init(int rx_pin,int tx_pin,int baudRate){
|
|||||||
delay(10000);
|
delay(10000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//const char* AirGradient::getCO2(int retryLimit) {
|
|
||||||
// int ctr = 0;
|
|
||||||
// int result_CO2 = getCO2_Raw();
|
|
||||||
// while(result_CO2 == -1){
|
|
||||||
// result_CO2 = getCO2_Raw();
|
|
||||||
// if((ctr == retryLimit) || (result_CO2 == -1)){
|
|
||||||
// Char_CO2[0] = 'N';
|
|
||||||
// Char_CO2[1] = 'U';
|
|
||||||
// Char_CO2[2] = 'L';
|
|
||||||
// Char_CO2[3] = 'L';
|
|
||||||
// return Char_CO2;
|
|
||||||
// }
|
|
||||||
// ctr++;
|
|
||||||
// }
|
|
||||||
// sprintf(Char_CO2,"%d", result_CO2);
|
|
||||||
// return Char_CO2;
|
|
||||||
//}
|
|
||||||
|
|
||||||
|
|
||||||
//int AirGradient::getCO2_Raw(){
|
|
||||||
// const byte CO2Command[] = {0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25};
|
|
||||||
// byte CO2Response[] = {0,0,0,0,0,0,0};
|
|
||||||
//
|
|
||||||
// _SoftSerial_CO2->write(CO2Command, 7);
|
|
||||||
// delay(100); //give the sensor a bit of time to respond
|
|
||||||
//
|
|
||||||
// if (_SoftSerial_CO2->available()){
|
|
||||||
// for (int i=0; i < 7; i++) {
|
|
||||||
// int byte = _SoftSerial_CO2->read();
|
|
||||||
// CO2Response[i] = byte;
|
|
||||||
// if (CO2Response[0] != 254) {
|
|
||||||
// return -1; //error code for debugging
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// unsigned long val = CO2Response[3]*256 + CO2Response[4];
|
|
||||||
// return val;
|
|
||||||
// }
|
|
||||||
// else
|
|
||||||
// {
|
|
||||||
// return -2; //error code for debugging
|
|
||||||
// }
|
|
||||||
//}
|
|
||||||
|
|
||||||
int AirGradient::getCO2(int numberOfSamplesToTake) {
|
int AirGradient::getCO2(int numberOfSamplesToTake) {
|
||||||
int successfulSamplesCounter = 0;
|
int successfulSamplesCounter = 0;
|
||||||
@ -800,14 +758,12 @@ int AirGradient::getCO2_Raw() {
|
|||||||
while(_SoftSerial_CO2->available()) // flush whatever we might have
|
while(_SoftSerial_CO2->available()) // flush whatever we might have
|
||||||
_SoftSerial_CO2->read();
|
_SoftSerial_CO2->read();
|
||||||
|
|
||||||
const byte CO2Command[] = {0xFE, 0X44, 0X00, 0X08, 0X02, 0X9F, 0X25};
|
const byte CO2Command[] = {0XFE, 0X04, 0X00, 0X03, 0X00, 0X01, 0XD5, 0XC5};
|
||||||
byte CO2Response[] = {0,0,0,0,0,0,0};
|
byte CO2Response[] = {0,0,0,0,0,0,0};
|
||||||
|
|
||||||
// tt
|
|
||||||
int datapos = -1;
|
int datapos = -1;
|
||||||
//
|
|
||||||
|
|
||||||
const int commandSize = 7;
|
const int commandSize = 8;
|
||||||
|
const int responseSize = 7;
|
||||||
|
|
||||||
int numberOfBytesWritten = _SoftSerial_CO2->write(CO2Command, commandSize);
|
int numberOfBytesWritten = _SoftSerial_CO2->write(CO2Command, commandSize);
|
||||||
|
|
||||||
@ -818,7 +774,7 @@ int AirGradient::getCO2_Raw() {
|
|||||||
|
|
||||||
// attempt to read response
|
// attempt to read response
|
||||||
int timeoutCounter = 0;
|
int timeoutCounter = 0;
|
||||||
while (_SoftSerial_CO2->available() < commandSize) {
|
while (_SoftSerial_CO2->available() < responseSize) {
|
||||||
timeoutCounter++;
|
timeoutCounter++;
|
||||||
if (timeoutCounter > 10) {
|
if (timeoutCounter > 10) {
|
||||||
// timeout when reading response
|
// timeout when reading response
|
||||||
@ -828,22 +784,15 @@ int AirGradient::getCO2_Raw() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// we have 7 bytes ready to be read
|
// we have 7 bytes ready to be read
|
||||||
for (int i=0; i < commandSize; i++) {
|
for (int i=0; i < responseSize; i++) {
|
||||||
CO2Response[i] = _SoftSerial_CO2->read();
|
CO2Response[i] = _SoftSerial_CO2->read();
|
||||||
|
|
||||||
// tt
|
|
||||||
if ((CO2Response[i] == 0xFE) && (datapos == -1)){
|
if ((CO2Response[i] == 0xFE) && (datapos == -1)){
|
||||||
datapos = i;
|
datapos = i;
|
||||||
}
|
}
|
||||||
Serial.print (CO2Response[i],HEX);
|
Serial.print (CO2Response[i],HEX);
|
||||||
Serial.print (":");
|
Serial.print (":");
|
||||||
//
|
|
||||||
}
|
}
|
||||||
// return CO2Response[3]*256 + CO2Response[4];
|
|
||||||
// tt
|
|
||||||
return CO2Response[datapos + 3]*256 + CO2Response[datapos + 4];
|
return CO2Response[datapos + 3]*256 + CO2Response[datapos + 4];
|
||||||
//
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//END CO2 FUNCTIONS //
|
//END CO2 FUNCTIONS //
|
||||||
|
@ -17,7 +17,8 @@ https://www.airgradient.com/
|
|||||||
|
|
||||||
Kits with all required components are available at https://www.airgradient.com/open-airgradient/shop/
|
Kits with all required components are available at https://www.airgradient.com/open-airgradient/shop/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AirGradient.h>
|
#include <AirGradient.h>
|
||||||
|
@ -21,7 +21,8 @@ If you have any questions please visit our forum at https://forum.airgradient.co
|
|||||||
If you are a school or university contact us for a free trial on the AirGradient platform.
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
https://www.airgradient.com/
|
https://www.airgradient.com/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AirGradient.h>
|
#include <AirGradient.h>
|
||||||
|
@ -78,16 +78,14 @@ long val;
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
u8g2.setBusClock(100000);
|
||||||
u8g2.begin();
|
u8g2.begin();
|
||||||
updateOLED();
|
updateOLED();
|
||||||
|
|
||||||
if (connectWIFI) {
|
if (connectWIFI) {
|
||||||
connectToWifi();
|
connectToWifi();
|
||||||
}
|
}
|
||||||
|
updateOLED2("Warm Up", "Serial#", String(ESP.getChipId(), HEX));
|
||||||
updateOLED2("Warming", "up the", "sensors");
|
|
||||||
|
|
||||||
ag.CO2_Init();
|
ag.CO2_Init();
|
||||||
ag.PMS_Init();
|
ag.PMS_Init();
|
||||||
ag.TMP_RH_Init(0x44);
|
ag.TMP_RH_Init(0x44);
|
||||||
@ -207,9 +205,9 @@ void sendToServer() {
|
|||||||
WiFiManager wifiManager;
|
WiFiManager wifiManager;
|
||||||
//WiFi.disconnect(); //to delete previous saved hotspot
|
//WiFi.disconnect(); //to delete previous saved hotspot
|
||||||
String HOTSPOT = "AG-" + String(ESP.getChipId(), HEX);
|
String HOTSPOT = "AG-" + String(ESP.getChipId(), HEX);
|
||||||
updateOLED2("Connect", "Wifi", HOTSPOT);
|
updateOLED2("Connect", "Wifi AG-", String(ESP.getChipId(), HEX));
|
||||||
delay(2000);
|
delay(2000);
|
||||||
wifiManager.setTimeout(60);
|
wifiManager.setTimeout(90);
|
||||||
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
|
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
|
||||||
updateOLED2("Booting", "offline", "mode");
|
updateOLED2("Booting", "offline", "mode");
|
||||||
Serial.println("failed to connect and hit timeout");
|
Serial.println("failed to connect and hit timeout");
|
||||||
|
@ -1,3 +1,22 @@
|
|||||||
|
/*
|
||||||
|
Important: This code is only for the AirGradient DIY OUTDOOR.
|
||||||
|
|
||||||
|
Build Instructions: https://www.airgradient.com/open-airgradient/instructions/diy-outdoor/
|
||||||
|
|
||||||
|
Kits (including a pre-soldered version) are available: https://www.airgradient.com/open-airgradient/kits/
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
Install required libraries
|
||||||
|
Patch PMS library to accept temperature and humidity from PMS5003T
|
||||||
|
|
||||||
|
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/
|
||||||
|
|
||||||
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
*/
|
||||||
|
|
||||||
#include "PMS.h"
|
#include "PMS.h"
|
||||||
#include "SoftwareSerial.h"
|
#include "SoftwareSerial.h"
|
||||||
#include <Wire.h>
|
#include <Wire.h>
|
||||||
@ -7,21 +26,20 @@
|
|||||||
#include <ESP8266HTTPClient.h>
|
#include <ESP8266HTTPClient.h>
|
||||||
#include <WiFiClient.h>
|
#include <WiFiClient.h>
|
||||||
|
|
||||||
#include "ClosedCube_SHT31D.h"
|
SoftwareSerial softSerial(D6, D5);
|
||||||
|
SoftwareSerial soft2(D3, D7);
|
||||||
|
|
||||||
SoftwareSerial softSerial(D6, D5); //(RX, TX)
|
|
||||||
SoftwareSerial soft2(D3, D7); //(RX, TX)
|
|
||||||
|
|
||||||
ClosedCube_SHT31D sht3xd;
|
|
||||||
|
|
||||||
PMS pms(softSerial);
|
PMS pms(softSerial);
|
||||||
PMS pms2(soft2);
|
PMS pms2(soft2);
|
||||||
PMS::DATA data;
|
PMS::DATA data;
|
||||||
|
PMS::DATA data2;
|
||||||
|
|
||||||
int pm1 = 0;
|
float pm1Value=0;
|
||||||
int pm2 = 0;
|
int pm1Position = 0;
|
||||||
float temp = 0;
|
|
||||||
int hum = 0;
|
float pm2Value=0;
|
||||||
|
int pm2Position = 0;
|
||||||
|
|
||||||
float temp_pm1 = 0;
|
float temp_pm1 = 0;
|
||||||
float hum_pm1 = 0;
|
float hum_pm1 = 0;
|
||||||
@ -29,33 +47,48 @@ float hum_pm1 = 0;
|
|||||||
float temp_pm2 = 0;
|
float temp_pm2 = 0;
|
||||||
float hum_pm2 = 0;
|
float hum_pm2 = 0;
|
||||||
|
|
||||||
|
unsigned long currentMillis = 0;
|
||||||
|
|
||||||
|
const int pm1Interval = 5000;
|
||||||
|
unsigned long previousPm1 = 0;
|
||||||
|
|
||||||
|
const int pm2Interval = 5000;
|
||||||
|
unsigned long previousPm2 = 0;
|
||||||
|
|
||||||
String APIROOT = "http://hw.airgradient.com/";
|
String APIROOT = "http://hw.airgradient.com/";
|
||||||
|
|
||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(9600);
|
Serial.begin(115200);
|
||||||
Serial.println("hhi");
|
Serial.println("Chip ID: "+String(ESP.getChipId()));
|
||||||
softSerial.begin(9600);
|
softSerial.begin(9600);
|
||||||
soft2.begin(9600);
|
soft2.begin(9600);
|
||||||
Wire.begin();
|
Wire.begin();
|
||||||
sht3xd.begin(0x44);
|
|
||||||
pinMode(D7, OUTPUT);
|
pinMode(D7, OUTPUT);
|
||||||
|
|
||||||
connectToWifi();
|
connectToWifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void loop()
|
void loop()
|
||||||
{
|
{
|
||||||
|
currentMillis = millis();
|
||||||
|
updatePm1();
|
||||||
|
updatePm2();
|
||||||
|
}
|
||||||
|
|
||||||
if (digitalRead(D8) == HIGH) {
|
|
||||||
|
void updatePm1()
|
||||||
|
{
|
||||||
|
if (currentMillis - previousPm1 >= pm1Interval) {
|
||||||
digitalWrite(D7, HIGH);
|
digitalWrite(D7, HIGH);
|
||||||
}
|
delay(400);
|
||||||
else {
|
|
||||||
digitalWrite(D7, LOW);
|
digitalWrite(D7, LOW);
|
||||||
}
|
Serial.println("updatePm1: "+String(pm1Position));
|
||||||
|
previousPm1 += pm1Interval;
|
||||||
if (pms.read(data)){
|
pms.requestRead();
|
||||||
pm1 = data.PM_AE_UG_2_5;
|
if (pms.readUntil(data)){
|
||||||
|
Serial.println("success read");
|
||||||
|
int pm1 = data.PM_AE_UG_2_5;
|
||||||
temp_pm1 = data.AMB_TMP;
|
temp_pm1 = data.AMB_TMP;
|
||||||
hum_pm1 = data.AMB_HUM;
|
hum_pm1 = data.AMB_HUM;
|
||||||
Serial.print("PMS 1: PM 2.5 (ug/m3): ");
|
Serial.print("PMS 1: PM 2.5 (ug/m3): ");
|
||||||
@ -66,11 +99,27 @@ void loop()
|
|||||||
Serial.println(hum_pm1);
|
Serial.println(hum_pm1);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
pm1Value=pm1Value+pm1;
|
||||||
|
pm1Position++;
|
||||||
|
if (pm1Position==20) {
|
||||||
|
sendToServerPM1(pm1Value);
|
||||||
|
pm1Position=0;
|
||||||
|
pm1Value=0;
|
||||||
}
|
}
|
||||||
if (pms2.read(data)){
|
}
|
||||||
pm2 = data.PM_AE_UG_2_5;
|
}
|
||||||
temp_pm2 = data.AMB_TMP ;
|
}
|
||||||
hum_pm2 = data.AMB_HUM;
|
|
||||||
|
void updatePm2()
|
||||||
|
{
|
||||||
|
if (currentMillis - previousPm2 >= pm2Interval) {
|
||||||
|
Serial.println("updatePm2: "+String(pm2Position));
|
||||||
|
previousPm2 += pm2Interval;
|
||||||
|
pms2.requestRead();
|
||||||
|
if (pms2.readUntil(data2)){
|
||||||
|
int pm2 = data2.PM_AE_UG_2_5;
|
||||||
|
temp_pm2 = data2.AMB_TMP ;
|
||||||
|
hum_pm2 = data2.AMB_HUM;
|
||||||
Serial.print("PMS 2: PM 2.5 (ug/m3): ");
|
Serial.print("PMS 2: PM 2.5 (ug/m3): ");
|
||||||
Serial.println(pm2);
|
Serial.println(pm2);
|
||||||
Serial.print("PMS 2: Temp: ");
|
Serial.print("PMS 2: Temp: ");
|
||||||
@ -79,57 +128,20 @@ void loop()
|
|||||||
Serial.println(hum_pm2);
|
Serial.println(hum_pm2);
|
||||||
Serial.println();
|
Serial.println();
|
||||||
delay(1000);
|
delay(1000);
|
||||||
|
pm2Value=pm2Value+pm2;
|
||||||
temp = sht3xd.readTempAndHumidity(SHT3XD_REPEATABILITY_LOW, SHT3XD_MODE_CLOCK_STRETCH, 50).t;
|
pm2Position++;
|
||||||
hum = sht3xd.readTempAndHumidity(SHT3XD_REPEATABILITY_LOW, SHT3XD_MODE_CLOCK_STRETCH, 50).rh;
|
if (pm2Position==20) {
|
||||||
|
sendToServerPM2(pm2Value);
|
||||||
Serial.println(temp);
|
pm2Position=0;
|
||||||
Serial.println(hum);
|
pm2Value=0;
|
||||||
|
|
||||||
sendToServer();
|
|
||||||
delay(1000);
|
|
||||||
sendToServerPM1();
|
|
||||||
delay(1000);
|
|
||||||
sendToServerPM2();
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void sendToServer() {
|
|
||||||
String payload = "{\"wifi\":" + String(WiFi.RSSI())
|
|
||||||
+ ", \"pm02\":" + String((pm1+pm2)/2)
|
|
||||||
+ ", \"atmp\":" + String(temp)
|
|
||||||
+ ", \"rhum\":" + String(hum)
|
|
||||||
+ "}";
|
|
||||||
|
|
||||||
if(WiFi.status()== WL_CONNECTED){
|
|
||||||
digitalWrite(D7, HIGH);
|
|
||||||
delay(300);
|
|
||||||
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();
|
|
||||||
digitalWrite(D7, LOW);
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
Serial.println("WiFi Disconnected");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void sendToServerPM1() {
|
void sendToServerPM1(float pm1Value) {
|
||||||
String payload = "{\"wifi\":" + String(WiFi.RSSI())
|
String payload = "{\"wifi\":" + String(WiFi.RSSI())
|
||||||
+ ", \"pm02\":" + String(pm1)
|
+ ", \"pm02\":" + String(pm1Value/20)
|
||||||
+ ", \"atmp\":" + String(temp_pm1/10)
|
+ ", \"atmp\":" + String(temp_pm1/10)
|
||||||
+ ", \"rhum\":" + String(hum_pm1/10)
|
+ ", \"rhum\":" + String(hum_pm1/10)
|
||||||
+ "}";
|
+ "}";
|
||||||
@ -138,7 +150,7 @@ void sendToServerPM1() {
|
|||||||
digitalWrite(D7, HIGH);
|
digitalWrite(D7, HIGH);
|
||||||
delay(300);
|
delay(300);
|
||||||
Serial.println(payload);
|
Serial.println(payload);
|
||||||
String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(), HEX) + "pm1/measures";
|
String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId()) + "-1/measures";
|
||||||
Serial.println(POSTURL);
|
Serial.println(POSTURL);
|
||||||
WiFiClient client;
|
WiFiClient client;
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
@ -157,9 +169,9 @@ void sendToServerPM1() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void sendToServerPM2() {
|
void sendToServerPM2(float pm2Value) {
|
||||||
String payload = "{\"wifi\":" + String(WiFi.RSSI())
|
String payload = "{\"wifi\":" + String(WiFi.RSSI())
|
||||||
+ ", \"pm02\":" + String(pm2)
|
+ ", \"pm02\":" + String(pm2Value/20)
|
||||||
+ ", \"atmp\":" + String(temp_pm2/10)
|
+ ", \"atmp\":" + String(temp_pm2/10)
|
||||||
+ ", \"rhum\":" + String(hum_pm2/10)
|
+ ", \"rhum\":" + String(hum_pm2/10)
|
||||||
+ "}";
|
+ "}";
|
||||||
@ -168,7 +180,7 @@ void sendToServerPM2() {
|
|||||||
digitalWrite(D7, HIGH);
|
digitalWrite(D7, HIGH);
|
||||||
delay(300);
|
delay(300);
|
||||||
Serial.println(payload);
|
Serial.println(payload);
|
||||||
String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId(), HEX) + "pm2/measures";
|
String POSTURL = APIROOT + "sensors/airgradient:" + String(ESP.getChipId()) + "-2/measures";
|
||||||
Serial.println(POSTURL);
|
Serial.println(POSTURL);
|
||||||
WiFiClient client;
|
WiFiClient client;
|
||||||
HTTPClient http;
|
HTTPClient http;
|
||||||
@ -191,11 +203,10 @@ void sendToServerPM2() {
|
|||||||
void connectToWifi() {
|
void connectToWifi() {
|
||||||
WiFiManager wifiManager;
|
WiFiManager wifiManager;
|
||||||
//WiFi.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());
|
||||||
wifiManager.setTimeout(60);
|
wifiManager.setTimeout(60);
|
||||||
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(6000);
|
delay(6000);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
242
examples/DIY_OUTDOOR_C3/DIY_OUTDOOR_C3.ino
Normal file
242
examples/DIY_OUTDOOR_C3/DIY_OUTDOOR_C3.ino
Normal file
@ -0,0 +1,242 @@
|
|||||||
|
/*
|
||||||
|
Important: This code is only for the DIY OUTDOOR OPEN AIR Presoldered Kit with the ESP-C3.
|
||||||
|
|
||||||
|
It is a high quality outdoor air quality sensor with dual PM2.5 modules and can send data over Wifi.
|
||||||
|
|
||||||
|
Kits are available: https://www.airgradient.com/open-airgradient/kits/
|
||||||
|
|
||||||
|
The codes needs the following libraries installed:
|
||||||
|
“WifiManager by tzapu, tablatronix” tested with version 2.0.11-beta
|
||||||
|
“pms” by Markusz Kakl version 1.1.0 (needs to be patched for 5003T model)
|
||||||
|
|
||||||
|
For built instructions and how to patch the PMS library: https://www.airgradient.com/open-airgradient/instructions/diy-open-air-presoldered-v11/
|
||||||
|
|
||||||
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "PMS.h"
|
||||||
|
#include <HardwareSerial.h>
|
||||||
|
#include <Wire.h>
|
||||||
|
#include <HTTPClient.h>
|
||||||
|
#include <WiFiManager.h>
|
||||||
|
|
||||||
|
#define DEBUG true
|
||||||
|
|
||||||
|
HTTPClient client;
|
||||||
|
|
||||||
|
PMS pms1(Serial0);
|
||||||
|
PMS::DATA data1;
|
||||||
|
|
||||||
|
PMS pms2(Serial1);
|
||||||
|
PMS::DATA data2;
|
||||||
|
|
||||||
|
float pm1Value=0;
|
||||||
|
int pm1Position = 0;
|
||||||
|
|
||||||
|
float pm2Value=0;
|
||||||
|
int pm2Position = 0;
|
||||||
|
|
||||||
|
float temp_pm1 = 0;
|
||||||
|
float hum_pm1 = 0;
|
||||||
|
|
||||||
|
float temp_pm2 = 0;
|
||||||
|
float hum_pm2 = 0;
|
||||||
|
|
||||||
|
unsigned long currentMillis = 0;
|
||||||
|
|
||||||
|
const int pm1Interval = 5000;
|
||||||
|
unsigned long previousPm1 = 0;
|
||||||
|
|
||||||
|
const int pm2Interval = 5000;
|
||||||
|
unsigned long previousPm2 = 0;
|
||||||
|
|
||||||
|
String APIROOT = "http://hw.airgradient.com/";
|
||||||
|
|
||||||
|
bool ledOn = false;
|
||||||
|
|
||||||
|
int loopCount = 0;
|
||||||
|
|
||||||
|
int averageCount = 10;
|
||||||
|
|
||||||
|
void debug(String msg) {
|
||||||
|
if (DEBUG)
|
||||||
|
Serial.print(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug(int msg) {
|
||||||
|
if (DEBUG)
|
||||||
|
Serial.print(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugln(String msg) {
|
||||||
|
if (DEBUG)
|
||||||
|
Serial.println(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void debugln(int msg) {
|
||||||
|
if (DEBUG)
|
||||||
|
Serial.println(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void switchLED(boolean ledON) {
|
||||||
|
if (ledON) {
|
||||||
|
digitalWrite(10, HIGH);
|
||||||
|
} else {
|
||||||
|
digitalWrite(10, LOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void IRAM_ATTR isr() {
|
||||||
|
debugln("pushed");
|
||||||
|
}
|
||||||
|
|
||||||
|
void postToServer(String postfix, int pm25,float tem, float hum) {
|
||||||
|
String payload = "{\"wifi\":" + String(WiFi.RSSI())
|
||||||
|
+ ", \"pm02\":" + String(pm25)
|
||||||
|
+ ", \"atmp\":" + String(tem/10)
|
||||||
|
+ ", \"rhum\":" + String(hum/10)
|
||||||
|
+ ", \"boot\":" + loopCount
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
if(WiFi.status()== WL_CONNECTED){
|
||||||
|
switchLED(true);
|
||||||
|
String url = APIROOT + "sensors/airgradient:" + getNormalizedMac() + postfix + "/measures";
|
||||||
|
debugln(url);
|
||||||
|
debugln(payload);
|
||||||
|
client.setConnectTimeout(5 * 1000);
|
||||||
|
client.begin(url);
|
||||||
|
client.addHeader("content-type", "application/json");
|
||||||
|
int httpCode = client.POST(payload);
|
||||||
|
debugln(httpCode);
|
||||||
|
client.end();
|
||||||
|
resetWatchdog();
|
||||||
|
switchLED(false);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
debug("post skipped, not network connection");
|
||||||
|
}
|
||||||
|
loopCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void countdown(int from) {
|
||||||
|
debug("\n");
|
||||||
|
while (from > 0) {
|
||||||
|
debug(String(from--));
|
||||||
|
debug(" ");
|
||||||
|
delay(1000);
|
||||||
|
}
|
||||||
|
debug("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// select board LOLIN C3 mini to flash
|
||||||
|
void setup() {
|
||||||
|
if (DEBUG) {
|
||||||
|
Serial.begin(115200);
|
||||||
|
// see https://github.com/espressif/arduino-esp32/issues/6983
|
||||||
|
Serial.setTxTimeoutMs(0); // <<<====== solves the delay issue
|
||||||
|
}
|
||||||
|
|
||||||
|
debug("starting ...");
|
||||||
|
|
||||||
|
// default hardware serial, PMS connector on the right side of the C3 mini on the Open Air
|
||||||
|
Serial0.begin(9600);
|
||||||
|
|
||||||
|
// second hardware serial, PMS connector on the left side of the C3 mini on the Open Air
|
||||||
|
Serial1.begin(9600, SERIAL_8N1, 0, 1);
|
||||||
|
|
||||||
|
// led
|
||||||
|
pinMode(10, OUTPUT);
|
||||||
|
|
||||||
|
// push button
|
||||||
|
pinMode(9, INPUT_PULLUP);
|
||||||
|
attachInterrupt(9, isr, FALLING);
|
||||||
|
|
||||||
|
pinMode(2, OUTPUT);
|
||||||
|
digitalWrite(2, LOW);
|
||||||
|
|
||||||
|
// give the PMSs some time to start
|
||||||
|
countdown(3);
|
||||||
|
|
||||||
|
connectToWifi();
|
||||||
|
switchLED(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void resetWatchdog() {
|
||||||
|
digitalWrite(2, HIGH);
|
||||||
|
delay(20);
|
||||||
|
digitalWrite(2, LOW);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
|
||||||
|
if(WiFi.status()== WL_CONNECTED) {
|
||||||
|
|
||||||
|
if (pms1.readUntil(data1, 2000)) {
|
||||||
|
pm1Value=pm1Value+data1.PM_AE_UG_2_5;
|
||||||
|
temp_pm1=temp_pm1+data1.AMB_TMP;
|
||||||
|
hum_pm1=hum_pm1+data1.AMB_HUM;
|
||||||
|
debugln("PMS 1 measurement "+String(pm1Position)+": "+String(data1.PM_AE_UG_2_5)+"ug/m3");
|
||||||
|
pm1Position++;
|
||||||
|
if (pm1Position==averageCount) {
|
||||||
|
pm1Value = pm1Value / averageCount;
|
||||||
|
temp_pm1 = temp_pm1 / averageCount;
|
||||||
|
hum_pm1 = hum_pm1 / averageCount;
|
||||||
|
postToServer("-1", pm1Value, temp_pm1,hum_pm1);
|
||||||
|
pm1Position=0;
|
||||||
|
pm1Value=0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugln("PMS 1 does't respond");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pms2.readUntil(data2, 2000)) {
|
||||||
|
pm2Value=pm2Value+data2.PM_AE_UG_2_5;
|
||||||
|
temp_pm2=temp_pm2+data2.AMB_TMP;
|
||||||
|
hum_pm2=hum_pm2+data2.AMB_HUM;
|
||||||
|
debugln("PMS 2 measurement "+String(pm2Position)+": "+String(data2.PM_AE_UG_2_5)+"ug/m3");
|
||||||
|
pm2Position++;
|
||||||
|
if (pm2Position==averageCount) {
|
||||||
|
pm2Value = pm2Value / averageCount;
|
||||||
|
temp_pm2 = temp_pm2 / averageCount;
|
||||||
|
hum_pm2 = hum_pm2 / averageCount;
|
||||||
|
postToServer("-2", pm2Value, temp_pm2, hum_pm2);
|
||||||
|
pm2Position=0;
|
||||||
|
pm2Value=0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debugln("PMS 2 does't respond");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
countdown(2);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Wifi Manager
|
||||||
|
void connectToWifi() {
|
||||||
|
WiFiManager wifiManager;
|
||||||
|
switchLED(true);
|
||||||
|
//WiFi.disconnect(); //to delete previous saved hotspot
|
||||||
|
String HOTSPOT = "AG-" + String(getNormalizedMac());
|
||||||
|
wifiManager.setTimeout(180);
|
||||||
|
|
||||||
|
|
||||||
|
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
|
||||||
|
switchLED(false);
|
||||||
|
Serial.println("failed to connect and hit timeout");
|
||||||
|
delay(6000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
String getNormalizedMac() {
|
||||||
|
String mac = WiFi.macAddress();
|
||||||
|
mac.replace(":", "");
|
||||||
|
mac.toLowerCase();
|
||||||
|
return mac;
|
||||||
|
}
|
@ -19,7 +19,7 @@ If you have any questions please visit our forum at https://forum.airgradient.co
|
|||||||
If you are a school or university contact us for a free trial on the AirGradient platform.
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
https://www.airgradient.com/
|
https://www.airgradient.com/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -78,7 +78,7 @@ int hum = 0;
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
u8g2.setBusClock(100000);
|
||||||
u8g2.begin();
|
u8g2.begin();
|
||||||
updateOLED();
|
updateOLED();
|
||||||
|
|
||||||
|
@ -5,7 +5,7 @@ This is the code for the AirGradient DIY PRO Air Quality Sensor with an ESP8266
|
|||||||
|
|
||||||
It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.
|
It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.
|
||||||
|
|
||||||
Build Instructions: https://www.airgradient.com/open-airgradient/instructions/diy-pro/
|
Build Instructions: https://www.airgradient.com/open-airgradient/instructions/diy-pro-v37/
|
||||||
|
|
||||||
Kits (including a pre-soldered version) are available: https://www.airgradient.com/open-airgradient/kits/
|
Kits (including a pre-soldered version) are available: https://www.airgradient.com/open-airgradient/kits/
|
||||||
|
|
||||||
@ -23,7 +23,7 @@ If you have any questions please visit our forum at https://forum.airgradient.co
|
|||||||
If you are a school or university contact us for a free trial on the AirGradient platform.
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
https://www.airgradient.com/
|
https://www.airgradient.com/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -52,14 +52,14 @@ NOxGasIndexAlgorithm nox_algorithm;
|
|||||||
uint16_t conditioning_s = 10;
|
uint16_t conditioning_s = 10;
|
||||||
|
|
||||||
// for peristent saving and loading
|
// for peristent saving and loading
|
||||||
int addr = 0;
|
int addr = 4;
|
||||||
byte value;
|
byte value;
|
||||||
|
|
||||||
// Display bottom right
|
// Display bottom right
|
||||||
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
|
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
|
||||||
|
|
||||||
// Replace above if you have display on top left
|
// Replace above if you have display on top left
|
||||||
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE);
|
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE);
|
||||||
|
|
||||||
|
|
||||||
// CONFIGURATION START
|
// CONFIGURATION START
|
||||||
@ -108,7 +108,7 @@ unsigned long previousTempHum = 0;
|
|||||||
float temp = 0;
|
float temp = 0;
|
||||||
int hum = 0;
|
int hum = 0;
|
||||||
|
|
||||||
int buttonConfig=0;
|
int buttonConfig=4;
|
||||||
int lastState = LOW;
|
int lastState = LOW;
|
||||||
int currentState;
|
int currentState;
|
||||||
unsigned long pressedTime = 0;
|
unsigned long pressedTime = 0;
|
||||||
@ -143,7 +143,7 @@ void setup() {
|
|||||||
connectToWifi();
|
connectToWifi();
|
||||||
}
|
}
|
||||||
|
|
||||||
updateOLED2("Warming up the", "sensors.", "");
|
updateOLED2("Warming Up", "Serial Number:", String(ESP.getChipId(), HEX));
|
||||||
sgp41.begin(Wire);
|
sgp41.begin(Wire);
|
||||||
ag.CO2_Init();
|
ag.CO2_Init();
|
||||||
ag.PMS_Init();
|
ag.PMS_Init();
|
||||||
@ -232,25 +232,25 @@ void setConfig() {
|
|||||||
inUSAQI = true;
|
inUSAQI = true;
|
||||||
}
|
}
|
||||||
if (buttonConfig == 4) {
|
if (buttonConfig == 4) {
|
||||||
updateOLED2("Temp. in C", "PM in ug/m3", "Display Top");
|
updateOLED2("Temp. in C", "PM in ug/m3", "Display Bottom");
|
||||||
u8g2.setDisplayRotation(U8G2_R0);
|
u8g2.setDisplayRotation(U8G2_R0);
|
||||||
inF = false;
|
inF = false;
|
||||||
inUSAQI = false;
|
inUSAQI = false;
|
||||||
}
|
}
|
||||||
if (buttonConfig == 5) {
|
if (buttonConfig == 5) {
|
||||||
updateOLED2("Temp. in C", "PM in US AQI", "Display Top");
|
updateOLED2("Temp. in C", "PM in US AQI", "Display Bottom");
|
||||||
u8g2.setDisplayRotation(U8G2_R0);
|
u8g2.setDisplayRotation(U8G2_R0);
|
||||||
inF = false;
|
inF = false;
|
||||||
inUSAQI = true;
|
inUSAQI = true;
|
||||||
}
|
}
|
||||||
if (buttonConfig == 6) {
|
if (buttonConfig == 6) {
|
||||||
updateOLED2("Temp. in F", "PM in ug/m3", "Display Top");
|
updateOLED2("Temp. in F", "PM in ug/m3", "Display Bottom");
|
||||||
u8g2.setDisplayRotation(U8G2_R0);
|
u8g2.setDisplayRotation(U8G2_R0);
|
||||||
inF = true;
|
inF = true;
|
||||||
inUSAQI = false;
|
inUSAQI = false;
|
||||||
}
|
}
|
||||||
if (buttonConfig == 7) {
|
if (buttonConfig == 7) {
|
||||||
updateOLED2("Temp. in F", "PM in US AQI", "Display Top");
|
updateOLED2("Temp. in F", "PM in US AQI", "Display Bottom");
|
||||||
u8g2.setDisplayRotation(U8G2_R0);
|
u8g2.setDisplayRotation(U8G2_R0);
|
||||||
inF = true;
|
inF = true;
|
||||||
inUSAQI = true;
|
inUSAQI = true;
|
||||||
@ -400,19 +400,8 @@ void sendToServer() {
|
|||||||
WiFiManager wifiManager;
|
WiFiManager wifiManager;
|
||||||
//WiFi.disconnect(); //to delete previous saved hotspot
|
//WiFi.disconnect(); //to delete previous saved hotspot
|
||||||
String HOTSPOT = "AG-" + String(ESP.getChipId(), HEX);
|
String HOTSPOT = "AG-" + String(ESP.getChipId(), HEX);
|
||||||
updateOLED2("60s to connect", "to Wifi Hotspot", HOTSPOT);
|
updateOLED2("90s to connect", "to Wifi Hotspot", HOTSPOT);
|
||||||
wifiManager.setTimeout(60);
|
wifiManager.setTimeout(90);
|
||||||
|
|
||||||
|
|
||||||
WiFiManagerParameter custom_text("<p>This is just a text paragraph</p>");
|
|
||||||
wifiManager.addParameter(&custom_text);
|
|
||||||
|
|
||||||
WiFiManagerParameter parameter("parameterId", "Parameter Label", "default value", 40);
|
|
||||||
wifiManager.addParameter(¶meter);
|
|
||||||
|
|
||||||
|
|
||||||
Serial.println("Parameter 1:");
|
|
||||||
Serial.println(parameter.getValue());
|
|
||||||
|
|
||||||
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
|
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
|
||||||
updateOLED2("booting into", "offline mode", "");
|
updateOLED2("booting into", "offline mode", "");
|
||||||
@ -420,9 +409,6 @@ void sendToServer() {
|
|||||||
delay(6000);
|
delay(6000);
|
||||||
}
|
}
|
||||||
|
|
||||||
Serial.println("Parameter 2:");
|
|
||||||
Serial.println(parameter.getValue());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate PM2.5 US AQI
|
// Calculate PM2.5 US AQI
|
||||||
|
418
examples/DIY_PRO_V4_2/DIY_PRO_V4_2.ino
Normal file
418
examples/DIY_PRO_V4_2/DIY_PRO_V4_2.ino
Normal file
@ -0,0 +1,418 @@
|
|||||||
|
/*
|
||||||
|
Important: This code is only for the DIY PRO PCB Version 3.7 that has a push button mounted.
|
||||||
|
|
||||||
|
This is the code for the AirGradient DIY PRO Air Quality Sensor with an ESP8266 Microcontroller with the SGP40 TVOC module from AirGradient.
|
||||||
|
|
||||||
|
It is a high quality sensor showing PM2.5, CO2, Temperature and Humidity on a small display and can send data over Wifi.
|
||||||
|
|
||||||
|
Build Instructions: https://www.airgradient.com/open-airgradient/instructions/diy-pro-v37/
|
||||||
|
|
||||||
|
Kits (including a pre-soldered version) are available: https://www.airgradient.com/open-airgradient/kits/
|
||||||
|
|
||||||
|
The codes needs the following libraries installed:
|
||||||
|
“WifiManager by tzapu, tablatronix” tested with version 2.0.11-beta
|
||||||
|
“U8g2” by oliver tested with version 2.32.15
|
||||||
|
"Sensirion I2C SGP41" by Sensation Version 0.1.0
|
||||||
|
"Sensirion Gas Index Algorithm" by Sensation Version 3.2.1
|
||||||
|
|
||||||
|
Configuration:
|
||||||
|
Please set in the code below the configuration parameters.
|
||||||
|
|
||||||
|
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/
|
||||||
|
|
||||||
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include <AirGradient.h>
|
||||||
|
#include <WiFiManager.h>
|
||||||
|
#include <ESP8266WiFi.h>
|
||||||
|
#include <ESP8266HTTPClient.h>
|
||||||
|
#include <WiFiClient.h>
|
||||||
|
|
||||||
|
#include <EEPROM.h>
|
||||||
|
|
||||||
|
//#include "SGP30.h"
|
||||||
|
#include <SensirionI2CSgp41.h>
|
||||||
|
#include <NOxGasIndexAlgorithm.h>
|
||||||
|
#include <VOCGasIndexAlgorithm.h>
|
||||||
|
|
||||||
|
|
||||||
|
#include <U8g2lib.h>
|
||||||
|
|
||||||
|
AirGradient ag = AirGradient();
|
||||||
|
SensirionI2CSgp41 sgp41;
|
||||||
|
VOCGasIndexAlgorithm voc_algorithm;
|
||||||
|
NOxGasIndexAlgorithm nox_algorithm;
|
||||||
|
// time in seconds needed for NOx conditioning
|
||||||
|
uint16_t conditioning_s = 10;
|
||||||
|
|
||||||
|
// for peristent saving and loading
|
||||||
|
int addr = 4;
|
||||||
|
byte value;
|
||||||
|
|
||||||
|
// Display bottom right
|
||||||
|
U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
|
||||||
|
|
||||||
|
// Replace above if you have display on top left
|
||||||
|
//U8G2_SH1106_128X64_NONAME_F_HW_I2C u8g2(U8G2_R2, /* reset=*/ U8X8_PIN_NONE);
|
||||||
|
|
||||||
|
|
||||||
|
// CONFIGURATION START
|
||||||
|
|
||||||
|
//set to the endpoint you would like to use
|
||||||
|
String APIROOT = "http://hw.airgradient.com/";
|
||||||
|
|
||||||
|
// set to true to switch from Celcius to Fahrenheit
|
||||||
|
boolean inF = false;
|
||||||
|
|
||||||
|
// PM2.5 in US AQI (default ug/m3)
|
||||||
|
boolean inUSAQI = false;
|
||||||
|
|
||||||
|
// Display Position
|
||||||
|
boolean displayTop = true;
|
||||||
|
|
||||||
|
// set to true if you want to connect to wifi. You have 60 seconds to connect. Then it will go into an offline mode.
|
||||||
|
boolean connectWIFI=true;
|
||||||
|
|
||||||
|
// CONFIGURATION END
|
||||||
|
|
||||||
|
|
||||||
|
unsigned long currentMillis = 0;
|
||||||
|
|
||||||
|
const int oledInterval = 5000;
|
||||||
|
unsigned long previousOled = 0;
|
||||||
|
|
||||||
|
const int sendToServerInterval = 10000;
|
||||||
|
unsigned long previoussendToServer = 0;
|
||||||
|
|
||||||
|
const int tvocInterval = 1000;
|
||||||
|
unsigned long previousTVOC = 0;
|
||||||
|
int TVOC = 0;
|
||||||
|
int NOX = 0;
|
||||||
|
|
||||||
|
const int co2Interval = 5000;
|
||||||
|
unsigned long previousCo2 = 0;
|
||||||
|
int Co2 = 0;
|
||||||
|
|
||||||
|
const int pm25Interval = 5000;
|
||||||
|
unsigned long previousPm25 = 0;
|
||||||
|
int pm25 = 0;
|
||||||
|
|
||||||
|
const int tempHumInterval = 2500;
|
||||||
|
unsigned long previousTempHum = 0;
|
||||||
|
float temp = 0;
|
||||||
|
int hum = 0;
|
||||||
|
|
||||||
|
int buttonConfig=4;
|
||||||
|
int lastState = LOW;
|
||||||
|
int currentState;
|
||||||
|
unsigned long pressedTime = 0;
|
||||||
|
unsigned long releasedTime = 0;
|
||||||
|
|
||||||
|
void setup() {
|
||||||
|
Serial.begin(115200);
|
||||||
|
Serial.println("Hello");
|
||||||
|
u8g2.begin();
|
||||||
|
//u8g2.setDisplayRotation(U8G2_R0);
|
||||||
|
|
||||||
|
EEPROM.begin(512);
|
||||||
|
delay(500);
|
||||||
|
|
||||||
|
buttonConfig = String(EEPROM.read(addr)).toInt();
|
||||||
|
setConfig();
|
||||||
|
|
||||||
|
updateOLED2("Press Button", "Now for", "Config Menu");
|
||||||
|
delay(2000);
|
||||||
|
|
||||||
|
currentState = digitalRead(D7);
|
||||||
|
if (currentState == HIGH)
|
||||||
|
{
|
||||||
|
updateOLED2("Entering", "Config Menu", "");
|
||||||
|
delay(3000);
|
||||||
|
lastState = LOW;
|
||||||
|
inConf();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (connectWIFI)
|
||||||
|
{
|
||||||
|
connectToWifi();
|
||||||
|
}
|
||||||
|
|
||||||
|
updateOLED2("Warming Up", "Serial Number:", String(ESP.getChipId(), HEX));
|
||||||
|
sgp41.begin(Wire);
|
||||||
|
ag.CO2_Init();
|
||||||
|
ag.PMS_Init();
|
||||||
|
ag.TMP_RH_Init(0x44);
|
||||||
|
}
|
||||||
|
|
||||||
|
void loop() {
|
||||||
|
currentMillis = millis();
|
||||||
|
updateTVOC();
|
||||||
|
updateOLED();
|
||||||
|
updateCo2();
|
||||||
|
updatePm25();
|
||||||
|
updateTempHum();
|
||||||
|
sendToServer();
|
||||||
|
}
|
||||||
|
|
||||||
|
void inConf(){
|
||||||
|
setConfig();
|
||||||
|
currentState = digitalRead(D7);
|
||||||
|
|
||||||
|
if(lastState == LOW && currentState == HIGH) {
|
||||||
|
pressedTime = millis();
|
||||||
|
}
|
||||||
|
|
||||||
|
else if(lastState == HIGH && currentState == LOW) {
|
||||||
|
releasedTime = millis();
|
||||||
|
long pressDuration = releasedTime - pressedTime;
|
||||||
|
if( pressDuration < 1000 ) {
|
||||||
|
buttonConfig=buttonConfig+1;
|
||||||
|
if (buttonConfig>7) buttonConfig=0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastState == HIGH && currentState == HIGH){
|
||||||
|
long passedDuration = millis() - pressedTime;
|
||||||
|
if( passedDuration > 4000 ) {
|
||||||
|
// to do
|
||||||
|
// if (buttonConfig==4) {
|
||||||
|
// updateOLED2("Saved", "Release", "Button Now");
|
||||||
|
// delay(1000);
|
||||||
|
// updateOLED2("Starting", "CO2", "Calibration");
|
||||||
|
// delay(1000);
|
||||||
|
// Co2Calibration();
|
||||||
|
// } else {
|
||||||
|
updateOLED2("Saved", "Release", "Button Now");
|
||||||
|
delay(1000);
|
||||||
|
updateOLED2("Rebooting", "in", "5 seconds");
|
||||||
|
delay(5000);
|
||||||
|
EEPROM.write(addr, char(buttonConfig));
|
||||||
|
EEPROM.commit();
|
||||||
|
delay(1000);
|
||||||
|
ESP.restart();
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
lastState = currentState;
|
||||||
|
delay(100);
|
||||||
|
inConf();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void setConfig() {
|
||||||
|
if (buttonConfig == 0) {
|
||||||
|
updateOLED2("Temp. in C", "PM in ug/m3", "Display Top");
|
||||||
|
u8g2.setDisplayRotation(U8G2_R2);
|
||||||
|
inF = false;
|
||||||
|
inUSAQI = false;
|
||||||
|
} else if (buttonConfig == 1) {
|
||||||
|
updateOLED2("Temp. in C", "PM in US AQI", "Display Top");
|
||||||
|
u8g2.setDisplayRotation(U8G2_R2);
|
||||||
|
inF = false;
|
||||||
|
inUSAQI = true;
|
||||||
|
} else if (buttonConfig == 2) {
|
||||||
|
updateOLED2("Temp. in F", "PM in ug/m3", "Display Top");
|
||||||
|
u8g2.setDisplayRotation(U8G2_R2);
|
||||||
|
inF = true;
|
||||||
|
inUSAQI = false;
|
||||||
|
} else if (buttonConfig == 3) {
|
||||||
|
updateOLED2("Temp. in F", "PM in US AQI", "Display Top");
|
||||||
|
u8g2.setDisplayRotation(U8G2_R2);
|
||||||
|
inF = true;
|
||||||
|
inUSAQI = true;
|
||||||
|
} else if (buttonConfig == 4) {
|
||||||
|
updateOLED2("Temp. in C", "PM in ug/m3", "Display Bottom");
|
||||||
|
u8g2.setDisplayRotation(U8G2_R0);
|
||||||
|
inF = false;
|
||||||
|
inUSAQI = false;
|
||||||
|
}
|
||||||
|
if (buttonConfig == 5) {
|
||||||
|
updateOLED2("Temp. in C", "PM in US AQI", "Display Bottom");
|
||||||
|
u8g2.setDisplayRotation(U8G2_R0);
|
||||||
|
inF = false;
|
||||||
|
inUSAQI = true;
|
||||||
|
} else if (buttonConfig == 6) {
|
||||||
|
updateOLED2("Temp. in F", "PM in ug/m3", "Display Bottom");
|
||||||
|
u8g2.setDisplayRotation(U8G2_R0);
|
||||||
|
inF = true;
|
||||||
|
inUSAQI = false;
|
||||||
|
} else if (buttonConfig == 7) {
|
||||||
|
updateOLED2("Temp. in F", "PM in US AQI", "Display Bottom");
|
||||||
|
u8g2.setDisplayRotation(U8G2_R0);
|
||||||
|
inF = true;
|
||||||
|
inUSAQI = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// to do
|
||||||
|
// if (buttonConfig == 8) {
|
||||||
|
// updateOLED2("CO2", "Manual", "Calibration");
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateTVOC()
|
||||||
|
{
|
||||||
|
uint16_t error;
|
||||||
|
char errorMessage[256];
|
||||||
|
uint16_t defaultRh = 0x8000;
|
||||||
|
uint16_t defaultT = 0x6666;
|
||||||
|
uint16_t srawVoc = 0;
|
||||||
|
uint16_t srawNox = 0;
|
||||||
|
uint16_t defaultCompenstaionRh = 0x8000; // in ticks as defined by SGP41
|
||||||
|
uint16_t defaultCompenstaionT = 0x6666; // in ticks as defined by SGP41
|
||||||
|
uint16_t compensationRh = 0; // in ticks as defined by SGP41
|
||||||
|
uint16_t compensationT = 0; // in ticks as defined by SGP41
|
||||||
|
|
||||||
|
delay(1000);
|
||||||
|
|
||||||
|
compensationT = static_cast<uint16_t>((temp + 45) * 65535 / 175);
|
||||||
|
compensationRh = static_cast<uint16_t>(hum * 65535 / 100);
|
||||||
|
|
||||||
|
if (conditioning_s > 0) {
|
||||||
|
error = sgp41.executeConditioning(compensationRh, compensationT, srawVoc);
|
||||||
|
conditioning_s--;
|
||||||
|
} else {
|
||||||
|
error = sgp41.measureRawSignals(compensationRh, compensationT, srawVoc,
|
||||||
|
srawNox);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (currentMillis - previousTVOC >= tvocInterval) {
|
||||||
|
previousTVOC += tvocInterval;
|
||||||
|
TVOC = voc_algorithm.process(srawVoc);
|
||||||
|
NOX = nox_algorithm.process(srawNox);
|
||||||
|
Serial.println(String(TVOC));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateCo2()
|
||||||
|
{
|
||||||
|
if (currentMillis - previousCo2 >= co2Interval) {
|
||||||
|
previousCo2 += co2Interval;
|
||||||
|
Co2 = ag.getCO2_Raw();
|
||||||
|
Serial.println(String(Co2));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updatePm25()
|
||||||
|
{
|
||||||
|
if (currentMillis - previousPm25 >= pm25Interval) {
|
||||||
|
previousPm25 += pm25Interval;
|
||||||
|
pm25 = ag.getPM2_Raw();
|
||||||
|
Serial.println(String(pm25));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateTempHum()
|
||||||
|
{
|
||||||
|
if (currentMillis - previousTempHum >= tempHumInterval) {
|
||||||
|
previousTempHum += tempHumInterval;
|
||||||
|
TMP_RH result = ag.periodicFetchData();
|
||||||
|
temp = result.t;
|
||||||
|
hum = result.rh;
|
||||||
|
Serial.println(String(temp));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateOLED() {
|
||||||
|
if (currentMillis - previousOled >= oledInterval) {
|
||||||
|
previousOled += oledInterval;
|
||||||
|
|
||||||
|
String ln3;
|
||||||
|
String ln1;
|
||||||
|
|
||||||
|
if (inUSAQI) {
|
||||||
|
ln1 = "AQI:" + String(PM_TO_AQI_US(pm25)) + " CO2:" + String(Co2);
|
||||||
|
} else {
|
||||||
|
ln1 = "PM:" + String(pm25) + " CO2:" + String(Co2);
|
||||||
|
}
|
||||||
|
|
||||||
|
String ln2 = "TVOC:" + String(TVOC) + " NOX:" + String(NOX);
|
||||||
|
|
||||||
|
if (inF) {
|
||||||
|
ln3 = "F:" + String((temp* 9 / 5) + 32) + " H:" + String(hum)+"%";
|
||||||
|
} else {
|
||||||
|
ln3 = "C:" + String(temp) + " H:" + String(hum)+"%";
|
||||||
|
}
|
||||||
|
updateOLED2(ln1, ln2, ln3);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void updateOLED2(String ln1, String ln2, String ln3) {
|
||||||
|
char buf[9];
|
||||||
|
u8g2.firstPage();
|
||||||
|
u8g2.firstPage();
|
||||||
|
do {
|
||||||
|
u8g2.setFont(u8g2_font_t0_16_tf);
|
||||||
|
u8g2.drawStr(1, 10, String(ln1).c_str());
|
||||||
|
u8g2.drawStr(1, 30, String(ln2).c_str());
|
||||||
|
u8g2.drawStr(1, 50, String(ln3).c_str());
|
||||||
|
} while ( u8g2.nextPage() );
|
||||||
|
}
|
||||||
|
|
||||||
|
void sendToServer() {
|
||||||
|
if (currentMillis - previoussendToServer >= sendToServerInterval) {
|
||||||
|
previoussendToServer += sendToServerInterval;
|
||||||
|
String payload = "{\"wifi\":" + String(WiFi.RSSI())
|
||||||
|
+ (Co2 < 0 ? "" : ", \"rco2\":" + String(Co2))
|
||||||
|
+ (pm25 < 0 ? "" : ", \"pm02\":" + String(pm25))
|
||||||
|
+ (TVOC < 0 ? "" : ", \"tvoc_index\":" + String(TVOC))
|
||||||
|
+ (NOX < 0 ? "" : ", \"nox_index\":" + String(NOX))
|
||||||
|
+ ", \"atmp\":" + String(temp)
|
||||||
|
+ (hum < 0 ? "" : ", \"rhum\":" + String(hum))
|
||||||
|
+ "}";
|
||||||
|
|
||||||
|
if(WiFi.status()== WL_CONNECTED){
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Serial.println("WiFi Disconnected");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wifi Manager
|
||||||
|
void connectToWifi() {
|
||||||
|
WiFiManager wifiManager;
|
||||||
|
//WiFi.disconnect(); //to delete previous saved hotspot
|
||||||
|
String HOTSPOT = "AG-" + String(ESP.getChipId(), HEX);
|
||||||
|
updateOLED2("90s to connect", "to Wifi Hotspot", HOTSPOT);
|
||||||
|
wifiManager.setTimeout(90);
|
||||||
|
|
||||||
|
if (!wifiManager.autoConnect((const char * ) HOTSPOT.c_str())) {
|
||||||
|
updateOLED2("booting into", "offline mode", "");
|
||||||
|
Serial.println("failed to connect and hit timeout");
|
||||||
|
delay(6000);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
// 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;
|
||||||
|
};
|
@ -97,7 +97,7 @@ int hum = 0;
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
u8g2.setBusClock(100000);
|
||||||
u8g2.begin();
|
u8g2.begin();
|
||||||
updateOLED();
|
updateOLED();
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ If you have any questions please visit our forum at https://forum.airgradient.co
|
|||||||
If you are a school or university contact us for a free trial on the AirGradient platform.
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
https://www.airgradient.com/
|
https://www.airgradient.com/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -91,7 +91,7 @@ int hum = 0;
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
u8g2.setBusClock(100000);
|
||||||
u8g2.begin();
|
u8g2.begin();
|
||||||
updateOLED();
|
updateOLED();
|
||||||
|
|
||||||
|
@ -20,7 +20,7 @@ If you have any questions please visit our forum at https://forum.airgradient.co
|
|||||||
If you are a school or university contact us for a free trial on the AirGradient platform.
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
https://www.airgradient.com/
|
https://www.airgradient.com/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -87,7 +87,7 @@ int hum = 0;
|
|||||||
void setup()
|
void setup()
|
||||||
{
|
{
|
||||||
Serial.begin(115200);
|
Serial.begin(115200);
|
||||||
|
u8g2.setBusClock(100000);
|
||||||
u8g2.begin();
|
u8g2.begin();
|
||||||
updateOLED();
|
updateOLED();
|
||||||
|
|
||||||
|
@ -10,7 +10,7 @@ The codes needs the following libraries installed:
|
|||||||
"WifiManager by tzapu, tablatronix" tested with Version 2.0.5-alpha
|
"WifiManager by tzapu, tablatronix" tested with Version 2.0.5-alpha
|
||||||
"Adafruit_ILI9341" tested with Version 1.5.10
|
"Adafruit_ILI9341" tested with Version 1.5.10
|
||||||
"Adafruit GFX library" tested with Version 1.10.12 (often automatically installed with above ILI9341 library)
|
"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
|
"ArduinoJSON" by Benoit Blanchon tested with Version 5.13.5
|
||||||
|
|
||||||
Configuration:
|
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.
|
Please set in the code below (line 90-) if you want to display the PM2.5 values in US AQI and temperature in F.
|
||||||
@ -21,7 +21,7 @@ If you have any questions please visit our forum at https://forum.airgradient.co
|
|||||||
If you are a school or university contact us for a free trial on the AirGradient platform.
|
If you are a school or university contact us for a free trial on the AirGradient platform.
|
||||||
https://www.airgradient.com/
|
https://www.airgradient.com/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <WiFiManager.h>
|
#include <WiFiManager.h>
|
||||||
|
@ -17,7 +17,7 @@ https://www.airgradient.com/
|
|||||||
|
|
||||||
Kits with all required components are available at https://www.airgradient.com/open-airgradient/shop/
|
Kits with all required components are available at https://www.airgradient.com/open-airgradient/shop/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AirGradient.h>
|
#include <AirGradient.h>
|
||||||
|
@ -17,7 +17,7 @@ Kits with all required components are available at https://www.airgradient.com/o
|
|||||||
|
|
||||||
If you have any questions please visit our forum at https://forum.airgradient.com/
|
If you have any questions please visit our forum at https://forum.airgradient.com/
|
||||||
|
|
||||||
MIT License
|
CC BY-SA 4.0 Attribution-ShareAlike 4.0 International License
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <AirGradient.h>
|
#include <AirGradient.h>
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
name=AirGradient Air Quality Sensor
|
name=AirGradient Air Quality Sensor
|
||||||
version=2.2.0
|
version=2.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, TVOC and Humidity with OLED display.
|
sentence=ESP8266 library for an air quality sensor featuring PM2.5, CO2, Temperature, TVOC and Humidity with OLED display.
|
||||||
|
Reference in New Issue
Block a user