As with the ESP32, the ADC2 is also used for the WiFi, so analoge pin A5 is not usable when WiFi is used.
The onboard Blue LED is connected to GPIO 8.
Projects with an Arduino
As with the ESP32, the ADC2 is also used for the WiFi, so analoge pin A5 is not usable when WiFi is used.
The onboard Blue LED is connected to GPIO 8.
Use an ESP32 to get the best performance with your WiFi router.
For the best performance with your WiFi router, you should choose a wireless channel less used by any of your neighbors. Many routers use the same channel by default–e.g., 6–and unless you know to test for and change the Wi-Fi channel when you first install your router, you’re probably using the same channel as someone else nearby. In other words, decreased performance.
#include "WiFi.h" void setup(){ Serial.begin(57600); WiFi.mode(WIFI_STA); WiFi.disconnect(); delay(100); } void loop(){ Serial.println("Start scan"); int n = WiFi.scanNetworks(); if (n == 0) { Serial.println("no networks found"); } else { Serial.print(n); Serial.println(" networks found"); for (int i = 0; i < n; ++i) { Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i)); Serial.print(" ("); Serial.print(WiFi.RSSI(i)); Serial.print(") "); Serial.print(" ["); Serial.print(WiFi.channel(i)); Serial.print("] "); String encryptionTypeDescription = translateEncryptionType(WiFi.encryptionType(i)); Serial.println(encryptionTypeDescription); delay(10); } } Serial.println("Scan done"); Serial.println(""); delay(10000); } String translateEncryptionType(wifi_auth_mode_t encryptionType) { switch (encryptionType) { case (0): return "Open"; case (1): return "WEP"; case (2): return "WPA_PSK"; case (3): return "WPA2_PSK"; case (4): return "WPA_WPA2_PSK"; case (5): return "WPA2_ENTERPRISE"; default: return "UNKOWN"; } }
Here an example output from my neighborhood:
scan start
15 networks found
1: robnet2 (-54) [13] WPA2_PSK
2: woodfamily2 (-85) [2] WPA2_PSK
3: VGV7519DFC699 (-85) [6] WPA_WPA2_PSK
4: woodfamilyGuest (-86) [2] WPA2_PSK
5: FRITZ!Box 7581 MO (-87) [6] WPA2_PSK
6: Ziggo beneden (-89) [1] WPA2_PSK
7: Infinity (-89) [6] WPA_WPA2_PSK
8: Ziggo (-91) [1] WPA2_ENTERPRISE
9: Ziggo (-91) [11] WPA2_ENTERPRISE
10: Ziggo (-92) [1] WPA2_ENTERPRISE
11: Infinity (-92) [11] WPA2_PSK
12: FBI surveillance van (-93) [6] WPA_WPA2_PSK
13: Ziggo39330 (-94) [1] WPA2_PSK
14: Eightball's network (-94) [6] WPA2_PSK
15: DIRECT-8E-HP ENVY 4520 series (-96) [6] WPA2_PSK
scan done
Once you know the wireless channel that’s least congested near you, head to your router’s administration page by typing in its IP address in the browser address bar. Depending on your router, this will likely be something like 192.168.2.1, 192.168.1.1, or 10.0.0.1 (check your router manual or the bottom of your router for details).
Head to your router’s wireless settings to change the Wi-Fi channel and hit apply for it to take effect.
See also my other page using the ESP8266 / Wemos D1 Mini as WiFi scanner
Not all pins of the ESP32 can be used.
Below a list of all special pins of the ESP32
if(_uart_nr == 1 && rxPin < 0 && txPin < 0) { rxPin = 9; txPin = 10; }
It is quite easy to build your own MP3 player with an Arduino and a DFPlayer module.
You can buy the DFPlayer module on aliexpress or ebay for about 1,5 Euro.
I wanted he player to start playing the music as soon I connected the power on the setup, without pushing any buttons.
For this the DFPlayer has the busy pin. This pin will become HIGH when the player is idle. As soon as the player is playing music the pin will become low.
I used the DFPlayer_Mini_Mp3 control library from github. (see the program code below for the details.)
/******************************************************************************* * DFPlayer_Mini_Mp3, This library provides a quite complete function for * * DFPlayer mini mp3 module. * * www.github.com/dfrobot/DFPlayer_Mini_Mp3 (github as default source provider)* * DFRobot-A great source for opensource hardware and robot. * * * * This file is part of the DFplayer_Mini_Mp3 library. * * * * DFPlayer_Mini_Mp3 is free software: you can redistribute it and/or * * modify it under the terms of the GNU Lesser General Public License as * * published by the Free Software Foundation, either version 3 of * * the License, or any later version. * * * * DFPlayer_Mini_Mp3 is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * DFPlayer_Mini_Mp3 is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU Lesser General Public License for more details. * * * * You should have received a copy of the GNU Lesser General Public * * License along with DFPlayer_Mini_Mp3. If not, see * * http://www.gnu.org/licenses/. * * * ******************************************************************************/ #include "DFPlayer_Mini_Mp3.h" void setup () { Serial.begin (9600); mp3_set_serial (Serial); // set Serial for DFPlayer-mini mp3 module delay(1000); // wait 1 sec for mp3 module to set volume mp3_set_volume (20); // value 0~30 delay(1000); // wait 1 sec for mp3 module to set volume } void loop () { boolean play_state = digitalRead(8); if(play_state == HIGH){ mp3_next (); delay(1000); } delay(1000); }
Below the schematic I used for the connections between the arduino and the DFPlayer.
For the best performance, you should choose a wireless channel less used by any of your neighbors. Many routers use the same channel by default–e.g., 6–and unless you know to test for and change the Wi-Fi channel when you first install your router, you’re probably using the same channel as someone else nearby. In other words, decreased performance.
You can use the ESP8266E which sits on the Wemos D1 mini as WiFi scanner to check which channel to use for your own home WiFi setup.
You do not need any additional hardware to make the WiFi scanner.
With the WiFi scanner you can check which WiFi channels are mostly used in your neighborhood, and with what strength they are.
Here an example output from my neighborhood:
scan start
16 networks found
1: NETGEAR08 (-88) [1] CCMP
2: HZN243330904 (-92) [1] CCMP
3: Ziggo beneden (-88) [1] AUTO
4: NETGEAR54 (-87) [3] CCMP
5: ThewoodfamilyGuest (-86) [3] CCMP
6: REMOTE25teeh (-94) [3] CCMP
7: Ziggo23355 (-91) [6] CCMP
8: robnet5 (-93) [6] CCMP
9: Ziggo (-93) [6] ?
10: Ziggo (-91) [6] ?
11: TP-LINK_2DEE (-84) [6] CCMP
12: ASUS (-92) [6] CCMP
13: H368N0E860E (-90) [8] AUTO
14: FRITZ!Box 7581 MO (-91) [10] CCMP
15: robnet2 (-44) [11] CCMP
16: Ziggo19179 (-87) [11] TKIP
scan done
Here the code that gives the above output
#include "ESP8266WiFi.h" WiFiClient client; void setup() { Serial.begin(57600); } void loop() { SSID_scan(); delay(10000); } void SSID_scan() { Serial.println(""); Serial.println("scan start"); WiFi.disconnect(); delay(100); // WiFi.scanNetworks will return the number of networks found int n = WiFi.scanNetworks(); if (n == 0) Serial.println("no networks found"); else { Serial.print(n); Serial.println(" networks found"); for (int i = 0; i < n; ++i) { // Print SSID and RSSI for each network found Serial.print(i + 1); Serial.print(": "); Serial.print(WiFi.SSID(i)); Serial.print(" ("); Serial.print(WiFi.RSSI(i)); Serial.print(") "); Serial.print(" ["); Serial.print(WiFi.channel(i)); Serial.print("] "); Serial.println((String) encryptionTypeStr(WiFi.encryptionType(i))); delay(10); } } Serial.println("scan done"); Serial.println(""); } String encryptionTypeStr(uint8_t authmode) { switch (authmode) { case ENC_TYPE_NONE: return "NONE"; case ENC_TYPE_WEP: return "WEP"; case ENC_TYPE_TKIP: return "TKIP"; case ENC_TYPE_CCMP: return "CCMP"; case ENC_TYPE_AUTO: return "AUTO"; default: return "?";; } }
Once you know the wireless channel that's least congested near you, head to your router's administration page by typing in its IP address in the browser address bar. Depending on your router, this will likely be something like 192.168.2.1, 192.168.1.1, or 10.0.0.1 (check your router manual or the bottom of your router for details).
Head to your router's wireless settings to change the Wi-Fi channel and hit apply for it to take effect.
As the MQ135 is not really suited as a CO2 sensor (See my previous blog) and I still wanted to use it, I will use it as an air quality probe on an ESP8266.
As the title mentioned I will use an ESP8266 connected to my local WiFi router for this to send the data to thingspeak.com.
The ESP8266 I use is the Wemos D1 mini. The Wemos D1 mini has an USB interface and can be programmed with the normal Arduino GUI. You can add the board to it. See this article for how to add this board to the GUI.
I also use an DHT22 (AM2302) in this project to measure temperature and humidity. The DHT22 data pin is connected to pin D5 of the ESP8266 in my project. VCC is connected to the 5V of the ESP, GND is connected to GND. You can of course any digital pin you want in your project. Just change line “#define DHTPIN D5” with the pin number you want.
For the MQ-135 you can only connect it to pin A0, as this is the only analog pin on the ESP8266.
For the air quality I store the lowest measured value in the EEPROM, so anything worse/higher that this best value is bad air quality. I use variable a1 & a2 & a3 to check if it is an new ESP8266, if these value in EEPROM are different than the stored values I presume that it is a new ESP and then set the lowest value to 510, if the values are the same I do not change the lowest value in EEPROM.
Below the program I use for this project.
I will try to describe any main step of it.
As there are some problems copying the below text I have added download links at the bottom of this page.
// Add the ESP8266 library #include "ESP8266WiFi.h" // replace with your channel’s thingspeak API key String apiKey = "XXXXXXXXXXXXXXXXX"; const char* server = "api.thingspeak.com"; // Add the EEPROM library to store the lowest measured MQ-135 value #include "EEPROM.h" int address = 24; byte value; // DHT22 setup #include "DHT.h" #define DHTPIN D5 #define DHTTYPE DHT22 // DHT 22 (AM2302), AM2321 DHT dht(DHTPIN, DHTTYPE); float val; float vall; int sensorPin = A0; int sensorValue = 0; float v; float h; // humidity float tc; // temperature float tf; // temperature float f = 0.; float pp = 0.; // number of analog MQ-135 samples taken each time int s = 25; int t; int x; int lowest = 500; int lowest_l; int lowest_h; int tel = 0; int telc = 0; int id = 1; int air; int airt; int airv; // change one value below to reset lowest value back to 510 int a1 = 148; int a2 = 231; int a3 = 23; // cl should be >= 3 before writing new low // value to EEPROM int cl = 0; // 5 SSID's possible for when you need to measure // at different places const char* ssid1 = "your ssid 1"; const char* password1 = "your ssid 1 password"; const char* ssid2 = "your ssid 2"; const char* password2 = "your ssid 2 password"; const char* ssid3 = "your ssid 3"; const char* password3 = "your ssid 3 password"; const char* ssid4 = "your ssid 4"; const char* password4 = "your ssid 4 password"; const char* ssid5 = "your ssid 5"; const char* password5 = "your ssid 5 password"; // start with ssid1 const char* ssid = ssid1; const char* password = password1; WiFiClient client; void setup() { Serial.begin(57600); EEPROM.begin(512); pinMode(sensorPin, INPUT); WiFi.begin(ssid, password); Serial.print("Trying "); Serial.print (ssid); Serial.print(" - "); while (WiFi.status() != WL_CONNECTED) { telc = telc + 1; if ( telc >= 10) { if ( id == 1 ) { ssid = ssid1; password = password1; id = 2; } else { if ( id == 2 ) { ssid = ssid2; password = password2; id = 3; } else { if ( id == 3 ) { ssid = ssid3; password = password3; id = 4; } else { if ( id == 4 ) { ssid = ssid4; password = password4; id = 5; } else { if ( id == 5 ) { ssid = ssid5; password = password5; id = 1; } } } } } telc = 0; Serial.println("."); Serial.print("Trying "); Serial.print (ssid); Serial.print(" - "); WiFi.begin(ssid, password); } delay(2000); Serial.print("."); } Serial.println("Connected"); delay(100); Serial.print("IP address: "); Serial.println(WiFi.localIP()); // check if this is new hardware to set EEPROM to 510 if (EEPROM.read(505) == a1 || EEPROM.read(506) == a2 || EEPROM.read(507) == a3) { Serial.println ("EEPROM setup is correct, not changing current values"); } else { // this should be a new start EEPROM.write(500, 255); EEPROM.write(501, 255); EEPROM.write(505, a1); EEPROM.write(506, a2); EEPROM.write(507, a3); delay(50); EEPROM.commit(); Serial.println ("New start for MQ135, startup values set"); } lowest_l = EEPROM.read(500); lowest_h = EEPROM.read(501); lowest = lowest_l + lowest_h; dht.begin(); // sleep 10 minutes to warm up the MQ135 // 10 minutes could be to low as warmup can take longer Serial.println("Sleep 10 minutes to warm up MQ-135"); delay(600000); } void loop() { v = 0; t = 0; while (t < s) { // Read the anolog value s (25) times val = (analogRead(sensorPin)) * 1; v = v + val; t++; delay(10); } vall = v / s; Serial.print ("raw = "); Serial.println (vall); if (vall <= lowest - 1 ) { cl = cl + 1; } else { cl = 0; } // to avoid wrong low value, the value must be 3 times low if (cl >= 3) { cl = 0; lowest = vall; if (lowest >= 255) { lowest_l = 255; lowest_h = lowest - 255; } else { lowest_l = lowest; lowest_h = 0; } EEPROM.write(500, lowest_l); EEPROM.write(501, lowest_h); delay(50); EEPROM.commit(); Serial.println ("New lowest value, saving to EEPROM"); } vall = vall - lowest; if (vall <= 0 ) { vall = 0; } airt = airt + vall; airv = airt / (tel + 1); Serial.print ("low: "); Serial.println (lowest); Serial.print ("Bad Air quality : "); Serial.println (vall); Serial.print ("Bad Air quality average: "); Serial.print (airv); Serial.print (" "); Serial.print (tel + 1); Serial.print (" "); Serial.println (airt); delay(4982); tel = tel + 1; if (tel >= 57) { tel = 0; air = airt / 57; ReadDHT(); if (tc == 1 && h == 1) { delay(2000); ReadDHT(); } if (tc == 1 && h == 1) { delay(2000); ReadDHT(); } if (tc == 1 && h == 1) { delay(2000); ReadDHT(); } ZendData_thingspeak(); airt = 0; } } void ZendData_thingspeak() { // I am using 4 fields at Thingspeak // 1 = temperature // 2 = humidity // 3 = Air Quality // 4 = lowest ever Air Quality if (client.connect(server, 80)) { // "184.106.153.149" or api.thingspeak.com String postStr = apiKey; postStr += "&field1="; postStr += String(tc); postStr += "&field2="; postStr += String(h); postStr += "&field3="; postStr += String(air); postStr += "&field4="; postStr += String(lowest); postStr += "\r\n\r\n"; client.print("POST /update HTTP/1.1\n"); client.print("Host: api.thingspeak.com\n"); client.print("Connection: close\n"); client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n"); client.print("Content-Type: application/x-www-form-urlencoded\n"); client.print("Content-Length: "); client.print(postStr.length()); client.print("\n\n"); client.print(postStr); Serial.println("Data send to Thingspeak"); client.stop(); } } void ReadDHT() { // Reading temperature or humidity takes about 250 milliseconds! // Sensor readings may also be up to 2 seconds 'old' (its a very slow sensor) h = dht.readHumidity(); // Read temperature as Celsius (the default) tc = dht.readTemperature(); // Read temperature as Fahrenheit (isFahrenheit = true) tf = dht.readTemperature(true); // Check if any reads failed and exit early (to try again). if (isnan(h) || isnan(tc) || isnan(tf)) { Serial.println("Failed to read from DHT sensor!"); h = 1; tc = 1; return; } Serial.print("Humidity: "); Serial.print(h, 1); Serial.println(" %\t"); Serial.print("Temperature: "); Serial.print(tc, 1); Serial.println(" *C "); }
If you only want to use the MQ135 without the DHT22 then use the code below.
// Add the ESP8266 library #include "ESP8266WiFi.h" // replace with your channel’s thingspeak API key String apiKey = "XXXXXXXXXXXXXXXXX"; const char* server = "api.thingspeak.com"; // Add the EEPROM library to store the lowest measured MQ-135 value #include "EEPROM.h" int address = 24; byte value; float val; float vall; int sensorPin = A0; int sensorValue = 0; float v; float f = 0.; float pp = 0.; // number of analog MQ-135 samples taken each time int s = 25; int t; int x; int lowest = 500; int lowest_l; int lowest_h; int tel = 0; int telc = 0; int id = 1; int air; int airt; int airv; // change one value below to reset lowest value back to 510 int a1 = 148; int a2 = 231; int a3 = 23; // cl should be >= 3 before writing new low // value to EEPROM int cl = 0; // 5 SSID's possible for when you need to measure // at different places const char* ssid1 = "your ssid 1"; const char* password1 = "your ssid 1 password"; const char* ssid2 = "your ssid 2"; const char* password2 = "your ssid 2 password"; const char* ssid3 = "your ssid 3"; const char* password3 = "your ssid 3 password"; const char* ssid4 = "your ssid 4"; const char* password4 = "your ssid 4 password"; const char* ssid5 = "your ssid 5"; const char* password5 = "your ssid 5 password"; const char* ssid = ssid1; const char* password = password1; WiFiClient client; void setup() { Serial.begin(57600); EEPROM.begin(512); pinMode(sensorPin, INPUT); WiFi.begin(ssid, password); Serial.print("Trying "); Serial.print (ssid); Serial.print(" - "); while (WiFi.status() != WL_CONNECTED) { telc = telc + 1; if ( telc >= 10) { if ( id == 1 ) { ssid = ssid1; password = password1; id = 2; } else { if ( id == 2 ) { ssid = ssid2; password = password2; id = 3; } else { if ( id == 3 ) { ssid = ssid3; password = password3; id = 4; } else { if ( id == 4 ) { ssid = ssid4; password = password4; id = 5; } else { if ( id == 5 ) { ssid = ssid5; password = password5; id = 1; } } } } } telc = 0; Serial.println("."); Serial.print("Trying "); Serial.print (ssid); Serial.print(" - "); WiFi.begin(ssid, password); } delay(2000); Serial.print("."); } Serial.println("Connected"); delay(100); Serial.print("IP address: "); Serial.println(WiFi.localIP()); // check if this is new hardware to set EEPROM to 510 if (EEPROM.read(505) == a1 || EEPROM.read(506) == a2 || EEPROM.read(507) == a3) { Serial.println ("EEPROM setup is correct, not changing current values"); } else { // this should be a new start EEPROM.write(500, 255); EEPROM.write(501, 255); EEPROM.write(505, a1); EEPROM.write(506, a2); EEPROM.write(507, a3); delay(50); EEPROM.commit(); Serial.println ("New start for MQ135, startup values set"); } lowest_l = EEPROM.read(500); lowest_h = EEPROM.read(501); lowest = lowest_l + lowest_h; // sleep 10 minutes to warm up the MQ135 // 10 minutes could be to low as warmup can take longer Serial.println("Sleep 10 minutes to warm up MQ-135"); delay(600000); } void loop() { v = 0; t = 0; while (t < s) { // Read the anolog value s (25) times val = (analogRead(sensorPin)) * 1; v = v + val; t++; delay(10); } vall = v / s; Serial.print ("raw = "); Serial.println (vall); if (vall <= lowest - 1 ) { cl = cl + 1; } else { cl = 0; } // to avoid wrong low value, the value must be 3 times low if (cl >= 3) { cl = 0; lowest = vall; if (lowest >= 255) { lowest_l = 255; lowest_h = lowest - 255; } else { lowest_l = lowest; lowest_h = 0; } EEPROM.write(500, lowest_l); EEPROM.write(501, lowest_h); delay(50); EEPROM.commit(); Serial.println ("New lowest value, saving to EEPROM"); } vall = vall - lowest; if (vall <= 0 ) { vall = 0; } airt = airt + vall; airv = airt / (tel + 1); Serial.print ("low: "); Serial.println (lowest); Serial.print ("Bad Air quality : "); Serial.println (vall); Serial.print ("Bad Air quality average: "); Serial.print (airv); Serial.print (" "); Serial.print (tel + 1); Serial.print (" "); Serial.println (airt); delay(4982); tel = tel + 1; if (tel >= 57) { tel = 0; air = airt / 57; ZendData_thingspeak(); airt = 0; } } void ZendData_thingspeak() { // I am using 2 fields at Thingspeak // 1 = Air Quality // 2 = lowest ever Air Quality if (client.connect(server, 80)) { // "184.106.153.149" or api.thingspeak.com String postStr = apiKey; postStr += "&field1="; postStr += String(air); postStr += "&field2="; postStr += String(lowest); postStr += "\r\n\r\n"; client.print("POST /update HTTP/1.1\n"); client.print("Host: api.thingspeak.com\n"); client.print("Connection: close\n"); client.print("X-THINGSPEAKAPIKEY: " + apiKey + "\n"); client.print("Content-Type: application/x-www-form-urlencoded\n"); client.print("Content-Length: "); client.print(postStr.length()); client.print("\n\n"); client.print(postStr); Serial.println("Data send to Thingspeak"); client.stop(); } }
Microsoft Explorer and Microsoft Edge seems to put this on one unusable line.
But Firefox and Google Chrome are both working.
I had bought 3 MQ-135 gas sensors on AliExpress to test if it is possible to measure CO2 with them.
First I started with a very simple analog read to check the values in my computer/hobby room with a CO2 ppm around 650.
// select the input pin for the MQ-135 sensor int sensorPin = A6; // variable to store the value coming from the sensor. int val = 0; void setup() { Serial.begin(9600); } void loop() { // read the value from the sensor val = analogRead(sensorPin); Serial.println (val); delay(1000); }
I connected the 5V power to the sensors and let them alone for 24 hours to burn in.
After these 24 hours I checked the values measured with the above little test program.
The values were 13 – 32 – 55
Breathing on them gave very little difference, as the values were only doubled to 28 – 61 – 103
With these values you can say that the first two are useless to measure CO2 as the difference is to little.
13 – 28 for CO2 ppm of about 500 – 2000 gives a resolution of about 100ppm/value measurement
32 – 61 gives about 52ppm/value
55 – 103 gives the best resolution of about 31ppm/value
These resolutions are valid if the scale is lineair, but the scale is logirithmic.
So in the lower ppm part the resolution is much better, but above the 1000ppm the resolution will be very low.
Found out that the resistor towards ground was just 1K ohm, after replacing the resister with one 22K ohm the results were getting much better.
In my room s the real ppm was about 770 ppm according to my NETATMO.
The raw value measured with the arduino was now 241.
Using MQ135-master from G.Krocker site and modifying MQ135.h with the correct RLOAD resistor value of 22K and a RZERO of 879.13
and using the below Arduino code
// The load resistance on the board #define RLOAD 22.0 // Calibration resistance at atmospheric CO2 level #define RZERO 879.13 #include "MQ135.h" MQ135 gasSensor = MQ135(A6); int val; int sensorPin = A6; int sensorValue = 0; void setup() { Serial.begin(9600); pinMode(sensorPin, INPUT); } void loop() { val = analogRead(A6); Serial.print ("raw = "); Serial.println (val); float zero = gasSensor.getRZero(); Serial.print ("rzero: "); Serial.println (zero); float ppm = gasSensor.getPPM(); Serial.print ("ppm: "); Serial.println (ppm); delay(5000); }
The Arduino sends out the following output to the serial port.
raw = 241 rzero: 691.60 ppm: 777.87
With these values I am very close to the values of the NETATMO
I will of course also run the calibration outside where it should show about 400ppm, and eventually adjust the RZERO in MQ135.h
The next morning ppm was down to 500 according to the NETATMO, but the arduino showed a ppm of 600. I change the RZERO to 819 and the arduino also showed 500.
This is no good of course, so something must go wrong in the calculations in the MQ135 library. Or I am using a MQ-135 sensor with a bad response curve.
The next day I have tested the same with another MQ-135, but the results were about the same.
The formula to calculate the resistance of the sensor is wrong.
It should read:
float MQ135::getResistance() { int val = analogRead(_pin); return ((1023. / (float)val) - 1.) * RLOAD; }
I think that I will stop my attempts for using the MQ-135 as a CO2 meter. With 1 sensor I measured different voltages on the analog port with same amount of CO2. It probably is to responsive to other gases in my surroundings. (Airport and highway).
One evening while my wife was one floor lower and took some perfume the ppm went sky high from 640ppm to 5570ppm, and then slowly (30 minutes) went down again.
I think that I will connect it to an ESP8266E to measure the outside air quality and sent the data over WiFi to thingspeak.com .