Building a WiFi based Room Monitor using an ESP8266 and an Arduino compatible

BeautifulPhoto635888272313367045Having purchased a few of the ESP8266 WiFi modules, I decided to devote one of them to a room monitoring device.  I live i a fairly good sized home, with an oversized garage. The room over the garage is a bedroom.  Well, the room, while nicely insulated, is huge and is difficult to maintain the same temperature as the rest of the upstairs.  And, since it is a bedroom where a child who has a problem maintaining his body temperature sleeps and plays, we need to keep an eye on the temp in that room.

I did have an Arduino UNO with the ethernet shield and a DHT11 sensor in the room, but the ethernet sheild did not work well with the WiFi extender I have in the room.  And, wanting to actually build something specifically for the purpose at hand, I decided to design and build a solution around the wifi module.

It needed to be simple and, preferably, run off of a battery.  While I have not yet gotten to WP_20160106_15_27_46_Pro_LIthe battery solution yet, I do have the rest built and am working on the code.

The whole thing fits on a 2.5 by 2inch perf board. It features an Atmega 328 chip, a Nokia 5110 LCD, DHT11 temp/humidity module, the aforementioned ESP8266 module, LED’s, a few caps and resistors and a 16mhz crystal.

WP_20160112_22_25_33_Pro_LIAssembly was easy.  Remembering the cathode on an LED…that’s hard, for me.  I always hated those damn things.  I love blinky lights, but can’t stand to wire up the things.  UGH.  Anyway, I’m only using a few of the I/O pins on the 328: Serial in and out, D2, A4, A5 and, for the LCD, D3 through D7.  This leaves a few pins for you to use if you wish to expand the capabilities of the device.

I started out by soldering the socket for the chip.  Then, I wired up the reset, which is pin 1 to a WP_20160119_22_28_27_Pro_LImomentary push button connected to ground.  I then wired up pin 13 to an LED via a 150 ohm resistor, connected to ground. Power (pin 7) and  ground (pin 8) were next.  You can test, at this point, by inserting a 328 that has the standard Arduino bootloader and nothing else burned into the chip. Insert the chip, apply five volts and the LED should blink.  If so, congrats!

You can install a power on LED as well.  Solder an LED and 150 ohm resistor to ground and Pin 7. When power is applied, the LED should light up.

The crystal was next.  Solder the crystal to pins 9 and 10.  Solder a 22pF capacitor to each each pin of the crystal and tie them to ground.

If you are at this point, congratulations, you have built a very basic Arduino compatible microcontroller. 

WP_20160115_18_50_02_Pro_LIFrom this point, I soldered some headers so I could connect serial I/O, power and the connections for the DHT11 and RTC (1307).   I then soldered the Nokia 5110 to the board and connected it as follows:

pin 7 – Serial clock out (SCLK)
pin 6 – Serial data out (DIN)
pin 5 – Data/Command select (D/C)
pin 4 – LCD chip select (CS)
pin 3 – LCD reset (RST)

Connect pin 6 on the LCD to +5, pin 8 to Ground and pin 7 to +5 if you want the back light. I connected a switch to my display so I could turn the light on or off.  Add the swtich between the +5 and pin 7 if you wish.

I uploaded a demo 5110 sketch to make sure the screen worked. It did.

The DHT only has one data pin, the middle pin, and it goes to D2 on the chip.  Connect the others to +5 and ground.

WP_20160118_00_04_44_Pro_LI (2)As the ESP8266 is intolerant of higher voltages, I installed a 3.3v regulator to power the module.  I grab a five volt line, solder it to the right pin of the to220 regulator, the left most pin to ground and the middle pin to the VCC pin on the 8266.  The TX line from the 8266 goes to D0 on the 328, the RX line to D1 and, ground to ground. You also, if you have the v1 of the module, connect power to the chip select pin (4) of the 8266 as well as connect its RST pin to the reset pin of the 328. 

The RTC (real time clock) is connected:
SCL to A5 on 328
SDA to A4 on 328
VCC to +5
GND to ground

Connect it all up and you have a complete wifi based room monitor. For now, it returns the temperature and humidity.  At somepoint, I am going to return a timestamp so I graph the data and figure out when the temperature spikes or cools. 

Software

WP_20160122_13_12_55_Pro_LIGetting the LCD to display the date, time, temperature and humidity was simple.  The issue I have is with the wifi module. And it is also keeping me from posting a complete solution. So, I am going to post what I have. If one of you can figure out the webserver piece, please share it with us. I am sure it is something I am doing wrong. 

