Hackster is hosting Hackster Holidays, Ep. 4: Livestream & Giveaway Drawing. Start streaming on Wednesday!Stream Hackster Holidays, Ep. 4 on Wednesday!
Vitalik BidochkaAndrew ShvaykaIlya Barkov
Published © Apache-2.0

PART 1 | How To Connect ESP-WROOM-32, MQ135 and ThingsBoard

In this article, we will show how to use ESP-WROOM-32 to get real-time data from air quality sensor and display it on ThingsBoard dashboard

IntermediateProtip1 hour18,845
PART 1 | How To Connect ESP-WROOM-32, MQ135 and ThingsBoard

Things used in this project

Hardware components

FireBeetle ESP32 IOT Microcontroller (Supports Wi-Fi & Bluetooth)
DFRobot FireBeetle ESP32 IOT Microcontroller (Supports Wi-Fi & Bluetooth)
×1
Grove - Gas Sensor(MQ2)
Seeed Studio Grove - Gas Sensor(MQ2)
We were used MQ-135
×1
Breadboard (generic)
Breadboard (generic)
×1
Jumper wires (generic)
Jumper wires (generic)
×1

Software apps and online services

Arduino IDE
Arduino IDE
ThingsBoard
ESP32 Board Package and the Serial Port Driver

Story

Read more

Schematics

Schema

Code

Arduino Code

C/C++
#include <WiFi.h>
#include <MQUnifiedsensor.h>
#include <ThingsBoard.h>

const char* ssid = "YOUR_SSID";           
const char* password = "YOUR_PASSWORD";

#define TOKEN               "YOUR_DEVICE_TOKEN"
#define THINGSBOARD_SERVER  "thingsboard.cloud"

// Initialize ThingsBoard client
WiFiClient espClient;
// Initialize ThingsBoard instance
ThingsBoard tb(espClient);
// the Wifi radio's status
int status = WL_IDLE_STATUS;

//Definitions
#define placa "ESP-32"
#define Voltage_Resolution 3.3
#define pin 34 //Analog input 0 of your arduino
#define type "MQ-135" //MQ135
#define ADC_Bit_Resolution 12 // For arduino UNO/MEGA/NANO
#define RatioMQ135CleanAir 3.6//RS / R0 = 3.6 ppm  

double          CO2          =   (0);

MQUnifiedsensor MQ135(placa, Voltage_Resolution, ADC_Bit_Resolution, pin, type);

void setup()
{
  Serial.begin(9600);
  if(Serial) Serial.println("Serial is open");

  WiFi.begin(ssid, password);

  Serial.print("Connecting");
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  Serial.print("Connected, IP address: ");
  Serial.println(WiFi.localIP());

  //Set math model to calculate the PPM concentration and the value of constants
  MQ135.setRegressionMethod(1); //_PPM =  a*ratio^b
 
  MQ135.init(); 
  Serial.print("Calibrating please wait.");
  float calcR0 = 0;
  for(int i = 1; i<=10; i ++)
  {
    MQ135.update(); // Update data, the arduino will be read the voltage on the analog pin
    calcR0 += MQ135.calibrate(RatioMQ135CleanAir);
    Serial.print(".");
  }
  MQ135.setR0(calcR0/10);
  Serial.println("  done!.");
  
  if(isinf(calcR0)) {Serial.println("Warning: Conection issue founded, R0 is infite (Open circuit detected) please check your wiring and supply"); while(1);}
  if(calcR0 == 0){Serial.println("Warning: Conection issue founded, R0 is zero (Analog pin with short circuit to ground) please check your wiring and supply"); while(1);}
  /*****************************  MQ CAlibration ********************************************/ 
  MQ135.serialDebug(false);
}

