Project tutorial
Wireless weather station (Arduino + ESP8266 + Thingspeak)

Wireless weather station (Arduino + ESP8266 + Thingspeak) © GPL3+

Ever wondered how much CO level is in your city air? How about the temperature and humidity around you? If so, welcome to this project page!

  • 22 respects

Components and supplies

Necessary tools and machines

09507 01
Soldering iron (generic)
Hy gluegun
Hot glue gun (generic)
Electric file

Apps and online services

About this project


This project started off as a final assessment homework for an university course I've followed this year, but proved out to be a really fun and practical way of learning new and interesting things about wireless communication and microcontrollers in general.

The main idea:

The core of this project is an Arduino Uno developing board which gathers data from two sensors:

  • DHT 11 - which is used for measuring temperature and humidity levels
  • MQ-7 - which is used for measuring the CO level in the air (ppm)

The data received from the sensors is then sent to by using an ESP8266 12-E Wireless Module.

The components and their role:

M1201 step down buck converter (#2)

This component is needed to step down the voltage from 5V to 1.4V. The 1.4V are then used to power up the MQ-7 gas sensor for a period of 90s, the so called "reading period". (check MQ-7 datasheet for more info on the operation principle)

Note: The one that I had couldn't go down to 1.4V (although it should have) so I've used 2 more diodes to lower the voltage (check the schematics)

Mini-360 step down buck converter (#3)

This component is needed to step down the voltage from 5V to 3.3V. You can as well see it as the main 3.3V power supply in the system. The 3.3V are used to power up the ESP8266 12-E Wi-Fi module, as well as the low side of the logic level shifter.

  • The ESP8266 12-E is a Wi-Fi module which is powered at 3.3V, NOT 5V. Powering it at 5V will permanently damage the module!
  • The ESP8266 draws more than 200mA of current while operating and sending values to the web server. Powering it from Arduino's 3.3V power pin would be a big mistake as Arduino cannot provide that much current, thus making the Wi-Fi module unstable.

SRD-05VDC-SL-C 5V 1 Channel Relay Module(#8)

This relay is directly connected on the powering line of the MQ-7 CO gas sensor and has the role of cycling between 1.4V for 90S and 5V for 60s. Why so? Well according to the MQ-7 datasheet you have to heat up the sensor for 90s@5V. Only after the heating cycle you can read the sensor values for the next 60s@1.4V.

Note: See the MQ-7 datasheet for mor info on this

Logic level shifter 5V - 3.3V (#7)

Since the Arduino Uno runs at 5V and the ESP8266 12-E runs at 3.3V the logic levels are quite different between the two components. Thus, when trying to "speak" with the ESP8266 by using the RX,TX (serial communication) ports on the Arduino Uno we need a logic level shifter to do so. This component does exactly what we need: shifts the logic levels from 5V to 3.3V.

  • Check the image (fig. 1) bellow for a visual representation of the different logic levels.

Wi-Fi ESP8266 E-12 Wi-Fi module (#6)

I guess it's pretty obvious what this part is used for and that's connecting to a local Wi-Fi network (preconfigured in the source code) and sending the sensor data to

On/Off Switch (#10)

It seems that one cannot upload a new source code file on the Arduino Uno while having the TX pin connected to another component. If you try to do so you would get a lot of errors in Arduino IDE. While uploading a new sketch the TX pin should be "floating". To do so, I've used a on/off switch to disconnect the TX line from the ESP8266 whenever I want to upload an new code on the board. (check schematics down bellow)

MQ-7 Gas Sensor (#5)

Used for reading the CO level in the air. The value provided is measured in ppm.

  • As stated earlier check the datasheet to see the working principle. The sensor needs to be powered for 90s@5v, time during which no reading is done, and 60s@1.4V, time which represents the reading period.
  • Check the datasheet for info on calibrating the sensor.

Reset button (#9)

Since the hole wiring will be hidden inside a box a the end of this project, with the Arduino Uno stuck with hot glue at the bottom of box, uploading a new sketch on the board it would pose quite a problem when it comes to physically reseting the board without opening the box. To solve this issue we would need an external reset button. That's exactly what this big red button does. It resets the board.

The LED's (#9)

  • 11 - general error indicator (for debugging the error we would need to connect the board to a pc and check the Serial Monitor Interface in Arduino IDE for the error message)
  • 12 - signals the presence/absence of the ESP8266 in the current system
  • 13 - signals if ESP8266 is connected/not connected to the local network
  • 15 - blinks whenever the MQ-7 is heating
  • 16 - blinks whenever Arduino Uno reads data from sensors

The Buzzer

Whenever the CO level read from the MQ-7 gas sensor exceeds a certain value hardcoded in the code, an alarm will be triggered by using the buzzer.

Software requirements:

In order to see the value of sensor data, we will need a private channel on We will also need Arduino IDE to write/upload the code for Arduino Uno.

List of software requirements:

  • Private channel on and
  • Arduino IDE (Preferably latest version).

You can download latest version of Arduino IDE from

In order for the sketch to work we will also need the DHT11 library which you can download in the attachment section down bellow. For a step by step tutorial on how to add this library to Arduino IDE check the following link:

Now lets create a private channel on

Creating private channel on

To make a private channel on follow these steps:

  • Open your web browser and go to and click on 'Sign Up' tab in right top corner, (Image no.1)
  • Fill in the details and click on 'Create account', (Image no.2)
  • Now click on 'New Channel' tab, (Image no.3)
  • Again fill in details for channel and enable 4 fields (as we will be sending 4 sensor values), scroll down and click on 'Save Channel' tab, (Image no.4/5)
  • On this page click on 'API Keys' tab and note down your 'Write API Key'.

That's all folks, now you have your private ThingSpeak channel. Now lets put all electronics component together.

The Code

The code for Portable weather station is quite simple. I have commented code properly for ease of portability. Before you burn the code take care of following things.

  • Make sure that all libraries are installed,
  • Replace hyphens (--------) with SSID of your access point (wifi router) in line 14 of the code,
  • Replace hyphens (--------) with PASSWORD of your wifi network in line 15 of the code,
  • Replace hyphens (--------) with your ThingSpeak's private channel write API key in line 17 and
  • While uploading the code to the Arduino make sure that the on/off switch on the TX line is set to "off" so that you can upload the code

Now that we have our hardware and software in place, only thing remaining is packaging.

The logic

If you find the code pretty difficult to understand take a look on the logic diagram down bellow:

Packaging and enclosing the system

Down bellow you are going to find some useful photos taken while I was preparing the enclosure for the system. Make sure you have the tools required to make a box like the one bellow (elecrtic file, soldering iron, hot glue gun...)

  • As you can see in the third image above I've used some generic "mother" type pins soldered together for providing power/ground to the components of the system. I've then hot glue the piece to the side panel of the box, inside of it.


You can check the results of this project by clicking on the following link which should redirect you to the public view of my thingspeak channel:

Problems encountered during development

  • Sometimes some parts of the system went unresponsive due to poor contact on the breadboard. If the ESP8266 becomes unresponsive out of a sudden, first thing I would suggest doing would be to check the connections once again
  • If you see a lot of garbage in the Serial Monitor console make sure the baud rate in the console is set accordingly with the ESP8266 settings.

For more info on changing the baud rate of the Serial Montior console check the following link:

For more info on changing the baud rate setting of the ESP8266 check the following link:

  • Make sure you calibrate the MQ-7 sensor correctly as if not you would receive some big measurement errors

For more info on that check the following link:

Future projects tips

  • DHT11 isn't quite precise, in the sense that it can give random errors. A DHT22 sensor would prove much more accurate, but it is also a little bit more expensive than the DHT11
  • ESP8266 proved to be a little bit unstable during the development phase. A ESP32 or a NodeMCU board might be better for a future project

Some random photos taken during developing stage



Main CodeC/C++
#include "DHT.h"

//-----ESP8266 macros---------
#define SSID "------"//your network name
#define PASS "------"//your network password
#define IP "" //
#define Baud_Rate 9600 //Another common value is 115200
#define GREEN_LED 3 //optional LED's for debugging
#define RED_LED 4 //optional LED's for debugging
#define YELLOW_LED 5 //optional LED's for debugging
#define ESP_FOUND_LED 6 //optional LED's for debugging
#define DELAY_TIME 3000 //time in ms between posting data to ThingSpeak

//Can use a post also
String GET = "GET /update?key=------";
//String FIELD1 = "&field1=";
String FIELD2 = "&field2=";
String FIELD3 = "&field3=";

bool updated;

//----Relay/MQ-7 macros
#define RELAY 8
#define MQ7_ANALOG_IN_PIN 0
#define HEATING_LED 9
#define READING_LED 10
#define BUZZER 11

#define MQ7_HEATER_5_V_TIME_MILLIS 60000
#define MQ7_HEATER_1_4_V_TIME_MILLIS 90000

unsigned long startMillis;
unsigned long switchTimeMillis;
unsigned int gasLevel;
boolean heaterInHighPhase;

//----Temperature sensor macros
#define DHTPIN 7     // what pin the DHT sensor is connected to
#define DHTTYPE DHT11   // Change to DHT22 if that's what you have


//this runs once
void setup()
  //initalize DHT sensor

  //start the clock
  startMillis = millis();

  //initialize network LEDs
  pinMode(RED_LED, OUTPUT);

  //initialize MQ-7 LEDs
  pinMode(BUZZER, OUTPUT);

  //initialize MQ-7 power supply
  pinMode(RELAY, OUTPUT);

  //set baud rate

  //-----connect to network---------
  Serial.println("Checking if ESP8266 is online...");

  if (Serial.find("OK")) {
    digitalWrite(ESP_FOUND_LED, HIGH);
    Serial.println("ESP8266 found <module online>...");
    Serial.println("Trying to connect to network...");
    //connect to your wifi netowork
    bool connected = false;

    do {

      connected = connectWiFi();

      if (!connected) //signal failure
        for (int i = 0; i < 3; i++)
    } while (!connected);

    Serial.println("Connection achived....");
    digitalWrite(YELLOW_LED, HIGH); // indicate connection achived

  } else {
    Serial.println("ESP8266 not found...");
    goto connectionStart;


//this runs over and over
void loop() {

  if (heaterInHighPhase) {
    // 5v phase of cycle. see if need to switch low yet
    if (millis() > switchTimeMillis) {
      Serial.println("Reading from sensors....");
  else {
    // 1.4v phase of cycle. see if need to switch high yet
    if (millis() > switchTimeMillis) {
      Serial.println("Heating the gas sensor....");

    // Read temperature and humidity
    float h = dht.readHumidity();
    float f = dht.readTemperature(false);
    unsigned int gasLevel = readGasLevel();

    // Check if any reads failed and exit early (to try again).
    if (isnan(h) || isnan(f) || isnan(gasLevel)) {
    else if (gasLevel >= 60) {
      tone(BUZZER, 3000); // Send 1KHz sound signal...
    else {
      noTone(BUZZER);     // Stop sound...

    //update ThingSpeak channel with new values
    updated = updateValues(String(f), String(h), String(gasLevel));

    //if update succeeded light up green LED, else light up red LED
    if (updated) {
    } else {



//----network update function--------------
bool updateValues(String temp, String humid, String gasLevel) {

  //initialize your AT command string
  String cmd = "AT+CIPSTART=\"TCP\",\"";

  //add IP address and port
  cmd += IP;
  cmd += "\",80";


  if (Serial.find("Error")) {
    return false;

  //build GET command, ThingSpeak takes Post or Get commands for updates, I use a Get
  cmd = GET;
  //cmd += FIELD1;
  cmd += temp;
  cmd += FIELD2;
  cmd += humid;
  cmd += FIELD3;
  cmd += gasLevel;

  cmd += "\r\n";

  //Use AT commands to send data
  if (Serial.find(">")) {
    //send through command to update values
  } else {

  if (Serial.find("OK")) {
    //success! Your most recent values should be online.
    return true;
  } else {
    return false;

//----network functions--------------
boolean connectWiFi() {
  //set ESP8266 mode with AT commands

  //build connection command
  String cmd = "AT+CWJAP=\"";
  cmd += SSID;
  cmd += "\",\"";
  cmd += PASS;
  cmd += "\"";

  //connect to WiFi network and wait 5 seconds

  //if connected return true, else false
  if (Serial.find("OK")) {
    return true;
  } else {
    return false;

void Error() {

//----MQ-7 functions--------------

void blinkHeating() {
  digitalWrite(HEATING_LED, HIGH);
  digitalWrite(HEATING_LED, LOW);

void blinkReading() {
  digitalWrite(READING_LED, HIGH);
  digitalWrite(READING_LED, LOW);
//--read from gas sensor---------
unsigned int readGasLevel() {
  return analogRead(MQ7_ANALOG_IN_PIN);

//----network LEDs--------

void networkBlinkSending() {
  digitalWrite(RED_LED, LOW);
  digitalWrite(GREEN_LED, HIGH);
  digitalWrite(GREEN_LED, LOW);

void networkBlinkError() {
  digitalWrite(GREEN_LED, LOW);
  digitalWrite(RED_LED, HIGH);
  digitalWrite(RED_LED, LOW);

void networkBlinkConnecting() {
  digitalWrite(YELLOW_LED, HIGH);
  digitalWrite(YELLOW_LED, LOW);

//--- relay logic
void turnHeaterHigh() {
  // 5v phase
  digitalWrite(RELAY, HIGH);
  heaterInHighPhase = true;
  switchTimeMillis = millis() + MQ7_HEATER_5_V_TIME_MILLIS;

void turnHeaterLow() {
  // 1.4v phase
  digitalWrite(RELAY, LOW);
  heaterInHighPhase = false;
  switchTimeMillis = millis() + MQ7_HEATER_1_4_V_TIME_MILLIS;

Custom parts and enclosures

DHT 11 lib
MQ-7 Datasheet


Schematic PNG
Schita smp
Fritzing schematics


Similar projects you might like

Personal Weather Station (Arduino+ ESP8266 + Thingspeak)

Project tutorial by Jayraj Desai

  • 141 respects

Weather Station for Drones

Project tutorial by Giuseppe Caccavale

  • 48 respects

Weather Station with Thingspeak

Project showcase by Tittiamo

  • 8 respects

Arduino UNO Mini-Weather Station

Project tutorial by Igor Fonseca Albuquerque

  • 102 respects

The Zeus Electronic Weather Station (ZeWS)

Project in progress by moisi

  • 16 respects

Mobile Weather Station Being Powered by Solar Energy

Project tutorial by Kutluhan Aktar

  • 16 respects
Add projectSign up / Login