Stazione comunitaria statica per polveri sottili PM10 + WiFi da 30 euro

Seguite il tutorial : questo post

1) togliete il sensore di temperatura e inserite il Dust Sensor PM10 da 18 euro..

2) Rispetto al post “Rilevazione PM10 con #arduino e stazione wifi mobile da 50euro” non ho necessità del GPS e quindi risparmio anche sull’Arduino UNo

Praticamente tutta la stazione si basa su alimentazione, scheda ESP8266, un led e il sensore Dust Grove

espwifi_pm10_bbrev1

Il sensore deve essere rivolto verso l’alto “in piedi” quindi e non vanno coperte le due finestrelle come da figura mentre il fori centrale va chiuso con nastro:

  

Al solito vi fate un account su data.sparkfun.com e la scheda WiFi si collega in hotspot tramite il vostro cellurare oppure se presente, con un Wifi permanente.

Schermata 2015-09-06 alle 09.30.58

Eccovi il codice. Attenzione usate Arduino IDE ma dovete mettere ESP8266 come scheda!! (leggete il post che vi ho indicato all’inizio):

/*
* This sketch sends data via HTTP GET requests to data.sparkfun.com service.
*
* You need to get streamId and privateKey at data.sparkfun.com and paste them
* below. Or just customize this script to talk to other HTTP servers.
*
*/

#define LOCATIONID "6542124" // 6542124 location id for Lecce, 3165185 Trieste on openweathermap.org
#define APIID "" // free api key on api.openweathermap.org

#include < ESP8266WiFi.h>
bool dry=false;
bool rain=false;
float c=1.0;

int pin = 0; // GPIO 0 pin of Dust Sensor
// #define ESP8266_LED 2
int ESP8266_LED = 2;
const char* ssid = "Piersoft"; //inserire SID e chiave WEP
const char* password = "12345678";

const char* hostw="178.62.133.61"; //api.openweathermap.org

const char* host = "54.86.132.254"; //data.sparkfun.com
const char* publicKey = ""; //inserire public stream on data.sparkfun.com
const char* privateKey = ""; //inserire private key on data.sparkfun.com
const char* host1 = "184.106.153.149"; //api.thinspeak.com (for twitter)
const char* privateKey1=""; //inserire privatekey thinkspeak twitter

unsigned long duration;
unsigned long starttime;
unsigned long sampletime_ms = 30000; //30000 for 30 sec, 300000 for 5 minutes
unsigned long lowpulseoccupancy = 0;
float ratio = 0;
float concentration = 0;
float concentration25 = 0;
float concentrationmg = 0;
float concentrationmg25 = 0;
int humidit=0.0;
String main="";

float pm10corretto=0;
float pm25corretto=0;

void setup() {

Serial.begin(9600);

pinMode(pin,INPUT);
starttime = millis();
pinMode(ESP8266_LED, OUTPUT);
delay(2000);
pinMode(ESP8266_LED, LOW);

// We start by connecting to a WiFi network

Serial.println();
Serial.println();
Serial.print("ESP8266 Connecting to ");
Serial.println(ssid);

WiFi.begin(ssid, password);

while (WiFi.status() != WL_CONNECTED) {

delay(500);
Serial.print(".");

}

Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());

Serial.print("connecting to ");
Serial.println(hostw);

// Use WiFiClient class to create TCP connections
WiFiClient client;
const int httpPort = 80;
if (!client.connect(hostw, httpPort)) {
Serial.println("connection failed");
setup();
//return;
}

// We now create a URI for the request

String url="/data/2.5/weather";
url+="?id=";
url += LOCATIONID;
url +="&APPID=";
url +=APIID;

Serial.print("Requesting URL: ");
Serial.println(url);

// This will send the request to the server
client.print(String("GET ") + url + " HTTP/1.1\r\n" +
"Host: "+hostw+"\r\nConnection: keep-alive\r\n\r\n");

delay(500);

// read response
String response = "";
while(client.available()){
String line = client.readStringUntil('\r');
// Serial.print(line);

if (line.indexOf("{") >=0){
response += (line);
}
if (line.indexOf("Clear") >=0 || line.indexOf("clear") >=0){
dry=true;
rain=false;
}
else if (line.indexOf("rain") >=0 || line.indexOf("Rain") >=0){
rain=true;
dry=false;
}

delay(1);
}

Serial.println();
Serial.print("Main: ");
Serial.println(getValuesFromKey(response, "main"));
main=getValuesFromKey(response, "main");

Serial.print("Temp: ");
Serial.print(getValuesFromKey(response,"temp").toInt()-272.15); // kelvin to celsius
Serial.println(" C°");

