Sunday, March 8, 2020

Weather station with ESP8266, DHT22 and BMP280

Objective:
  Setup a weather station with ESP8266 ESP-01, DHT22 and BMP280.  It also come with remote switch.

Note: 
  The experience from this project can be transfer to another project quickly.  Such as application with I2C and ESP8266.  The MQTT setup is not part of the scope of this project demonstration; therefore, it is not discussed here.

Learned lesson: 
1. How to program ESP8266 ESP-01.  See my other post at https://ap170210.blogspot.com/2020/03/program-esp8266-01-with-usb-to-esp8266.html
2. CH_PD/EN has to connect to 3.3V in order to work properly.
3. I2C set up with ESP8266 is different from Arduino.  For example, I must add Wire.pins(0, 2); Wire.begin(0, 2);   in order to make I2C work.  But Arduino Uno does not need it.
4. The location of SCL and SDA on ESP8266.
5. When program GPIO0 (not in this example) since it is grounded during the programming, do NOT set it to HIGH, it will damage your chip.


Code:
//Reference website
//https://lastminuteengineers.com/bmp280-esp8266-weather-station/
//https://www.theengineeringprojects.com/2019/05/introduction-to-esp-01.html
//https://www.instructables.com/id/One-More-Arduino-Weather-Station-ESP-01-BMP280-DHT/
//In order function properly, CH_PD/EN must connect to 3.3V

//BMP280 SDA -- ESP-01 GPIO0
//BMP280 SCL -- ESP-01 GPIO2
//BMP280 VCC -- 3.3V
//BMP280 GND -- GND
//DHT22 signal -- Tx(GPIO1)
//DHT22 VCC -- 3.3V
//DHT22 GND -- GND
//ESP-01 CH_PD/EN -- 3.3V

#include <ESP8266WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BMP280.h>
#include "DHT.h"

/************************* WiFi Access Point *********************************/
#define WLAN_SSID       "**********"
#define WLAN_PASS      "**********"
/************************* Adafruit.io Setup *********************************/
#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883                   // use 8883 for SSL
#define AIO_USERNAME    "**********"
#define AIO_KEY         "**********"

// DHT Sensor
#define DHTTYPE DHT22
uint8_t DHTPin = 1;  
DHT dht(DHTPin, DHTTYPE); 
float temperature_dht, humidity_dht;  

//Initialize BMP sensor              
Adafruit_BMP280 bmp;
float temperature, pressure, altitude;

// Create an ESP8266 WiFiClient class to connect to the MQTT server.
WiFiClient client;

// Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

/****************************** Feeds ***************************************/
Adafruit_MQTT_Publish bmp_temp =      Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/bmp_temp");
Adafruit_MQTT_Publish bmp_pressure =  Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/bmp_pressure");
Adafruit_MQTT_Publish dht_humidity =  Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/dht_humidity");
Adafruit_MQTT_Publish dht_temperature =  Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/dht_temperature");
Adafruit_MQTT_Subscribe onoffbutton = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/onoff");

int onoffpin=1;
/*************************** Sketch Code ************************************/
void MQTT_connect();

void setup() {
  //I2C stuff, without it, ESP8266 ESP-01 cannot work properly
  Wire.pins(0, 2); Wire.begin(0, 2);    
  bmp.begin(0x76); delay(100);

  pinMode(DHTPin, INPUT);
  dht.begin(); delay(100);
  
  WiFi.begin(WLAN_SSID, WLAN_PASS); while (WiFi.status() != WL_CONNECTED) {delay(500);}
  pinMode(onoffpin, OUTPUT); mqtt.subscribe(&onoffbutton);
}