The code is at the end of this post.

Building things from ‘scratch’ is far more rewarding than just connecting a few sensors to an UNO or some other board.  But, you can do that if you wish.  At any rate, no matter what you do, YOU are still doing it and that is what matters. 

Code:

/*********************************************************************
* This sketch uses the Adafruit libraries for Monochrome Nokia 5110 LCD Displays
*
* Pick one up today in the adafruit shop!
* ——> http://www.adafruit.com/products/338
*
* These displays use SPI to communicate, 4 or 5 pins are required to
* interface
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Limor Fried/Ladyada  for Adafruit Industries.
* BSD license, check license.txt for more information
* All text above, and the splash screen must be included in any redistribution
*********************************************************************/

#include <Adafruit_GFX.h>
#include <Adafruit_PCD8544.h>
#include “DHT.h”
#include <Wire.h>
#include “RTClib.h”

#define BUFFER_SIZE 128
char buffer[BUFFER_SIZE];

DHT dht;
RTC_DS1307 rtc;

// pin 7 – Serial clock out (SCLK)
// pin 6 – Serial data out (DIN)
// pin 5 – Data/Command select (D/C)
// pin 4 – LCD chip select (CS)
// pin 3 – LCD reset (RST)
Adafruit_PCD8544 display = Adafruit_PCD8544(7, 6, 5, 4, 3);

// Workaround for http://gcc.gnu.org/bugzilla/show_bug.cgi?id=34734
#ifdef PROGMEM
#undef PROGMEM
#define PROGMEM __attribute__((section(“.progmem.vars”)))
#endif
const unsigned char PROGMEM logo16_glcd_bmp[] =
{ B00000001, B10000000,
  B00000011, B11000000,
  B00000111, B11100000,
  B00001111, B11110000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000,
  B00000000, B00000000
};
#define SCREENWIDTH 84
#define SCREENHEIGHT 48

#define DEBUG true
const int ESP8266_CHPD = 4;
int isConnected = false;

void setup() {

  display.begin();
  Wire.begin();
  rtc.begin();
  //rtc.adjust(DateTime(__DATE__, __TIME__));
  if (! rtc.isrunning()) {
    display.println(“RTC is NOT running!”);
    // following line sets the RTC to the date & time this sketch was compiled
    rtc.adjust(DateTime(__DATE__, __TIME__));
  }
  Serial.begin(115200); // your esp’s baud rate might be different
  Serial.setTimeout(5000);
  Serial.println(“AT+RST”);

  if (Serial.find(“ready”))
  {
    display.println(“Module is ready”);
    isConnected = true;
    display.drawBitmap(0, 0, logo16_glcd_bmp, 16, 16, BLACK);
    display.display();
  }
  else
  {
    display.println(“Module have no response.”);
    display.display();
    setup();
  }
  Serial.print(“AT+CWMODE=1\r\n”);
  Serial.print(“AT+CWJAP=\”xxx\”,\”xxx\”\r\n”);  //replace xxx with your ssid and password
  Serial.print(“AT+CIFSR\r\n”);
  Serial.print(“AT+CIPMUX=1\r\n”);
  Serial.print(“AT+CIPSERVER=1,80\r\n”);
  display.println(Serial.read());
  display.setContrast(50);
  dht.setup(2); // data pin 2
  display.display(); // show splashscreen
  delay(2000);
  display.clearDisplay();   // clears the screen and buffer
  display.display();
  display.setTextSize(1);
  display.setTextColor(BLACK);
  display.println(“HalfByte Room    Monitor”);

  display.display();
  delay(3000);
  display.clearDisplay();
  display.setTextSize(1);
}