Serial.print("Humidity: ");
Serial.print(getValuesFromKey(response, "humidity"));
Serial.println(" %");

Serial.print("Pressure: ");
Serial.print(getValuesFromKey(response, "pressure"));
Serial.println(" hPa");
Serial.println();

humidit=(getValuesFromKey(response, "humidity").toInt());
correction(humidit);

}
void(* resetFunc) (void) = 0;

int value=0;

void loop() {
value++;
pinMode(ESP8266_LED, LOW);
if (value<=30) { duration = pulseIn(pin, LOW); lowpulseoccupancy = lowpulseoccupancy+duration; if ((millis()-starttime) > sampletime_ms)
{

ratio = lowpulseoccupancy/(sampletime_ms*10.0); // Integer percentage 0=>100
concentration = 1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62; // using spec sheet curve
// secondo me nella formula seguente / 10 secondo le formule sui siti no..ma i valori sono troppo alti anche se coerenti
concentrationmg= concentration * 0.427 /10;
concentrationmg25= concentration * 0.0020800535;

// 0.427 proviene da :
// http://www.fijnstofmeter.com/documentatie/Data-Validation.pdf
// assumendo PM10 "The mass of a particle in the PM10 channel is 1.21E-4 μg"
// PM concentration μg/m3 --> concentration × 3531.5 × Particles Mass
// 3531.5 è la conversione tra feet3 e m3
// ergo 3531.5 x 1.21 / 10000 = 0.4273 per il PM10
// The mass of a particle in the PM2.5 channel is 5.89E-7 μg
// analogamente 3531.5 x 5.89 / 10000000 = 0.0020800535
// tabelle di correzione --> fattore c
// PM10 corretto = PM10 non corretto x humidit/100 x c
pm10corretto=concentrationmg;
pm25corretto=concentrationmg25;

if (dry==true || rain == true) {
pm10corretto=concentrationmg*c*humidit/100;
pm25corretto=concentrationmg25*c*humidit/100;
}

if (pm10corretto <= 0.1 ) resetFunc(); lowpulseoccupancy = 0; starttime = millis(); } }else{ WiFiClient client; const int httpPort = 80; Serial.print("connecting to "); Serial.println(host); if (!client.connect(host, httpPort)) { Serial.println("connection failed"); //setup(); return; } Serial.print(lowpulseoccupancy); Serial.print(","); Serial.print(ratio); Serial.print(", concentrazione particelle per 0.0.1 feet3: "); Serial.println(concentration); Serial.print(",PM10 ug/m3 non corretto: "); Serial.println(concentrationmg); Serial.print("PM10 corretto: "); Serial.println(pm10corretto); Serial.print(", PM2.5 ug/m3 non corretto: "); Serial.println(concentrationmg25); Serial.print("PM25 corretto: "); Serial.println(pm25corretto); // We now create a URI for the request String url2 = "/input/"; url2 += publicKey; url2 += "?private_key="; url2 += privateKey; url2 += "&pm10="; url2 += pm10corretto; url2 += "&pm2_5="; url2 += pm25corretto; url2 += "&hum="; url2 += humidit; url2 += "&ic="; url2 += c; url2 += "&status="; url2 += main; Serial.print("connecting to "); Serial.println(host); if (!client.connect(host, httpPort)) { Serial.println("connection failed"); // resetFunc(); return; } Serial.print("Requesting UR2L: "); Serial.println(url2); // This will send the request to the server client.print(String("GET ") + url2 + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Connection: close\r\n\r\n"); pinMode(ESP8266_LED, HIGH); delay(200); pinMode(ESP8266_LED, LOW); delay(200); pinMode(ESP8266_LED, HIGH); delay(200); pinMode(ESP8266_LED, LOW); delay(200); pinMode(ESP8266_LED, HIGH); delay(200); pinMode(ESP8266_LED, LOW); delay(200); pinMode(ESP8266_LED, HIGH); delay(200); pinMode(ESP8266_LED, LOW); delay(200); pinMode(ESP8266_LED, HIGH); delay(200); pinMode(ESP8266_LED, LOW); delay(200); pinMode(ESP8266_LED, HIGH); delay(200); pinMode(ESP8266_LED, LOW); delay(200); while(client.available()){ String line = client.readStringUntil('\r'); Serial.print(line); } Serial.println(); Serial.println("closing connection Data"); if (pm10corretto > 50 ) { // la normativa prevede il max 50ug/m3 medie giornaliere da superare max 35 volte in una anno
WiFiClient client;
const int httpPort = 80;
Serial.print("connecting to ");
Serial.println(host1);
if (!client.connect(host1, httpPort)) {
Serial.println("connection Twitter failed");
// resetFunc();
return;
}

String url1 = "/apps/thingtweet/1/statuses/update?";
url1 += "api_key=";
url1 += privateKey1;
//cambiare @piersoft con proprio account se si vuole essere taggati
url1 += "&status=@piersoft Concentrazione PM10: ";
url1 += pm10corretto;
url1 += " qualcuno perlomeno sta fumando.. ";

delay(10);
Serial.print("Requesting URL Twitter: ");
Serial.println(url1);
// This will send the request to the server

client.print(String("GET ") + url1 + " HTTP/1.1\r\n" +
"Host: " + host1 + "\r\n" +
"Connection: close\r\n\r\n");

pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);
pinMode(ESP8266_LED, HIGH);
delay(100);
pinMode(ESP8266_LED, LOW);
delay(100);

//setup();
// Read all the lines of the reply from server and print them to Serial
while(client.available()){
String line = client.readStringUntil('\r');
Serial.print(line);
}

Serial.println();
Serial.println("closing connection Twitter");

}

delay(15*60000); // restart ogni 5 minuti
resetFunc();

}

}