void loop() {
  MQTT_connect();
  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(5000))) {
    if (subscription == &onoffbutton) {
      if(onoffbutton.lastread[1]==78){digitalWrite(onoffpin,LOW);}
      if(onoffbutton.lastread[1]==70){digitalWrite(onoffpin,HIGH);}
    }
  }
  temperature = bmp.readTemperature()-2.1;  //2.1 is the calibration factor
  pressure = bmp.readPressure() / 100.0F;
  //altitude = bmp.readAltitude(1015);  //1015 is the pressure at ~San Jose sea level
  temperature_dht =dht.readTemperature()-0.9; //0.9 is a calibration factor
  humidity_dht=dht.readHumidity();
  
  // Now we can publish stuff!
  if (pressure>0){
    bmp_temp.publish(temperature);delay(2000);
    bmp_pressure.publish(pressure);delay(2000);
  }
  if (humidity_dht>0){
    dht_temperature.publish(temperature_dht);delay(2000);
    dht_humidity.publish(humidity_dht);delay(2000);
  }
}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;
  // Stop if already connected.
  if (mqtt.connected()) {return;}
  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       mqtt.disconnect(); delay(5000);  // wait 5 seconds
       retries--;
       if (retries == 0) {while (1);} // basically die and wait for WDT to reset me   
  }  
}



BMP280 I2C Code


Objective: 

  • Demo a temperature and pressure reading from BMP280 with Arduino.


Connection:
        Arduino -- BMP280
5V (or 3.3V) -- Vcc
            GND -- GND
                A5 -- SCL
                A4 -- SDA

Note: 
    BMP280 work with 5V and 3.3V.  This BMP come with Vcc, GND, SCL, SDA, CSB and SDD.  Only the first four been connected in this project.


Arduino Code:
#include <Adafruit_BMP280.h>   // include Adafruit library for BMP280 sensor
Adafruit_BMP280 bmp; // I2C

void setup() {
  Serial.begin(115200); delay(100);
  bmp.begin(0x76); delay(100);
}

void loop() {
  Serial.println(bmp.readTemperature());delay(100);
  Serial.println(bmp.readPressure());delay(100);
  Serial.println(bmp.readAltitude(1013.25));delay(100);  //SEALEVELPRESSURE_HPA = 1013.25
}

Saturday, March 7, 2020

Program ESP8266-01 with USB to ESP8266 Adapter for Arduino


Objective: 
  • Demonstrate how to program ESP8266 ESP-01 with its USB adapter

Equipment: 
  • ESP8266 ESP-01
  • ESP8266 USB adapter
  • Shorting wire/assembly
ESP8266 kit can be purchased from Amazon.com

Learned Lesson:
1. GPIO0 has be grounded in order to program it.
2. CH_PD/EN need to connected to 3.3V in order to use ESP-01 after program is completed.
3. Software version must use 2.5.0.  Other version may not work.


Program Procedure:
  • Open Arduino IDE
  • In File --> References, enter "http://arduino.esp8266.com/stable/package_esp8266com_index.json" in "Additional Board Manager URLs" text box.

  • In Tool --> Board: --> Board Manager type in 8266
  • Install version 2.5.0.  Note: the correct version is very important.  
  • In Tool --> Board: select "Generic ESP8266 Module"

  • Modify "USB to ESP8266 Adapter for Arduino" module for shorting GND and GPIO0 temporary.



  • Connect ESP8266-01 to above module and insert to computer's USB port


  • Choose correct port.  From Tool --> Board: select correct port, in below example, it is COM 7.

  • Open test file.  From File --> Examples --> ESP8266 --> Blink
  • Upload the Blink program
  • After upload is complete, the ESP8266-01's led should be blinking now.  

  • If you want to program the same module again, please power cycle it (unplug and plug in from the USB port) before program it.

Trouble shooting:
  1. Check your wiring
  2. Check your ESP8266's driver version is 2.5.0
  3. GND and GPIO0 has been shorted.
  4. Power cycle it

Proclamation: 
Bonus:
Program ESP8266 ESP-01 with FT232RL FTDI USB to TTL Serial Converter Adapter