void loop()
{
  if (!tb.connected()) {
    // Connect to the ThingsBoard
    Serial.print("Connecting to: ");
    Serial.print(THINGSBOARD_SERVER);
    Serial.print(" with token ");
    Serial.println(TOKEN);
    if (!tb.connect(THINGSBOARD_SERVER, TOKEN)) {
      Serial.println("Failed to connect");
      return;
    }
  }

  MQ135.update(); // Update data, the arduino will be read the voltage on the analog pin
 
  MQ135.setA(110.47); MQ135.setB(-2.862);
  CO2 = MQ135.readSensor();

  MQ135.setA(605.18); MQ135.setB(-3.937);
  float CO = MQ135.readSensor();

  MQ135.setA(77.255); MQ135.setB(-3.18);
  float Alcohol = MQ135.readSensor();

  MQ135.setA(44.947); MQ135.setB(-3.445);
  float Toluene = MQ135.readSensor();

  MQ135.setA(102.2 ); MQ135.setB(-2.473);
  float NH4 = MQ135.readSensor();

  MQ135.setA(34.668); MQ135.setB(-3.369);
  float Acetone = MQ135.readSensor();
  
  Serial.print("CO2: ");
  Serial.println(CO2);
  Serial.print("Light level: ");
  Serial.println(lux);
  Serial.println("Sending data...");

  tb.sendTelemetryFloat("CO2", CO2);  
  
  tb.sendTelemetryFloat("CO", CO);  
  
  tb.sendTelemetryFloat("Alcohol", Alcohol);  
  
  tb.sendTelemetryFloat("Toluene", Toluene);  
  
  tb.sendTelemetryFloat("NH4", NH4);  
  
  tb.sendTelemetryFloat("Acetone", Acetone);  

  tb.loop();
  
  delay(1000); //Sampling frequency
}

Dashboard JSON File