String getValuesFromKey(const String response, const String sKey)
{
String sKey_ = sKey;

sKey_ = "\"" + sKey + "\":";

char key[sKey_.length()];

sKey_.toCharArray(key, sizeof(key));

int keySize = sizeof(key)-1;

String result = "";

int n = response.length();

for(int i=0; i < (n-keySize-1); i++) { char c[keySize]; for(int k=0; k fattore c
// PM10 corretto = PM10 non corretto x humidit/100 x c
Serial.print("humidity intera: ");
Serial.println(hum);

if (dry==true){
if (0<=hum && hum<=19) c=10.1; else if (20<=hum && hum<=24) c=8.75; else if (25<=hum && hum<=29) c=8; else if (30<=hum && hum<=34) c=8; else if (35<=hum && hum<=39) c=8; else if (40<=hum && hum<=44) c=7; else if (45<=hum && hum<=49) c=6; else if (50<=hum && hum<=54) c=5.75; else if (55<=hum && hum<=59) c=5.5; else if (60<=hum && hum<=64) c=5.5; else if (65<=hum && hum<=69) c=3.5; else if (70<=hum && hum <=74) c=3.5; else if (75<=hum && hum<=79) c=3.75; else if (80<=hum && hum <=84) c=2.25; else if (85<=hum && hum <=89) c=1.5; else if (90<=hum && hum<=94) c=0.825; else if (95<=hum && hum<=100) c=0.525; } else if (rain==true){ if (0<=hum && hum<=19) c=6.4; else if (20<=hum && hum<=24) c=6.4; else if (25<=hum && hum<=29) c=6.4; else if (30<=hum && hum<=34) c=6.4; else if (35<=hum && hum<=39) c=6.4; else if (40<=hum && hum<=44) c=6.3; else if (45<=hum && hum<=49) c=6.3; else if (50<=hum && hum<=54) c=5.7; else if (55<=hum && hum<=59) c=5.5; else if (60<=hum && hum<=64) c=4.2; else if (65<=hum && hum<=69) c=4.1; else if (70<=hum && hum<=74) c=3.2; else if (75<=hum && hum<=79) c=3.2; else if (80<=hum && hum<=84) c=2.1; else if (85<=hum && hum<=89) c=2.1; else if (90<=hum && hum<=94) c=0.8; else if (95<=hum&& hum<=100) c=0.5; } Serial.print("indice correzione: "); Serial.println(c); //float pm10=5; //prova correzione pm10 con valore fittizio //float pm10corretto=pm10*c*hum/100; //Serial.print("PM10 corretto: "); //Serial.println(pm10corretto); }

Nota metodologica:
1) il sensore è al buio (messo nastro isolante nel foro centrale) e inserito in una scatola con prese d'aria.
2) la formula di conversione tra particelle e microgrammi e feet al cubo e m3 è un'approssimazione come descritto su http://www.fijnstofmeter.com/documentatie/Data-Validation.pdf ed è relativa al PM10 --> 1,21E-4 (PM10) x 3531.5 x concentrazione particelle /100 --> 0.427 x concentrazione particelle / 100

particles2

particles

Quindi il codice usa le API di api.openweathermap.org per prendere le rilevazioni dell'umidità e del fatto che ci sia pioggia o sereno e viene applicata questa tabella correttiva:

Schermata 2015-09-18 alle 00.40.21

e quindi applicata la formula finale:
Schermata 2015-09-18 alle 00.40.29

nel codice le parti da personalizzare sono SSID e Password WEP, la key pubblica e privata di data.sparkfun.com, la key privata dell'app twitter collegata con proprio account thinkspeak, l'api key su openweathermap.org

Potrebbero interessarti anche...