Proclamation: 
  Below procedure is inspired from https://iot-playground.com/blog/2-uncategorised/67-arduino-esp8266-ide


Procedure:
1. Plug in above USB adapter
2. Check if your computer can find its COM port if yes, skip to step 4
3. Install driver manually from https://www.ftdichip.com/Drivers/VCP.htm or just run the EXE file from https://www.ftdichip.com/Drivers/CDM/CDM21228_Setup.zip.
4. Connect your adapter as shown in below diagram.
5. Setup your Arduino IDE for ESP8266 as shown in previous procedure.
6. Upload a test program, it should work now.
7. Before your try to upload another program, you need to reset it first (unplug and plug its power pin).
 https://iot-playground.com/blog/2-uncategorised/67-arduino-esp8266-ide










Other Code Example:
  Below code is using ESP8266 ESP-01 with Adafruit's MQTT.  LED on ESP-01 can be remotely turned on or off, and ESP-01 push a new value to io.adafruit.  It is just for your reference only, and we will not discuss it in this project.

#include <ESP8266WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"

/************************* WiFi Access Point *********************************/

#define WLAN_SSID       "*******"
#define WLAN_PASS       "*******"

/************************* Adafruit.io Setup *********************************/

#define AIO_SERVER      "io.adafruit.com"
#define AIO_SERVERPORT  1883                   // use 8883 for SSL
#define AIO_USERNAME    "*******"
#define AIO_KEY         "*******"


WiFiClient client;
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);

Adafruit_MQTT_Publish   count =  Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/count");
Adafruit_MQTT_Subscribe onoffbutton  = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/onoff");

void MQTT_connect();

void setup() {
  Serial.begin(115200); delay(10);

  // Connect to WiFi access point.
  Serial.println(); Serial.println();
  Serial.print("Connecting to ");
  Serial.println(WLAN_SSID);

  WiFi.begin(WLAN_SSID, WLAN_PASS);
  while (WiFi.status() != WL_CONNECTED) {
    delay(500);
    Serial.print(".");
  }
  Serial.println();

  pinMode(1, OUTPUT);
  
  Serial.println("WiFi connected");
  Serial.println("IP address: "); Serial.println(WiFi.localIP());

  // Setup MQTT subscription for onoff feed.
  mqtt.subscribe(&onoffbutton);
}

int count_value=0;

void loop() {
  MQTT_connect();
  Adafruit_MQTT_Subscribe *subscription;
  while ((subscription = mqtt.readSubscription(5000))) {
    if (subscription == &onoffbutton) {
      Serial.print(F("Got: "));
      Serial.println((char *)onoffbutton.lastread);
      if(onoffbutton.lastread[1]==78){digitalWrite(1,HIGH);Serial.print("Light on");}
      if(onoffbutton.lastread[1]==70){digitalWrite(1,LOW);Serial.print("Light off");}
    }
  }
  
  count_value++ ;
  
  // Now we can publish stuff!
  Serial.print(F("\nSending pressure val ")); Serial.print(count_value);Serial.print("...");
  if (! count.publish(count_value)) {Serial.println(F("Failed"));} else { Serial.println(F("OK!"));  }
  delay(1000);

}

// Function to connect and reconnect as necessary to the MQTT server.
// Should be called in the loop function and it will take care if connecting.
void MQTT_connect() {
  int8_t ret;

  // Stop if already connected.
  if (mqtt.connected()) {
    return;
  }

  Serial.print("Connecting to MQTT... ");

  uint8_t retries = 3;
  while ((ret = mqtt.connect()) != 0) { // connect will return 0 for connected
       Serial.println(mqtt.connectErrorString(ret));
       Serial.println("Retrying MQTT connection in 5 seconds...");
       mqtt.disconnect();
       delay(5000);  // wait 5 seconds
       retries--;
       if (retries == 0) {
         // basically die and wait for WDT to reset me
         while (1);
       }
  }
  Serial.println("MQTT Connected!");
}