Air Quality Sensor
-
@epierre OK, I found a mistake in my Shinyei ppd42ns code. Basically, it produces pcs/0.01cf values (normally, anything from 2000 to 10000 per a 30 secs reading).
This sensor use counting method to test dust concentration but not weight method, and the unit it pcs/L or pcs/0.01cf.This has to be converted into ug/m3 (the EPA standard)and then we can convert it into ppmv. I do not think dividing it by a volume factor is enough. Please see below updated code, which combines both ppd42ns and MH-Z14A sensors.
/** * The MySensors Arduino library handles the wireless radio link and protocol * between your home built sensors/actuators and HA controller of choice. * The sensors forms a self healing radio network with optional repeaters. Each * repeater and gateway builds a routing tables in EEPROM which keeps track of the * network topology allowing messages to be routed to nodes. * * Created by Henrik Ekblad <henrik.ekblad@mysensors.org> * Copyright (C) 2013-2015 Sensnology AB * Full contributor list: https://github.com/mysensors/Arduino/graphs/contributors * * Documentation: http://www.mysensors.org * Support Forum: http://forum.mysensors.org * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * version 2 as published by the Free Software Foundation. * ******************************* * DESCRIPTION * * Dust Sensor for Shinyei ppd42ns * * 1 : COMMON(GND) * 2 : OUTPUT(P2) * 3 : INPUT(5VDC 90mA) * 4 : OUTPUT(P1) * 5 : INPUT(T1)・・・FOR THRESHOLD FOR [P2] - not used * * http://www.seeedstudio.com/wiki/images/4/4c/Grove_-_Dust_sensor.pdf * * connect the sensor as follows : * Pin 4 of dust sensor PM1 -> Digital 6 * Pin 3 of dust sensor -> +5V * Pin 2 of dust sensor PM25 -> Digital 3 * Pin 1 of dust sensor -> Ground * Contributor: epierre and alexsh1 **/ #include <MySensor.h> #include <SPI.h> // Define a static node address, remove if you want auto address assignment #define NODE_ADDRESS_DUST 11 #define NODE_ADDRESS_CO2 13 #define CHILD_ID_DUST_PM10 0 #define CHILD_ID_DUST_PM25 1 #define CHILD_ID_DUST_PM10_MG_M3 2 #define CHILD_ID_DUST_PM25_MG_M3 3 #define DUST_SENSOR_DIGITAL_PIN_PM10 6 #define DUST_SENSOR_DIGITAL_PIN_PM25 3 #define CHILD_ID 0 #define CO2_SENSOR_PWM_PIN 2 unsigned long SLEEP_TIME = 30*1000; // Sleep time between reads (in milliseconds) //VARIABLES int val = 0; // variable to store the value coming from the sensor float valDUSTPM25 =0.0; float lastDUSTPM25 =0.0; float valDUSTPM10 =0.0; float lastDUSTPM10 =0.0; unsigned long duration; unsigned long starttime; unsigned long endtime; unsigned long sampletime_ms = 30000; unsigned long lowpulseoccupancy = 0; float ratio = 0; long concentrationPM25 = 0; long concentrationPM10 = 0; float concentration = 0; float concentrationPM25_ugm3; float concentrationPM10_ugm3; int temp=273.5+22; //external temperature, if you can replace this with a DHT11 or better float ppmvPM25; float ppmvPM10; float valAIQ =0.0; float lastAIQ =0.0; unsigned long duration_co2; long co2ppm; MySensor gw; MyMessage dustMsgPM10(CHILD_ID_DUST_PM10, V_LEVEL); MyMessage msgPM10(CHILD_ID_DUST_PM10_MG_M3, V_LEVEL); MyMessage dustMsgPM25(CHILD_ID_DUST_PM25, V_LEVEL); MyMessage msgPM25(CHILD_ID_DUST_PM25_MG_M3, V_LEVEL); MySensor gw1; MyMessage msg(CHILD_ID, V_LEVEL); void setup() { gw.begin(NULL,NODE_ADDRESS_DUST,false); // Send the sketch version information to the gateway and Controller gw.sendSketchInfo("Dust Sensor PPD42NS", "1.5"); // Register all sensors to gateway (they will be created as child devices) gw.present(CHILD_ID_DUST_PM10, S_DUST); //gw.send(msgPM10.set("ppm")); gw.present(CHILD_ID_DUST_PM25, S_DUST); //gw.send(msgPM25.set("ppm")); gw.present(CHILD_ID_DUST_PM10_MG_M3, S_DUST); gw.present(CHILD_ID_DUST_PM25_MG_M3, S_DUST); pinMode(DUST_SENSOR_DIGITAL_PIN_PM10,INPUT); pinMode(DUST_SENSOR_DIGITAL_PIN_PM25,INPUT); gw1.begin(NULL,NODE_ADDRESS_CO2,false); gw1.sendSketchInfo("AIQ Sensor CO2 MH-Z14A", "1.0"); // Register all sensors to gateway (they will be created as child devices) gw1.present(CHILD_ID, S_AIR_QUALITY); pinMode(CO2_SENSOR_PWM_PIN, INPUT); } void loop() { //get PM 2.5 density of particles over 2.5 μm. concentrationPM25=(long)getPM(DUST_SENSOR_DIGITAL_PIN_PM25); Serial.print("PM25: "); Serial.print(concentrationPM25); Serial.println(" pcs/0.01cf"); concentrationPM25_ugm3 = conversion25(concentrationPM25); Serial.print("PM25: "); Serial.print(concentrationPM25_ugm3); Serial.println(" ug/m3"); Serial.print("\n"); //ppmv=mg/m3 * (0.08205*Tmp)/Molecular_mass //0.08205 = Universal gas constant in atm·m3/(kmol·K) ppmvPM25=((concentrationPM25_ugm3) * ((0.08205*temp)/28.97)); if ((concentrationPM25 != lastDUSTPM25)&&(concentrationPM25>0)) { gw.send(dustMsgPM25.set(ppmvPM25,2)); gw.send(msgPM25.set(concentrationPM25_ugm3,2)); lastDUSTPM25 = ceil(concentrationPM25); } //get PM 1.0 - density of particles over 1 μm. concentrationPM10=getPM(DUST_SENSOR_DIGITAL_PIN_PM10); Serial.print("PM10: "); Serial.print(concentrationPM10); Serial.println(" pcs/0.01cf"); concentrationPM10_ugm3 = conversion10(concentrationPM10); Serial.print("PM10: "); Serial.print(concentrationPM10_ugm3); Serial.println(" ug/m3"); Serial.print("\n"); //ppmv=mg/m3 * (0.08205*Tmp)/Molecular_mass //0.08205 = Universal gas constant in atm·m3/(kmol·K) ppmvPM10=((concentrationPM10_ugm3) * ((0.08205*temp)/28.97)); if ((ceil(concentrationPM10) != lastDUSTPM10)&&((long)concentrationPM10>0)) { gw.send(dustMsgPM10.set(ppmvPM10,2)); gw.send(msgPM10.set(concentrationPM10_ugm3,2)); lastDUSTPM10 = ceil(concentrationPM10); } while(digitalRead(CO2_SENSOR_PWM_PIN) == HIGH) {;} //wait for the pin to go HIGH and measure HIGH time duration_co2 = pulseIn(CO2_SENSOR_PWM_PIN, HIGH, 2000000); co2ppm = 5000 * ((duration_co2/1000) - 2)/1000; Serial.print("CO2: "); Serial.print(co2ppm); Serial.print(" ppm"); Serial.print("\n"); if ((co2ppm != lastAIQ)&&(abs(co2ppm-lastAIQ)>=10)) { gw1.send(msg.set((long)ceil(co2ppm))); lastAIQ = ceil(co2ppm); } //sleep to save on radio gw.sleep(SLEEP_TIME); gw1.sleep(SLEEP_TIME); } float conversion25(long concentrationPM25) { double pi = 3.14159; double density = 1.65 * pow (10, 12); double r25 = 0.44 * pow (10, -6); double vol25 = (4/3) * pi * pow (r25, 3); double mass25 = density * vol25; double K = 3531.5; return (concentrationPM25) * K * mass25; } float conversion10(long concentrationPM10) { double pi = 3.14159; double density = 1.65 * pow (10, 12); double r10 = 0.44 * pow (10, -6); double vol10 = (4/3) * pi * pow (r10, 3); double mass10 = density * vol10; double K = 3531.5; return (concentrationPM10) * K * mass10; } long getPM(int DUST_SENSOR_DIGITAL_PIN) { starttime = millis(); while (1) { duration = pulseIn(DUST_SENSOR_DIGITAL_PIN, LOW); lowpulseoccupancy += duration; endtime = millis(); if ((endtime-starttime) > sampletime_ms) { ratio = (lowpulseoccupancy-endtime+starttime)/(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 Serial.print("lowpulseoccupancy:"); Serial.print(lowpulseoccupancy); Serial.print("\n"); Serial.print("ratio:"); Serial.print(ratio); Serial.print("\n"); //Serial.print("PPDNS42:"); //Serial.println(concentration); //Serial.print("\n"); lowpulseoccupancy = 0; return(concentration); } } }Please see the terminal printout below. The lowpulseoccupancy and ratio are correct. um/m3 to ppmv conversion is correct as well. I had to dive into physics and a bit of googling to find out how to convert pcs/0.01cf into ug/m3 - this is a tricky one!
send: 11-11-0-0 s=1,c=1,t=37,pt=7,l=5,sg=0,st=ok:5.39 send: 11-11-0-0 s=3,c=1,t=37,pt=7,l=5,sg=0,st=ok:6.45 lowpulseoccupancy:3339978 ratio:11.03 PM10: 6751 pcs/0.01cf PM10: 10.53 ug/m3 send: 11-11-0-0 s=0,c=1,t=37,pt=7,l=5,sg=0,st=ok:8.80 send: 11-11-0-0 s=2,c=1,t=37,pt=7,l=5,sg=0,st=ok:10.53 CO2: 960 ppm send: 13-13-0-0 s=0,c=1,t=37,pt=4,l=4,sg=0,st=ok:960 lowpulseoccupancy:1983280 ratio:6.51 PM25: 3527 pcs/0.01cf PM25: 5.50 ug/m3 send: 11-11-0-0 s=1,c=1,t=37,pt=7,l=5,sg=0,st=ok:4.60 send: 11-11-0-0 s=3,c=1,t=37,pt=7,l=5,sg=0,st=ok:5.50 lowpulseoccupancy:3430970 ratio:11.34 PM10: 7008 pcs/0.01cf PM10: 10.93 ug/m3 send: 11-11-0-0 s=0,c=1,t=37,pt=7,l=5,sg=0,st=ok:9.13 send: 11-11-0-0 s=2,c=1,t=37,pt=7,l=5,sg=0,st=ok:10.93 CO2: 960 ppm lowpulseoccupancy:1789340 ratio:5.86 PM25: 3141 pcs/0.01cf PM25: 4.90 ug/m3 send: 11-11-0-0 s=1,c=1,t=37,pt=7,l=5,sg=0,st=ok:4.09 send: 11-11-0-0 s=3,c=1,t=37,pt=7,l=5,sg=0,st=ok:4.90 lowpulseoccupancy:3271804 ratio:10.80 PM10: 6563 pcs/0.01cf PM10: 10.23 ug/m3 send: 11-11-0-0 s=0,c=1,t=37,pt=7,l=5,sg=0,st=ok:8.55 send: 11-11-0-0 s=2,c=1,t=37,pt=7,l=5,sg=0,st=ok:10.23 CO2: 970 ppm send: 13-13-0-0 s=0,c=1,t=37,pt=4,l=4,sg=0,st=ok:970I still have not connected the BMP280 to get the pressure and temp readings into the equation.
What do you think?
-
@alexsh1 I dont think so, in epierres sketch both values appear:
https://github.com/empierre/arduino/blob/master/AirQuality-MQ135.ino#L25
https://github.com/empierre/arduino/blob/master/AirQuality-MQ135.ino#L33So, what the heck is mq135_ro? And what to tune to?
@rollercontainer said:
@alexsh1 I dont think so, in epierres sketch both values appear:
https://github.com/empierre/arduino/blob/master/AirQuality-MQ135.ino#L25
https://github.com/empierre/arduino/blob/master/AirQuality-MQ135.ino#L33So, what the heck is mq135_ro? And what to tune to?
I think https://github.com/empierre/arduino/blob/master/AirQuality-MQ135.ino#L25
is identical to
https://github.com/GeorgK/MQ135/blob/master/MQ135.h#L27 multiplied by a factor is 1000
Maybe @epierre can clarify it?
-
Hm, in the loop, mq135_ro will be read and used. As written in line 78, the MQ135_DEFAULTRO can be overwritten by the messured mq135_ro. Ok, but where is the 10kOhm voltage divider in this calculation? Included in the measurement of mq135_ro?
https://github.com/empierre/arduino/blob/master/AirQuality-MQ135.ino#L78 -
Hm, in the loop, mq135_ro will be read and used. As written in line 78, the MQ135_DEFAULTRO can be overwritten by the messured mq135_ro. Ok, but where is the 10kOhm voltage divider in this calculation? Included in the measurement of mq135_ro?
https://github.com/empierre/arduino/blob/master/AirQuality-MQ135.ino#L78@rollercontainer you are correct - mq135_ro is overwritten in the loop and I do not see a point in float mq135_ro = 10000.0; unless the mq135_ro function is deactivated during calibration. However, #define MQ135_DEFAULTRO 68550 this is the parameter you should change during the calibration process. Try to calibrate with the function mq135_ro and deactivating it though I am sure the result will be the same.
-
Hi all,
I have my library for reading sensor. It is open source and its name is OpenSensor. I think that it's useful for every body.
Besides, I have my a monitoring system in real time using Arduino, MQ2, MQ135, MG811, GP2Y10 sensors and shield wifi ESP8266. It use OpenSensor library to read value from sensor and push it to database of WebServer by ESP826.
This is link: https://github.com/tantt2810
Hoping it helpful for all,
Good job,
-
Hi all,
I have my library for reading sensor. It is open source and its name is OpenSensor. I think that it's useful for every body.
Besides, I have my a monitoring system in real time using Arduino, MQ2, MQ135, MG811, GP2Y10 sensors and shield wifi ESP8266. It use OpenSensor library to read value from sensor and push it to database of WebServer by ESP826.
This is link: https://github.com/tantt2810
Hoping it helpful for all,
Good job,
@tantt2810 Thanks
#define RSRO_CLEAN_AIR_FACTOR 3.7 //The value of Rs/Ro in clean air. According chart in datasheet. #define RL_VALUE 20 //The value of the load resistance on the board, in kilo ohms. #define GET_RO_SAMPLE_TIMES 10 //The times of calibrating #define GET_RS_SAMPLE_TIMES 10Can you please elaborate on how to calibrate the sensor?
Also how do you connect it if it comes on the board like this?http://i.ebayimg.com/00/s/NjAwWDYwMA==/z/vMIAAOxycD9TTOVW/$_1.JPG
-
@tantt2810 Thanks
#define RSRO_CLEAN_AIR_FACTOR 3.7 //The value of Rs/Ro in clean air. According chart in datasheet. #define RL_VALUE 20 //The value of the load resistance on the board, in kilo ohms. #define GET_RO_SAMPLE_TIMES 10 //The times of calibrating #define GET_RS_SAMPLE_TIMES 10Can you please elaborate on how to calibrate the sensor?
Also how do you connect it if it comes on the board like this?http://i.ebayimg.com/00/s/NjAwWDYwMA==/z/vMIAAOxycD9TTOVW/$_1.JPG
@alexsh1 said:
Also how do you connect it if it comes on the board like this?
http://i.ebayimg.com/00/s/NjAwWDYwMA==/z/vMIAAOxycD9TTOVW/$_1.JPGeasy here, the AOUT is the one you will put on an analog one.
the DOUT (Digital OUT) is just an alarm linked to a level you could change on the board)
-
@alexsh1 said:
Also how do you connect it if it comes on the board like this?
http://i.ebayimg.com/00/s/NjAwWDYwMA==/z/vMIAAOxycD9TTOVW/$_1.JPGeasy here, the AOUT is the one you will put on an analog one.
the DOUT (Digital OUT) is just an alarm linked to a level you could change on the board)
-
@epierre said:
the DOUT (Digital OUT) is just an alarm linked to a level you could change on the board)
So DOUT is not used. Just AOUT?
-
@epierre For the air quality purpose which sensor would you recommend TSG-2600 or TS2602? They are slightly different, but both detect aiir contaminants (based on ppm of H2 and EtOH).
So far, I got MH-Z14A and the Dust sensor working with OLED screen and Domoticz and I just want to add 1-2 sensors to finish the project.
-
How do i get the Airquality sensor to show in domoticz? I use the AirQuality example from the library and MQ2.
I can see that it works in the serial, and it shows as a node under the mysensors hardware, but nothing in log or the device list when i expose it for gas. -
How do i get the Airquality sensor to show in domoticz? I use the AirQuality example from the library and MQ2.
I can see that it works in the serial, and it shows as a node under the mysensors hardware, but nothing in log or the device list when i expose it for gas.@Tore-André-Rosander said:
ut nothing in log or the device list when i expose it for gas.
huh you're on which version of mysensors ? have you tried the console (in arduino programmer) to see if there are some readings or a good wiring ?
-
@epierre Hi! The dev branch (v 2) and the raspberry pi gateway (nrf24 directly connected to RPi GPIO). This is what i get in the serial console when i test with gas from a lighter:
Starting sensor (RNNNA-, 2.0.0-beta) Radio init successful. find parent send: 255-255-255-255 s=255,c=3,t=7,pt=0,l=0,sg=0,st=bc: find parent send: 255-255-255-255 s=255,c=3,t=7,pt=0,l=0,sg=0,st=bc: read: 0-0-255 s=255,c=3,t=8,pt=1,l=1,sg=0:0 parent=0, d=1 req id send: 255-255-0-0 s=255,c=3,t=3,pt=0,l=0,sg=0,st=ok: req id send: 255-255-0-0 s=255,c=3,t=3,pt=0,l=0,sg=0,st=ok: read: 0-0-255 s=255,c=3,t=4,pt=0,l=2,sg=0:5 send: 5-5-0-0 s=255,c=3,t=15,pt=0,l=2,sg=0,st=ok: send: 5-5-0-0 s=255,c=0,t=17,pt=0,l=10,sg=0,st=ok:2.0.0-beta send: 5-5-0-0 s=255,c=3,t=6,pt=1,l=1,sg=0,st=fail:0 id=5 Init complete, id=5, parent=0, distance=1 0 LPG:0ppm CO:0ppm SMOKE:0ppm 0 LPG:8ppm CO:47ppm SMOKE:18ppm send: 5-5-0-0 s=0,c=1,t=37,pt=2,l=2,sg=0,st=ok:95 0 LPG:0ppm CO:0ppm SMOKE:0ppm send: 5-5-0-0 s=0,c=1,t=37,pt=2,l=2,sg=0,st=ok:0``` -
@Tore-André-Rosander said:
t=37
I don't know, would it be possible to have someone knowing the difference of the gateway with domoticz for 2.0 ? here it seems correct to me, some value are well seend from the sensor, so it is between the gateway and domoticz for me.
-
@epierre I am attempting to apply this code to work with the MQ-8. I am trying to get rid of all of the radio and gw stuff that is in the code. Do you have anything that just calibrates the sensor and reads out the value without of all these other libraries?
-
@epierre Also, what is the purpose of #define MQ135_MAXRSRO 2.428 //for CO2
#define MQ135_MINRSRO? I don't see them being referenced after they're defined?@tuimanso said:
@epierre Also, what is the purpose of #define MQ135_MAXRSRO 2.428 //for CO2
#define MQ135_MINRSRO? I don't see them being referenced after they're defined?Datasheet defines min and max values they should guarantee, this is an application of it.
if(validinterval<MQ135_MAXRSRO && validinterval>MQ135_MINRSRO) { -
Your previous message
Hello,
I have a question about the MQ-8 sensor module . The potentiometer that is soldered onto the board, is it to control the sensitivity of the LED light or for the sensor itself? According to the datasheet for the sensor, the RL (load resistance) for the sensor should be at minimum 10k Ohm, yet I only see an SMD 102 resistor on the board, which is a 1K Ohm resistor. I have used a multimeter to connect the 5V pin and the AOUT pin, and I get precisely a measurement of about 1K Ohm... Does that mean that I should connect a load resistor to this?
This value seems very important since it is referenced in the code, the RL is part of the calculations, yet it is already pre-written 10K ohms...
Please Clarify
Thanks