Instructions - happybono/FinedustMonitor GitHub Wiki
Step 1: Choosing and setting up the hardware for our IoT device
The physics process is called Mie scattering. It works on dust particulates that are bigger than 1/10 of the infrared light wavelength. So, the device can only measure particulates above a certain size. Most commercial sensors can measure particulates above 1um (1 micrometer) in size, which should provide readings for densities of PM2.5 (PM is Particulate Matter, which means particulates that are smaller than 2.5um in size). The accuracy of such inexpensive sensors is subject to a lot of debate. But, in general, they are considered fairly accurate, especially indoors.(There is even a PhD dissertation done on this topic!)
For air quality sensors, You may choose from a variety of sensors. The website AQICN has some good reviews for these sensors. The cheaper ones all work the same way: They have an infrared light source (LED or laser) and a light detector diametrically positioned across an air chamber. The detector measures light scattered by the fine dust or smog particulates in the air chamber, although, accuracy may varies, depends on the sensor models and price.
For this project, I chose to use the Nova PM Sensor SDS011 air quality sensor.
The sensor module requires 4 wires at least in order to operate properly : two for power supply and two for data. The power wires (GND and VCC) connect to the GND and Vin PINs on the NodeMCU board, as they draw 5V power from the NodeMCU. The data wire connects to two digital PINs on the NodeMCU. I choose to connect to [D0] and [D1]. The wiring is shown in The assembled prototype device with power source. above (the wire colors refer to the wires coming out of the air quality sensor the photo which located at the top). The NodeMCU board can be powered by using a regular Micro-USB connection. So, I attached a rechargeable USB portable battery to the prototype as power source.
Step 2: Reading sensor data
The data output from the sensor is a waveform with random peaks and troughs. Every peak indicates that the sensor has detected Particulate Matter (PM) greater than 1um in size. To read PM level from the sensor, the NodeMCU application needs to compute Lo Pulse Occupancy time (LPO time) in a given time unit. It needs to determine how much time (percentage) the data wire is in the low voltage state. The LPO value can then be converted to particulates per liter of air (or particulate mass per mΒ³) using a response curve given in the product specification.
dust.ino
int stat = 1;
int cnt = 0;
char buf[10];
void do_dust(char c, void (*function)(int, int)) {
//Serial.print("stat="+ String(stat) +", "+ "cnt="+ String(cnt) +" ");
//Serial.print(c, HEX);
//Serial.println(" ");
if (stat == 1) {
if (c == 0xAA) stat = 2;
} else
if (stat == 2) {
if (c == 0xC0) stat =3;
else stat = 1;
} else
if (stat == 3) {
buf[cnt++] = c;
if (cnt == 7) stat = 4;
} else
if (stat == 4) {
if (c == 0xAB) {
//check checusum
stat = 1;
}
else {
//Serial.println("Eh? wrong tailer");
}
cnt = 0;
int pm25 = buf[0] + 256*buf[1];
int pm10 = buf[2] + 256*buf[3];
function(pm25, pm10);
}
}
FineDustMonitorWithGPS.ino
#include <SoftwareSerial.h>
#include "RunningMedian.h"
RunningMedian pm25s = RunningMedian(19);
RunningMedian pm10s = RunningMedian(19);
SoftwareSerial ss(12, 13);
SoftwareSerial dust(D1, D0, false, 256);
void loop() {
while (dust.available() > 0) {
do_dust(dust.read(), got_dust);
yield(); //loop μμ while λ¬Έμ μ¬μ©νλ κ²½μ° yield λ₯Ό ν¬ν¨ν΄μ£Όμ΄μΌ ν©λλ€.
//Serial.println(map_x);
//Serial.print("pm 25 : ");
//Serial.println(int(pm25s.getMedian()));
if (millis() > mark) {//one minute(60000) interval
mark = millis() + 60000;
got_interval = true;
}
if (got_interval) {
got_interval = false;
do_interval();
}
yield();
}
Step 3: Connecting our IoT device to ThingSpeak or Plaive
In my previous Wiki article, I described how to set up IoT projects on ThingSpeak Data-analysis Platform. Please follow the instructions in that article to setup an IoT project in your ThingSpeak account and create API key for your device.
In the FinedustMonitor.ino, we will first assign the device ID and access token that was created from ThingSpeak Data-analysis Platform to this device. This code segment must be customized for each device.
FineDustMonitorWithGPS.ino
char* ssid = "";
char* password = "";
String api_key = "";
//#define PLAIVE_SERVER_ENABLE
#define THINGSPEAK_SERVER_ENABLE
Step 4: Sending the data to ThingSpeak IoT Platform and analyzing the data
After the device is connected, it can send messages to the ThingSpeak IoT service.
FineDustMonitorWithGPS.ino
//μλ²μ λ°μ΄ν° 보λ΄κΈ° (Sending collected data to server.)
void do_interval() {
if (wifi_ready) {
#ifdef PLAIVE_SERVER_ENABLE
do_server_plaive(api_key, int(pm25s.getMedian()), int(pm10s.getMedian()), get_temperature(), s_map_x, s_map_y);
#else
#ifdef THINGSPEAK_SERVER_ENABLE
do_server_thingspeak(api_key, int(pm25s.getMedian()), int(pm10s.getMedian()), get_temperature(), s_map_x, s_map_y, status);
#else
do_server_default(api_key, int(pm25s.getMedian()), int(pm10s.getMedian()), get_temperature(), s_map_x, s_map_y);
#endif
#endif
} //wifi is ok
}
wifi.ino
#include <ESP8266WiFi.h>
boolean connect_ap(char* ssid, char* password) {
int count = 60; // μ΅λ 60 ν μ°κ²° μλ μ€ wifi μ°κ²°νλ©΄ μ±κ³΅, μλλ©΄ μ€ν¨
Serial.println();
Serial.print("connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
//wifi_oled(count);
if (!count--) {
Serial.print("\nNO WIFI");
return(false);
}
}
Serial.print("\n Got WiFi, IP address: ");
Serial.println(WiFi.localIP());
return(true);
}
server.ino
const char* host_plaive = "data.plaive.10make.com";
const char* host_thingspeak = "api.thingspeak.com";
const char* host_default = "finedustapi.10make.com";
const int httpPort = 80;
#include <ESP8266WiFi.h>
#include <WiFiClient.h>
WiFiClient client;
String data;
String contentType;
void do_server_plaive(String api_key,int pm25, int pm10, float temperature, String map_x, String map_y) {
data = "api_key="+ String(api_key) + "&field1=" + String(pm25) + "&field2=" + String(pm10) + "&field3=" + String(temperature) + "&field4=" + String(map_x) + "&field5=" + String(map_y);
//contentType= "application/x-www-form-urlencoded";
//μλ² ν΅μ 곡μ client.println μ μ¬μ©νμ¬μΌ ν©λλ€.
if(client.connect(host_plaive,httpPort)){
Serial.println("connected");
client.print("GET /insert.php?");
client.print(data);
client.println(" HTTP/1.1");
client.println("Host: " + String(host_plaive)); // SERVER ADDRESS HERE AS WELL
client.println("Cache-Control: no-cache");
//client.println("Content-Type: application/xE-www-form-urlencoded");
//client.print("Content-Length: ");
//client.println(data.length());
client.println("Connection: close");
client.println();
//client.print(data);
}
//μλ² ν΅μ μ΄ λμ§ μμΌλ©΄
else{
Serial.println("connection failed: ");
return;
}
}
void do_server_thingspeak(String api_key,int pm25, int pm10, float temperature, String map_x, String map_y, String status) {
data = "api_key=" + String(api_key) + "&field1=" + String(pm25) + "&field2=" + String(pm10) + "&field3=" + String(temperature) + "&field4=" + String(map_x) + "&field5=" + String(map_y) + "&status=" + String(status);
//contentType= "application/x-www-form-urlencoded";
//μλ² ν΅μ 곡μ client.println μ μ¬μ©νμ¬μΌ ν©λλ€.
if(client.connect(host_thingspeak,httpPort)){
Serial.println("connected");
client.print("GET /update?");
client.print(data);
client.println(" HTTP/1.1");
client.println("Host: " + String(host_thingspeak)); // SERVER ADDRESS HERE AS WELL
client.println("Cache-Control: no-cache");
//client.println("Content-Type: application/xE-www-form-urlencoded");
//client.print("Content-Length: ");
//client.println(data.length());
client.println("Connection: close");
client.println();
//client.print(data);
}
//μλ² ν΅μ μ΄ λμ§ μμΌλ©΄
else{
Serial.println("connection failed: ");
return;
}
}
Conclusion
In this article, I discussed how to build an IoT air quality sensor using the NodeMCU hardware board and development kit, and then connect the device to ThingSpeak or Plaive Service. The ThingSpeak IoT Platform provides an easy-to-use hosted service to aggregate and manage data from IoT devices.