Skip to content
  • MySensors
  • OpenHardware.io
  • Categories
  • Recent
  • Tags
  • Popular
Skins
  • Light
  • Brite
  • Cerulean
  • Cosmo
  • Flatly
  • Journal
  • Litera
  • Lumen
  • Lux
  • Materia
  • Minty
  • Morph
  • Pulse
  • Sandstone
  • Simplex
  • Sketchy
  • Spacelab
  • United
  • Yeti
  • Zephyr
  • Dark
  • Cyborg
  • Darkly
  • Quartz
  • Slate
  • Solar
  • Superhero
  • Vapor

  • Default (No Skin)
  • No Skin
Collapse
Brand Logo
  1. Home
  2. Hardware
  3. Air Quality Sensor

Air Quality Sensor

Scheduled Pinned Locked Moved Hardware
calibrationaqigas sensorhchoair quality
270 Posts 46 Posters 308.8k Views 35 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • M moskovskiy82

    Which one to use for detection of fire smoke? Currently have got several MQ-7 but they don't seem so good at it

    epierreE Offline
    epierreE Offline
    epierre
    Hero Member
    wrote on last edited by
    #198

    @moskovskiy82 said:

    Which one to use for detection of fire smoke? Currently have got several MQ-7 but they don't seem so good at it

    as discussed just above, a particle sensor could be good for smoke is a particle concentration, coupled with heat this would be a good indicator

    if (concentration > 315000) {
         Serial.println("Smokes from cigarettes detected! Or It might be a huge fire! Beware!"); 
    

    z-wave - Vera -> Domoticz
    rfx - Domoticz <- MyDomoAtHome <- Imperihome
    mysensors -> mysensors-gw -> Domoticz

    1 Reply Last reply
    0
    • M Offline
      M Offline
      moskovskiy82
      wrote on last edited by
      #199

      What about mq2 or mq135? Any experience? As a gas sensor will be more suitable detecting early fire

      epierreE 1 Reply Last reply
      0
      • M moskovskiy82

        What about mq2 or mq135? Any experience? As a gas sensor will be more suitable detecting early fire

        epierreE Offline
        epierreE Offline
        epierre
        Hero Member
        wrote on last edited by
        #200

        @moskovskiy82 said:

        What about mq2 or mq135? Any experience? As a gas sensor will be more suitable detecting early fire

        please see what it does, this is not a gas sensor this only detect particle size whatever the gas...

        z-wave - Vera -> Domoticz
        rfx - Domoticz <- MyDomoAtHome <- Imperihome
        mysensors -> mysensors-gw -> Domoticz

        M 1 Reply Last reply
        0
        • epierreE epierre

          @moskovskiy82 said:

          What about mq2 or mq135? Any experience? As a gas sensor will be more suitable detecting early fire

          please see what it does, this is not a gas sensor this only detect particle size whatever the gas...

          M Offline
          M Offline
          moskovskiy82
          wrote on last edited by
          #201

          @epierre
          It still detects concentration. Both state CO detection. So in case of fire won't they detect the increase in concentration much faster that the particle sensor like Sharp’s GP2Y1010AU0F or alternative?

          alexsh1A 1 Reply Last reply
          0
          • M moskovskiy82

            @epierre
            It still detects concentration. Both state CO detection. So in case of fire won't they detect the increase in concentration much faster that the particle sensor like Sharp’s GP2Y1010AU0F or alternative?

            alexsh1A Offline
            alexsh1A Offline
            alexsh1
            wrote on last edited by
            #202

            @moskovskiy82 For a fire smoke, you can use pretty much any gas or particle sensor - there are a quite few gases formed during the burning process. MQ2 is highly sensitivity and has a fast response time. I can recommend it for a fire detection usage. However, I have been disappointed in MQ* sensors in general - there are not accurate, require 24h heat-up time, consume a lot of power etc. The only advantage is the price.

            To detect fire to can use a flame sensor - http://www.instructables.com/id/Flame-detection-using-Arduino-and-flame-sensor/

            1 Reply Last reply
            1
            • rollercontainerR Offline
              rollercontainerR Offline
              rollercontainer
              wrote on last edited by
              #203

              Can someone tell me how to read this line?

              float mq135_ro = 10000.0;    // this has to be tuned 10K Ohm
              

              Do I have to messure the sensor and adjust the variable or do I have to tune the resistance? If I have to do the first thing, when do I have to messure it? In warm state and clean air with a multimeter?

              1 Reply Last reply
              0
              • alexsh1A Offline
                alexsh1A Offline
                alexsh1
                wrote on last edited by alexsh1
                #204

                @epierre Did you check out the airbeam, which is based on a more expensive sensor Shinyei PPD60PV?
                http://www.takingspace.org/airbeam-technical-specifications-operation-performance/

                They made a step-by-step manual about building the same on Shinyei PPD42NS. I took their code and stripped a few parts and this is what I am left with:

                #include  <SoftwareSerial.h>
                #include  <FlexiTimer2.h>
                
                int pin = 3;
                
                volatile  double  rawParticalCount;
                volatile  double  totalParticles  = 0;
                volatile  double  particleCountToDisplay  = 0;
                volatile  double  ratio = 0;
                volatile  uint16_t  timeCounter = 0;
                
                #define         numberOfPeaksRecording                            5
                volatile        uint32_t        previousPeaks[numberOfPeaksRecording];
                volatile        uint32_t        sumOfPreviousPeaks          = 0;
                volatile        uint32_t        instantGoal                         = 0;
                volatile        int32_t         delta                                     = 0;
                volatile        uint32_t        slowMovingAverage             = 0;
                volatile  boolean readyToSendData = false;
                
                void  setup() {
                    Serial.begin(115200);
                    pinMode(pin,INPUT);
                    
                    FlexiTimer2::set(1,1.0/10000,readPin);
                    FlexiTimer2::start();
                    
                }
                void  loop()  {
                   
                    
                    if(readyToSendData){
                                Serial.print(rawParticalCount,  DEC);
                                Serial.print("  Raw Particle  Count (0-10000) ");
                                Serial.print(ratio, DEC);
                                Serial.print("  Ratio (0-100%)  ");
                                Serial.print(particleCountToDisplay,  DEC); 
                                Serial.print("  Particle  Count");
                                Serial.println("");
                                             
                                readyToSendData = false;
                    }
                    
                }
                
                void  readPin(){
                    if(digitalRead(pin) ==  LOW){
                        rawParticalCount++;
                    }    
                    timeCounter++;
                    if  (timeCounter  ==  10000)
                    {
                        timeCounter=0;
                           
                        //Changes are made  here  based on  Chris Nafis's code: http://www.howmuchsnow.com/arduino/airquality/grovedust/
                        ratio = rawParticalCount/100.0; 
                        //Convert to  percentage, the shinyei reads 10milliseconds  to  90milliseconds  duration  for particles.  Basing on 10milliseconds, smallest  particle  assumingly  from  specification sheet.
                        //FlexiTimer2,  reads 10,000  readings  per second, which would be  1 reading per 100 microseconds. 100 readings  would be  10  milliseconds. Since Shinyei runs  at minimal 10  millisecond range.  I divided 10,000  readings  by  100 to  get 100.
                        //Good  example would be  rawPArticalCount  is  5000  half  of  the 10,000  readings were  active. 5000/100  would be  50  which translate to  50% low pulse occupancy.
                        totalParticles  = (1.1*pow(ratio,3)-3.8*pow(ratio,2)+520*ratio+0.62);
                        rawParticalCount  = 0;
                          
                                //  shift counters  over, code  adapted from  template  provided  by  Mike  Taylor  and Joshua  Schapiro  from  Carnegie  Mellon  University's  CREATE  Lab
                                for (uint8_t  i = 0;  i < (numberOfPeaksRecording-1); i++)  {
                                        previousPeaks[i]  = previousPeaks[i+1];
                                }
                                previousPeaks[numberOfPeaksRecording  - 1]  = totalParticles;
                                sumOfPreviousPeaks  = 0;
                                for (uint8_t  i = 0;  i < numberOfPeaksRecording; i++)  {
                                        sumOfPreviousPeaks  +=  previousPeaks[i];
                                }
                                instantGoal = 2*sumOfPreviousPeaks;
                                
                                delta = instantGoal - slowMovingAverage;
                                
                                if  (delta  < -5000){
                                        slowMovingAverage = slowMovingAverage - 250;
                                } else  if  (delta  < -2500){
                                        slowMovingAverage = slowMovingAverage - 120;
                                } else  if(delta  < -1200){
                                        slowMovingAverage = slowMovingAverage - 60;
                                } else  if(delta  < -500){
                                        slowMovingAverage = slowMovingAverage - 25;
                                } else  if(delta  < -5){
                                        slowMovingAverage = slowMovingAverage - 5;
                                } else  if(delta  < -1){
                                        slowMovingAverage = slowMovingAverage - 1;
                                } else  if(delta  > 5000) {
                                        slowMovingAverage = slowMovingAverage + 500;
                                } else  if(delta  > 2500){
                                        slowMovingAverage = slowMovingAverage + 250;
                                } else  if(delta  > 1200){
                                        slowMovingAverage = slowMovingAverage + 120;
                                } else  if(delta  > 500){
                                        slowMovingAverage = slowMovingAverage + 50;
                                } else  if(delta  > 5){
                                        slowMovingAverage = slowMovingAverage + 5;
                                } else  if(delta  > 1){
                                        slowMovingAverage = slowMovingAverage + 1;
                                }
                                
                                particleCountToDisplay  = slowMovingAverage;
                        readyToSendData = true;
                    }
                }
                

                I have not adopted it for MySensors yet.
                I like moving average they use, but the values do not make sense to me:

                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  53470.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 27.0000000000  Ratio (0-100%)  53970.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  54470.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 21.6200008392  Ratio (0-100%)  54970.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  55470.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 24.2800006866  Ratio (0-100%)  55970.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  56470.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 24.1200008392  Ratio (0-100%)  56970.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  57470.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 22.3199996948  Ratio (0-100%)  57970.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  58470.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 20.3600006103  Ratio (0-100%)  58970.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  59470.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 17.6299991607  Ratio (0-100%)  59970.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  60220.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 19.0499992370  Ratio (0-100%)  60720.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 0.0000000000  Ratio (0-100%)  60715.0000000000  Particle  Count
                0.0000000000  Raw Particle  Count (0-10000) 20.6599998474  Ratio (0-100%)  61215.0000000000  Particle  Count
                
                1 Reply Last reply
                0
                • epierreE Offline
                  epierreE Offline
                  epierre
                  Hero Member
                  wrote on last edited by
                  #205

                  @alexsh1 said:

                  I took their code and stripped a few parts and this is what I am left with:

                  @alexsh1 the PPDN42 is for 1 micron and 2.5 micron , this one is for 0.5 micron

                  airbeam has standard code: https://github.com/HabitatMap/AirCastingAndroidClient/blob/master/arduino/aircasting/aircasting_shinyeiPPD42NS.ino

                  or I've not seen ?

                  z-wave - Vera -&gt; Domoticz
                  rfx - Domoticz &lt;- MyDomoAtHome &lt;- Imperihome
                  mysensors -&gt; mysensors-gw -&gt; Domoticz

                  alexsh1A 1 Reply Last reply
                  0
                  • epierreE epierre

                    @alexsh1 said:

                    I took their code and stripped a few parts and this is what I am left with:

                    @alexsh1 the PPDN42 is for 1 micron and 2.5 micron , this one is for 0.5 micron

                    airbeam has standard code: https://github.com/HabitatMap/AirCastingAndroidClient/blob/master/arduino/aircasting/aircasting_shinyeiPPD42NS.ino

                    or I've not seen ?

                    alexsh1A Offline
                    alexsh1A Offline
                    alexsh1
                    wrote on last edited by
                    #206

                    @epierre this is not the air beam code. They introduced "do it yourself" consept similar to the airbeam but with a different sensor (shinyei ppd42ns)

                    1 Reply Last reply
                    0
                    • rollercontainerR Offline
                      rollercontainerR Offline
                      rollercontainer
                      wrote on last edited by
                      #207

                      Hey guys, I am struggeling to get the MQ135 to work. Is there a step by step howto? Or can someone answer my question from 3 days ago?
                      I would appreciate it very much.

                      alexsh1A 1 Reply Last reply
                      0
                      • rollercontainerR rollercontainer

                        Hey guys, I am struggeling to get the MQ135 to work. Is there a step by step howto? Or can someone answer my question from 3 days ago?
                        I would appreciate it very much.

                        alexsh1A Offline
                        alexsh1A Offline
                        alexsh1
                        wrote on last edited by
                        #208

                        @rollercontainer I followed David Gironi method to calibrate - it is described as follows:

                        Before you can use the sensor, it has to be calibrated. For this, connect the sensor to your circuit and leave it powered on for 12-24 h to burn it in. Then put it into outside air, preferably at 20°C/35% rel. hum. (humidity is not so crucial). Read out the calibration value as such

                        float rzero = gasSensor.getRZero();
                        Wait until the value has somewhat settled (30min-1h). Remember, this is an ADC measurement so you might not want to wait some time between reading the sensor and also do some averaging. Once you have determined your RZero, put it into the MQ135.h. Note: Different sensors will likely have different RZero!

                        #define RZERO 76.63

                        Congrats, you have calibrated the sensor and can now read the CO2 ppm value in your sketch

                        float ppm = gasSensor.getPPM();

                        rollercontainerR 1 Reply Last reply
                        1
                        • alexsh1A alexsh1

                          @rollercontainer I followed David Gironi method to calibrate - it is described as follows:

                          Before you can use the sensor, it has to be calibrated. For this, connect the sensor to your circuit and leave it powered on for 12-24 h to burn it in. Then put it into outside air, preferably at 20°C/35% rel. hum. (humidity is not so crucial). Read out the calibration value as such

                          float rzero = gasSensor.getRZero();
                          Wait until the value has somewhat settled (30min-1h). Remember, this is an ADC measurement so you might not want to wait some time between reading the sensor and also do some averaging. Once you have determined your RZero, put it into the MQ135.h. Note: Different sensors will likely have different RZero!

                          #define RZERO 76.63

                          Congrats, you have calibrated the sensor and can now read the CO2 ppm value in your sketch

                          float ppm = gasSensor.getPPM();

                          rollercontainerR Offline
                          rollercontainerR Offline
                          rollercontainer
                          wrote on last edited by
                          #209

                          @alexsh1 Thx
                          Is "RZERO" the same as "mq135_ro" or is it a seperate variable? (ro = R0 = RZERO?)

                          rollercontainerR alexsh1A 2 Replies Last reply
                          0
                          • rollercontainerR rollercontainer

                            @alexsh1 Thx
                            Is "RZERO" the same as "mq135_ro" or is it a seperate variable? (ro = R0 = RZERO?)

                            rollercontainerR Offline
                            rollercontainerR Offline
                            rollercontainer
                            wrote on last edited by
                            #210

                            So, obvious these are two variables. Wherefore is the mq135_ro? Is it the load resistor from signal to ground?

                            alexsh1A 1 Reply Last reply
                            0
                            • rollercontainerR rollercontainer

                              So, obvious these are two variables. Wherefore is the mq135_ro? Is it the load resistor from signal to ground?

                              alexsh1A Offline
                              alexsh1A Offline
                              alexsh1
                              wrote on last edited by
                              #211

                              @rollercontainer let's start from the basic - which MQ-135 do you have? A bare unit or with a logic controller and a variable resistor?

                              rollercontainerR 1 Reply Last reply
                              0
                              • alexsh1A alexsh1

                                @rollercontainer let's start from the basic - which MQ-135 do you have? A bare unit or with a logic controller and a variable resistor?

                                rollercontainerR Offline
                                rollercontainerR Offline
                                rollercontainer
                                wrote on last edited by
                                #212

                                @alexsh1 I bought a breakout board and desoldered everything but the sensor and the 33Ohm resistor for the heating. Then I soldered a 10kOhm pulldown from analog signal out to ground.

                                alexsh1A 1 Reply Last reply
                                0
                                • rollercontainerR rollercontainer

                                  @alexsh1 Thx
                                  Is "RZERO" the same as "mq135_ro" or is it a seperate variable? (ro = R0 = RZERO?)

                                  alexsh1A Offline
                                  alexsh1A Offline
                                  alexsh1
                                  wrote on last edited by
                                  #213

                                  @rollercontainer

                                  Apologies for the confusion. @epierre did not use this library, but I have used MQ135.h library, but have not adopted it for MySensors and I did not like the sensor's reading jumping up and down.

                                  In MQ135.h:

                                  // Calibration resistance at atmospheric CO2 level
                                  #define RZERO 394.5 //RZERO 76.63
                                  

                                  I think the principle of RZERO is the same as mq135_ro

                                  1 Reply Last reply
                                  0
                                  • rollercontainerR rollercontainer

                                    @alexsh1 I bought a breakout board and desoldered everything but the sensor and the 33Ohm resistor for the heating. Then I soldered a 10kOhm pulldown from analog signal out to ground.

                                    alexsh1A Offline
                                    alexsh1A Offline
                                    alexsh1
                                    wrote on last edited by
                                    #214

                                    @rollercontainer I have do not done any changes to my breakout board. Just tuning the variable resistor and that's it.

                                    One thing I noticed is that the sensor performs much better in enclosed premises (no windows and no doors). Alternatively, it has to be in the box or something. Any small light draft dramatically changing the readings.

                                    rollercontainerR 1 Reply Last reply
                                    0
                                    • alexsh1A alexsh1

                                      @rollercontainer I have do not done any changes to my breakout board. Just tuning the variable resistor and that's it.

                                      One thing I noticed is that the sensor performs much better in enclosed premises (no windows and no doors). Alternatively, it has to be in the box or something. Any small light draft dramatically changing the readings.

                                      rollercontainerR Offline
                                      rollercontainerR Offline
                                      rollercontainer
                                      wrote on last edited by
                                      #215

                                      @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#L33

                                      So, what the heck is mq135_ro? And what to tune to?

                                      alexsh1A 1 Reply Last reply
                                      0
                                      • alexsh1A Offline
                                        alexsh1A Offline
                                        alexsh1
                                        wrote on last edited by alexsh1
                                        #216

                                        @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:970
                                        

                                        I still have not connected the BMP280 to get the pressure and temp readings into the equation.

                                        What do you think?

                                        1 Reply Last reply
                                        0
                                        • rollercontainerR rollercontainer

                                          @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#L33

                                          So, what the heck is mq135_ro? And what to tune to?

                                          alexsh1A Offline
                                          alexsh1A Offline
                                          alexsh1
                                          wrote on last edited by
                                          #217

                                          @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#L33

                                          So, 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?

                                          1 Reply Last reply
                                          0
                                          Reply
                                          • Reply as topic
                                          Log in to reply
                                          • Oldest to Newest
                                          • Newest to Oldest
                                          • Most Votes


                                          26

                                          Online

                                          11.7k

                                          Users

                                          11.2k

                                          Topics

                                          113.0k

                                          Posts


                                          Copyright 2019 TBD   |   Forum Guidelines   |   Privacy Policy   |   Terms of Service
                                          • Login

                                          • Don't have an account? Register

                                          • Login or register to search.
                                          • First post
                                            Last post
                                          0
                                          • MySensors
                                          • OpenHardware.io
                                          • Categories
                                          • Recent
                                          • Tags
                                          • Popular