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

Hacking the Half-Byte Console and Tiny Basic v2 (or, making Tiny Basic tell me the temperature)

WP_20140826_22_19_55_ProI had one main goal in mind when I designed the Half-Byte Console: to bring together parent and child in a learning experience. Now that the console is a reality and a few are out in the wild, I want it to do other things.  So, I thought ‘what can this do that isn’t expensive and would be easy to add to the Tiny Basic as well?’

Looking around my office, I see a DHT-11 temperature and humidity sensor. Ah ha! These are cheap, just a few dollars each.  They are also easy to access in code and, with only three pins, easy to connect.  So, this is the Half-Byte Console’s first hack: measuring indoor environment.

The DHT-11 has three pins: +5, data and Ground (-).  I chose to use D5 on the console as it is safe to use and won’t interfere with video or the keyboard.  Plus, it is easy to get to on the board. I loaded the example sketch and changed the pin reference to make sure it worked. It did. WP_20140826_22_20_22_Pro

Next, I added support for the sensor to Tiny Basic.  I am working on Version 2 and this support will be part of that release (which should be ready very soon.)

Support comes in the form of two functions:

  • x=Temp(1)
  • x=Humidity (1)

The parameter for Temp actually has meaning: if the parameter is a zero, the temperature is returned as Celsius. If it is a 1, it is returned as Fahrenheit. Any non-zero parameter defaults to Fahrenheit.WP_20140826_22_20_46_Pro

So, now the console can do something useful.  I’m anxious to get the release of Tiny Basic out and see what you all can do with this new functionality.  I am going to post more on the new features of Tiny Basic (hint…more graphics, LIST is fixed…)

In the mean time, if you have any suggestions for Tiny Basic, please let me know in the comments.

It may be small, but this OLED is cute and useful and that little DHT11 really knows when something is hot or not

WP_20140302_013As I stated in a previous post, I have a fetish for displays. Any display. Again, while searching eBay for some parts for my Half-Byte Console project, I found a small, .96 inch OLED display. This little gem uses either SPI, Serial or I2C to interface with your device.  I ordered one and received it a few days ago. As is with most of these cheap parts from China, there was little in the way of documentation or code.  Fortunately, more than one vendor sold them and I found some code, which was good since none of the code I found on the net seemed to work.

This little display is advertised as monochrome, but it really is a two color display.  The top two lines have a yellow background OR yellow foreground and the rest of the screen is blue on black or black on blue.  It was likely out of an old cell phone. To be honest, I’ve not done much research on the history of the screen itself.

Since there are a number of ways to connect the display, which uses the SSD1306, I chose the method in the code that I found:

  1. SCL –>9
  2. SCA –>8

Of course, VCC goes to either 3.3v or 5v and GND to ground.  Once the hardware was connected, I uploaded the code I found. 

The code, found here (but, download it from here, instead), was a simple demonstration and did not come with a very versatile library. Though, it does appear to use the Adafruit GFX library.

Although too small for most of my uses, I wanted to see if it may fit a project I have in mind further down the road. Turns out, it will. So, I then attempted to bang together WP_20140302_016part of that idea using a DHT11 temperature sensor. This sensor also gives the relative humidity. So, I connect the OLED and the DHT11 sensor to an Arduino Mini Pro. The DHT11’s data pin goes to Pin 2 (TX) on the Arduino, and pin 1 goes to 5v and the third pin to GND. I incorporated the DHT code into my OLED demo and then … problems.  Turns out, the OLED library has no built in method to output numerical data.  Remembering my Tiny Basic code, I stole some code from it to output numerical data and…viola! Works like a charm (see photo above.)

At six dollars, the screen isn’t really worth it, as there are better screens out there for the same or even less.  However, if you can these cheaper, they will make great little status displays or even part of a smartwatch or other wearable device.

To use my sample code below, you will need the following libraries installed:

  • SoftwareSerial (should be part of your Arduino installation)
  • IIC_without_ACK.h (use the link above)
  • TinyDHT (download here)
  • avr/power.h (part of your install)

A note about the AdaFruit libraries: While provided free of charge, developing these is not always an easy task (though, it might for Lady Ada) and, as such, you should patronize them whenever you can. They have a great selection and good pricing. I buy quite a bit from them.

The display is also capable of graphical display, but I’ve not yet bothered to try and put an image on the screen. There is a bitmap function in the limited library, but you must convert your image to a C array first.  Take a look at the header file for the OLED font.

have fun!

Sample Code:

#include <SoftwareSerial.h>
#include <IIC_without_ACK.h>
#include “oledfont.c”  

#define OLED_SDA 8
#define OLED_SCL 9

IIC_without_ACK oled(OLED_SDA, OLED_SCL);//9 — sda,10 — scl

/*
* DHT Temperature Sensor
// Connect DHT pin 1 (on the left) of the sensor to +5V
// Connect DHT pin 2 of the sensor to whatever your DHTPIN is
// Connect DHT pin 3 (on the right) of the sensor to GROUND
*/
 
// include the library code

#include <TinyDHT.h>        // lightweight DHT sensor library
#include <avr/power.h>      // needed to up clock to 16 MHz on 5v Trinket
 
// Uncomment whatever type sensor you are using!
#define DHTTYPE DHT11     // DHT 11
//#define DHTTYPE DHT22   // DHT 22  (AM2302)
//#define DHTTYPE DHT21   // DHT 21 (AM2301)
#define TEMPTYPE 1        // Use Fahrenheit (0 for celsius)
#define DHTPIN 1          DHT dht(DHTPIN, DHTTYPE); // Define Temp Sensor
static unsigned char *spt;
/***************************************************************************/
static void pushb(const char b)
{
    spt–;
    *spt = b;
}

/***************************************************************************/
static unsigned char popb()
{
    unsigned char b;
    b = *spt;
    spt++;
    return b;
}

/***************************************************************************/
void printnum(unsigned char x, unsigned char y, int num)
{
        char st[]=”   “;
    int digits=0;
        int pos=0;
       
    if(num < 0)
    {
        num = -num;
        oled.Char_F6x8(x,y,”-“);
    }

    do {
        pushb(num%10+’0′);
        num = num/10;
        digits++;
    }
    while (num > 0);
        while(digits > 0)
          {
                  st[pos]=popb();
                  x++;
            digits–;
                  pos++;
          }
         oled.Char_F6x8(x,y, st);
}
 
void setup() { 
  dht.begin();  // Initialize DHT Teperature Sensor
  oled.Initial();
}
 
void loop() {
  int8_t h = dht.readHumidity();               // Read humidity
  int16_t t = dht.readTemperature(TEMPTYPE);   // read temperature
 
  delay(2000);
  oled.Fill_Screen(0x00);
 
  if ( t == BAD_TEMP || h == BAD_HUM ) { // if error conditions (see TinyDHT.h)
    oled.Char_F6x8(0,0,”Bad Read on DHT”); //   print error message
  } else {
    oled.Char_F6x8(0,2,”Humidity:”);
    printnum(60,2,h);
    oled.Char_F6x8(78,2,”%”);
    oled.Char_F6x8(0,4,”Temp: “);
    printnum(36,4,t);
    oled.Char_F6x8(50,8,”F”);    
  }
  delay(2000);  // Read temp every second (2000 ms) (DHT sensor max rate)
}