void loop() {
  int ch_id, packet_len;
  char *pb;
  Serial.readBytesUntil(‘\n’, buffer, BUFFER_SIZE);

  delay(dht.getMinimumSamplingPeriod());

  float humidity = dht.getHumidity();
  float temperature = dht.getTemperature();

  display.clearDisplay();
  display.display();
  if (isConnected == true) {
    display.drawBitmap(70, 0, logo16_glcd_bmp, 16, 16, BLACK);
    display.display();
  }
  display.setCursor(3, 29);
  display.print(“Humidity: “);
  display.setCursor(display.width() / 2, 38);
  display.print(humidity, 1);
  display.print(“%”);
  display.setCursor(3, 20);
  display.print(“Temp: “);
  display.setCursor(40, 20);
  display.print(dht.toFahrenheit(temperature), 1);
  display.print(“F”);
  display.drawRect(0, 28, display.width(), 19, BLACK);
  display.display();

  DateTime now = rtc.now();
  display.setCursor((display.width() / 2) – 35, 1);
  if (now.month() < 10) display.print(0);
  display.print(now.month(), DEC);
  display.print(‘/’);
  if (now.day() < 10) display.print(0);
  display.print(now.day(), DEC);
  display.print(‘/’);
  display.print(now.year(), DEC);
  display.setCursor((display.width() / 2) – 30, 12);
  if (now.hour() < 10) display.print(0);
  display.print(now.hour(), DEC);
  display.print(‘:’);
  if (now.minute() < 10) display.print(0);
  display.print(now.minute(), DEC);
  display.print(‘:’);
  if (now.second() < 10) display.print(0);
  display.print(now.second(), DEC);
  display.display();

  if (strncmp(buffer, “+IPD,”, 5) == 0) {
    // request: +IPD,ch,len:data
    sscanf(buffer + 5, “%d,%d”, &ch_id, &packet_len);
    if (packet_len > 0) {
      // read serial until packet_len character received
      // start from :
      pb = buffer + 5;
      while (*pb != ‘:’) pb++;
      pb++;
      if (strncmp(pb, “GET / “, 6) == 0)
        //if (Serial.available()) // check if the esp is sending a message
        //{
        if (Serial.find(“+IPD,”))
        {
          //delay(1000);
          delay(100);
          clearSerialBuffer();
          int connectionId = Serial.read() – 48; // subtract 48 because the read() function returns
          display.print(connectionId);
          display.display();
          // the ASCII decimal value and 0 (the first decimal number) starts at 48
          homepage(connectionId);
        }
    }
  }
}

void homepage(int ch_id) {
  String Header;
  float temperature = dht.getTemperature();
  Header =  “HTTP/1.1 200 OK\r\n”;
  Header += “Content-Type: text/html\r\n”;
  Header += “Connection: close\r\n”;
  Header += “Refresh: 5\r\n”;

  String Content;
  Content = “Environmental Status:<br/>”;
  Content += String(“<B>Temperature:</b>”);
  Content += String(dht.toFahrenheit(temperature));
  Content += String(“<br><b>Humidity: </b>”);
  Content += String(dht.getHumidity());
  Header += “Content-Length: “;
  Header += (int)(Content.length());
  Header += “\r\n\r\n”;

  Serial.print(“AT+CIPSEND=”);
  Serial.print(ch_id);
  Serial.print(“,”);
  Serial.println(Header.length() + Content.length());
  delay(10);

  //if (Serial.find(“>”))
  {
    Serial.print(Header);
    Serial.print(Content);
    Serial.println(“AT+CIPCLOSE=0”);

    delay(10);
  }
}

// Get the data from the WiFi module and send it to the debug serial port
String GetResponse(String AT_Command, int wait) {
  String tmpData;

  Serial.println(AT_Command);
  delay(10);
  while (Serial.available() > 0 )  {
    char c = Serial.read();
    tmpData += c;

    if ( tmpData.indexOf(AT_Command) > -1 )
      tmpData = “”;
    else
      tmpData.trim();

  }
  return tmpData;
}

void clearSerialBuffer(void) {
  while ( Serial.available() > 0 ) {
    Serial.read();
  }
}

void clearBuffer(void) {
  for (int i = 0; i < BUFFER_SIZE; i++ ) {
    buffer[i] = 0;
  }
}

boolean connectWiFi(String NetworkSSID, String NetworkPASS) {
  String cmd = “AT+CWJAP=\””;
  cmd += NetworkSSID;
  cmd += “\”,\””;
  cmd += NetworkPASS;
  cmd += “\””;

  GetResponse(cmd, 10);
}

Advertisements

The ESP8266 WiFi Module–how to get it to work with an Arduino

WP_20160106_15_27_46_Pro_LIFinally got around to playing with the ESP8266 WiFi Module with an Arduino UNO.  I am using the UNO simply because it has a steady, 3.3v output while the HalfByte Console isn’t as steady and the module is, from everything I have read, is not tolerant of much more than the 3.3 volts.  Until I fix the console’s 3.3volt output, I will use the UNO.

Before I go on, I have to say, this little board isn’t very reliable. It is only connecting about a third of the time.