JSON
{
  "title": "Air Quality",
  "image": null,
  "mobileHide": false,
  "mobileOrder": null,
  "configuration": {
    "description": "",
    "widgets": {
      "11a80b8e-e962-de17-dc1c-cc1543aebf2c": {
        "isSystemType": true,
        "bundleAlias": "charts",
        "typeAlias": "basic_timeseries",
        "type": "timeseries",
        "title": "New widget",
        "image": null,
        "description": null,
        "sizeX": 8,
        "sizeY": 5,
        "config": {
          "datasources": [
            {
              "type": "entity",
              "name": null,
              "entityAliasId": "4bf9b60c-91d0-61e1-ec10-d1bdca48100d",
              "filterId": null,
              "dataKeys": [
                {
                  "name": "CO2",
                  "type": "timeseries",
                  "label": "CO2",
                  "color": "#2196f3",
                  "settings": {
                    "excludeFromStacking": false,
                    "hideDataByDefault": false,
                    "disableDataHiding": false,
                    "removeFromLegend": false,
                    "showLines": true,
                    "fillLines": false,
                    "showPoints": false,
                    "showPointShape": "circle",
                    "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
                    "showPointsLineWidth": 5,
                    "showPointsRadius": 3,
                    "tooltipValueFormatter": "",
                    "showSeparateAxis": false,
                    "axisTitle": "",
                    "axisPosition": "left",
                    "axisTicksFormatter": "",
                    "thresholds": [
                      {
                        "thresholdValueSource": "predefinedValue"
                      }
                    ],
                    "comparisonSettings": {
                      "showValuesForComparison": true,
                      "comparisonValuesLabel": "",
                      "color": ""
                    }
                  },
                  "_hash": 0.019369294834221784
                },
                {
                  "name": "Alcohol",
                  "type": "timeseries",
                  "label": "Alcohol",
                  "color": "#f44336",
                  "settings": {
                    "excludeFromStacking": false,
                    "hideDataByDefault": false,
                    "disableDataHiding": false,
                    "removeFromLegend": false,
                    "showLines": true,
                    "fillLines": false,
                    "showPoints": false,
                    "showPointShape": "circle",
                    "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
                    "showPointsLineWidth": 5,
                    "showPointsRadius": 3,
                    "tooltipValueFormatter": "",
                    "showSeparateAxis": false,
                    "axisTitle": "",
                    "axisPosition": "left",
                    "axisTicksFormatter": "",
                    "thresholds": [
                      {
                        "thresholdValueSource": "predefinedValue"
                      }
                    ],
                    "comparisonSettings": {
                      "showValuesForComparison": true,
                      "comparisonValuesLabel": "",
                      "color": ""
                    }
                  },
                  "_hash": 0.10773096272975002
                },
                {
                  "name": "CO",
                  "type": "timeseries",
                  "label": "CO",
                  "color": "#ffc107",
                  "settings": {
                    "excludeFromStacking": false,
                    "hideDataByDefault": false,
                    "disableDataHiding": false,
                    "removeFromLegend": false,
                    "showLines": true,
                    "fillLines": false,
                    "showPoints": false,
                    "showPointShape": "circle",
                    "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
                    "showPointsLineWidth": 5,
                    "showPointsRadius": 3,
                    "tooltipValueFormatter": "",
                    "showSeparateAxis": false,
                    "axisTitle": "",
                    "axisPosition": "left",
                    "axisTicksFormatter": "",
                    "thresholds": [
                      {
                        "thresholdValueSource": "predefinedValue"
                      }
                    ],
                    "comparisonSettings": {
                      "showValuesForComparison": true,
                      "comparisonValuesLabel": "",
                      "color": ""
                    }
                  },
                  "_hash": 0.16983810931760046
                },
                {
                  "name": "NH4",
                  "type": "timeseries",
                  "label": "NH4",
                  "color": "#607d8b",
                  "settings": {
                    "excludeFromStacking": false,
                    "hideDataByDefault": false,
                    "disableDataHiding": false,
                    "removeFromLegend": false,
                    "showLines": true,
                    "fillLines": false,
                    "showPoints": false,
                    "showPointShape": "circle",
                    "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
                    "showPointsLineWidth": 5,
                    "showPointsRadius": 3,
                    "tooltipValueFormatter": "",
                    "showSeparateAxis": false,
                    "axisTitle": "",
                    "axisPosition": "left",
                    "axisTicksFormatter": "",
                    "thresholds": [
                      {
                        "thresholdValueSource": "predefinedValue"
                      }
                    ],
                    "comparisonSettings": {
                      "showValuesForComparison": true,
                      "comparisonValuesLabel": "",
                      "color": ""
                    }
                  },
                  "_hash": 0.8795072817187648
                },
                {
                  "name": "Acetone",
                  "type": "timeseries",
                  "label": "Acetone",
                  "color": "#607d8b",
                  "settings": {
                    "excludeFromStacking": false,
                    "hideDataByDefault": false,
                    "disableDataHiding": false,
                    "removeFromLegend": false,
                    "showLines": true,
                    "fillLines": false,
                    "showPoints": false,
                    "showPointShape": "circle",
                    "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
                    "showPointsLineWidth": 5,
                    "showPointsRadius": 3,
                    "tooltipValueFormatter": "",
                    "showSeparateAxis": false,
                    "axisTitle": "",
                    "axisPosition": "left",
                    "axisTicksFormatter": "",
                    "thresholds": [
                      {
                        "thresholdValueSource": "predefinedValue"
                      }
                    ],
                    "comparisonSettings": {
                      "showValuesForComparison": true,
                      "comparisonValuesLabel": "",
                      "color": ""
                    }
                  },
                  "_hash": 0.06822020169930765
                },
                {
                  "name": "Toluene",
                  "type": "timeseries",
                  "label": "Toluene",
                  "color": "#9c27b0",
                  "settings": {
                    "excludeFromStacking": false,
                    "hideDataByDefault": false,
                    "disableDataHiding": false,
                    "removeFromLegend": false,
                    "showLines": true,
                    "fillLines": false,
                    "showPoints": false,
                    "showPointShape": "circle",
                    "pointShapeFormatter": "var size = radius * Math.sqrt(Math.PI) / 2;\nctx.moveTo(x - size, y - size);\nctx.lineTo(x + size, y + size);\nctx.moveTo(x - size, y + size);\nctx.lineTo(x + size, y - size);",
                    "showPointsLineWidth": 5,
                    "showPointsRadius": 3,
                    "tooltipValueFormatter": "",
                    "showSeparateAxis": false,
                    "axisTitle": "",
                    "axisPosition": "left",
                    "axisTicksFormatter": "",
                    "thresholds": [
                      {
                        "thresholdValueSource": "predefinedValue"
                      }
                    ],
                    "comparisonSettings": {
                      "showValuesForComparison": true,
                      "comparisonValuesLabel": "",
                      "color": ""
                    }
                  },
                  "_hash": 0.8240666057673744
                }
              ]
            }
          ],
          "timewindow": {
            "realtime": {
              "timewindowMs": 60000
            }
          },
          "showTitle": true,
          "backgroundColor": "#fff",
          "color": "rgba(0, 0, 0, 0.87)",
          "padding": "8px",
          "settings": {
            "shadowSize": 4,
            "fontColor": "#545454",
            "fontSize": 10,
            "xaxis": {
              "showLabels": true,
              "color": "#545454"
            },
            "yaxis": {
              "showLabels": true,
              "color": "#545454",
              "tickDecimals": 2
            },
            "grid": {
              "color": "#545454",
              "tickColor": "#DDDDDD",
              "verticalLines": true,
              "horizontalLines": true,
              "outlineWidth": 1
            },
            "stack": false,
            "tooltipIndividual": false,
            "showTooltip": true,
            "timeForComparison": "previousInterval",
            "xaxisSecond": {
              "axisPosition": "top",
              "showLabels": true
            },
            "comparisonEnabled": false,
            "smoothLines": true,
            "tooltipCumulative": false
          },
          "title": "CO2",
          "dropShadow": true,
          "enableFullscreen": true,
          "titleStyle": {
            "fontSize": "16px",
            "fontWeight": 400
          },
          "useDashboardTimewindow": true,
          "displayTimewindow": true,
          "showTitleIcon": false,
          "iconColor": "rgba(0, 0, 0, 0.87)",
          "iconSize": "24px",
          "titleTooltip": "",
          "enableDataExport": true,
          "widgetStyle": {},
          "showLegend": true,
          "legendConfig": {
            "direction": "column",
            "position": "bottom",
            "sortDataKeys": false,
            "showMin": false,
            "showMax": false,
            "showAvg": true,
            "showTotal": false
          }
        },
        "row": 0,
        "col": 0,
        "id": "11a80b8e-e962-de17-dc1c-cc1543aebf2c"
      }
    },
    "states": {
      "default": {
        "name": "Air Quality",
        "root": true,
        "layouts": {
          "main": {
            "widgets": {
              "11a80b8e-e962-de17-dc1c-cc1543aebf2c": {
                "sizeX": 12,
                "sizeY": 6,
                "row": 0,
                "col": 0
              },
              "12d74d94-f73a-83d4-b708-6b4a4d7ad5f0": {
                "sizeX": 6,
                "sizeY": 6,
                "row": 0,
                "col": 12
              },
              "8b62ff45-cf96-5002-555a-a610115b545e": {
                "sizeX": 12,
                "sizeY": 5,
                "row": 6,
                "col": 0
              },
              "cd052af7-efa9-2e58-8197-0b406f3723e7": {
                "sizeX": 12,
                "sizeY": 3,
                "row": 6,
                "col": 12
              },
              "32311d7a-cfd7-23ea-a3f1-7687a79e7cb5": {
                "sizeX": 12,
                "sizeY": 2,
                "row": 9,
                "col": 12
              },
              "a03a3244-2944-55f8-35fe-df348de691ed": {
                "sizeX": 6,
                "sizeY": 6,
                "row": 0,
                "col": 18
              }
            },
            "gridSettings": {
              "backgroundColor": "#eeeeee",
              "columns": 24,
              "margin": 10,
              "backgroundSizeMode": "100%"
            }
          }
        }
      }
    },
    "entityAliases": {
      "4bf9b60c-91d0-61e1-ec10-d1bdca48100d": {
        "id": "4bf9b60c-91d0-61e1-ec10-d1bdca48100d",
        "alias": "Alias",
        "filter": {
          "type": "singleEntity",
          "resolveMultiple": false,
          "singleEntity": {
            "entityType": "DEVICE",
            "id": "d62db230-25b5-11ec-a9e6-556e8dbef35c"
          }
        }
      }
    },
    "filters": {},
    "timewindow": {
      "hideInterval": false,
      "hideAggregation": false,
      "hideAggInterval": false,
      "hideTimezone": false,
      "selectedTab": 0,
      "realtime": {
        "realtimeType": 0,
        "timewindowMs": 60000,
        "quickInterval": "CURRENT_DAY",
        "interval": 1000
      },
      "aggregation": {
        "type": "NONE",
        "limit": 25000
      }
    },
    "settings": {
      "stateControllerId": "entity",
      "showTitle": false,
      "showDashboardsSelect": true,
      "showEntitiesSelect": true,
      "showDashboardTimewindow": true,
      "showDashboardExport": true,
      "toolbarAlwaysOpen": true
    }
  },
  "name": "Air Quality"
}

Credits

Vitalik Bidochka

Vitalik Bidochka

3 projects • 1 follower
Andrew Shvayka

Andrew Shvayka

5 projects • 17 followers
Ilya Barkov

Ilya Barkov

3 projects • 0 followers

Comments