The documentation is spotty, even though it has been out for quite sometime now.  So, I hope to help anyone who just wants to use it as a WiFi module and not reprogram it to play Tic Tac Toe.

First, it is important to know which module you have as there are quite a few variations.  You go here to figure that out. The board I have is an ESP-01 Rev 2.  The Rev is important as you have a couple of extra steps from the rev 1 board.

From the wiki, here’s the pin out for the rev 2 board:

image

In order for this thing to work, you MUST jumper the CHIP_EN (or CHIP_PD) pin to the VCC pin, pulling the pin high.  This enables the whole thing to, you know, work. 

One other important detail…the baud rate is 115,200.  Most documentation I read said it was 9600, but, at least on mine, it is 115,200 baud.

Those two things were the key for me to get my module to connect and work.

Wiring it up is easy:image

ESP8266 ARDUINO
UTX RX (pin 0)
URX TX (pin 1)
GND GND
VCC 3.3V
CHIP_EN 3.3V
RST Reset

The code is straightforward enough. I copied an example from the wiki and modified it to work with my module and took out some extraneous junk.WP_20160106_15_59_14_Pro_LI (2)

Code:

#include <SoftwareSerial.h>
#define SSID        “xxx”
#define PASS        “xxx”
#define DST_IP      “173.194.116.116”    //google.com
SoftwareSerial dbgSerial(10, 11); // RX, TX
void setup() 
{
    // Open serial communications and wait for port to open:
    Serial.begin(115200);
    Serial.setTimeout(5000);
    dbgSerial.begin(9600);  //can’t be faster than 19200 for softserial
    dbgSerial.println(“ESP8266 Demo”);
    //test if the module is ready
    Serial.println(“AT+RST”);
    delay(1000);
    if(Serial.find(“ready”))
    {
        dbgSerial.println(“Module is ready”);
     }
    else
    {
        dbgSerial.println(“Module have no response.”);
        while(1);
     }
    delay(1000);
    //connect to the wifi
    boolean connected=false;
    for(int i=0;i<5;i++)
    {
    if(connectWiFi())
      {
      connected = true;
      break;
      }
    }
    if (!connected){while(1);}
      delay(5000);
      //set the single connection mode
      Serial.println(“AT+CIPMUX=0”);
}
void loop()
{
  String cmd = “AT+CIPSTART=\”TCP\”,\””;
  cmd += DST_IP;
  cmd += “\”,80″;
  Serial.println(cmd);
  dbgSerial.println(cmd);
  if(Serial.find(“Error”)) return;
  cmd = “GET / HTTP/1.0\r\n\r\n”;
  Serial.print(“AT+CIPSEND=”);
  Serial.println(cmd.length());
  if(Serial.find(“>”))
  {
    dbgSerial.print(“>”);
  }else
  {
    Serial.println(“AT+CIPCLOSE”);
    dbgSerial.println(“connect timeout”);
    delay(1000);
    return;
  }
  Serial.print(cmd);
  delay(2000);
  //Serial.find(“+IPD”);
  while (Serial.available())
  {
  char c = Serial.read();
  dbgSerial.write(c);
  if(c==’\r’) dbgSerial.print(‘\n’);
  }
  dbgSerial.println(“====”);
  delay(1000);
}
boolean connectWiFi()
{
  Serial.println(“AT+CWMODE=1”);
  String cmd=”AT+CWJAP=\””;
  cmd+=SSID;
  cmd+=”\”,\””;
  cmd+=PASS;
  cmd+=”\””;
  dbgSerial.println(cmd);
  Serial.println(cmd);
  delay(2000);
  if(Serial.find(“OK”))
  {
    dbgSerial.println(“OK, Connected to WiFi.”);
    return true;
  }else
  {
    dbgSerial.println(“Can not connect to the WiFi.”);
    return false;
  }
}

Because I am using the serial I/O on the UNO for the module, I used softwareserial to talk to a HalfByte Console running the HalfByte graphical terminal sketch so I could see the output of the module.  Normally, you would, likely, not have any kind of output on the Arduino as you’d be using the WiFi module for your I/O. I’m guessing.

I may order a few more of these things to play with reprogramming them and running code directly on them.  There is a Basic Language interpreter, LUA and Javascript for them, so I may play with that.  For now, IF I can get it working reliably, I may pair one with an ATTINY85, like a Trinket or DigiSpark, and a DHT11 temp sensor and set up a network of wireless thermometers in the house. 

I can see the potential, but the reliability is an issue.