E-Ink Display driven by Arduino

Recently I discovered an 4,3 “ E-Ink display (Waveshare 4,3″inch e-Paper 800×600) that can be used with an Arduino. E-Ink displays (or E-Paper) are low-energy displays that keep what was printed even when the power is turned off. This feature makes E-Ink displays not only perfect for E-Readers, but also interesting for IoT projects. Such a display could show information that does not require animations (E-Ink displays take their time to update).
For IoT projects I can immediately think of examples such as displaying weather data (and the time), daily appointments from an electronic calendar, cooking recipes… .

Hardware

Waveshare 4,3″inch e-Paper 800×600
Arduino (Uno)
some cables

Wiring

e-Ink Display Arduino
VCC 5V
GND GND
DOUT RX
DIN TX
WAKE_UP D2
RST A3

Software

In this post I discovered the epd library for usage in Arduino sketches. Originally this library was found here and repackaged. This library can be directly imported into the Arduino IDE.

Arduino Sketch

This sketch is based on the example from here. It was immediateley working with little changes only.
To upload the sketch the RX/TX lines have to be removed from the Arduino. If the RX/TX lines are put back the Arduino can be reset to refresh the display.

#include <epd.h>

void fillPage(void) {
  char buff[] = {'G', 'B', 'K', '3', '2', ':', ' ', 0xc4, 0xe3, 0xba, 0xc3, 0xca, 0xc0, 0xbd, 0xe7, 0};

  epd_set_color(BLACK, WHITE);  // text=black, background=white
 
  epd_clear();

  // setting the font type and size
  epd_set_ch_font(GBK32);
  epd_set_en_font(ASCII32);

  epd_disp_string(buff, 0, 0);
  epd_disp_string("Test of the length of characters that can be printed in a line #1", 0, 0);
  epd_disp_string("Test of the length of characters that can be printed in a line #2", 0, 50);
  epd_disp_string("Test of the length of characters that can be printed in a line #3", 0, 100);
  
  // increasing the font type and size
  epd_set_ch_font(GBK48);
  epd_set_en_font(ASCII48);

  buff[3] = '4';
  buff[4] = '8';

  // print larger text
  epd_disp_string(buff, -10, -10);
  epd_disp_string("thisisyetanotherblog.wordpress.com", 25, 200);

  epd_set_ch_font(GBK64);
  epd_set_en_font(ASCII64);

  buff[3] = '6';
  buff[4] = '4';

  // drawing some forms
  epd_draw_circle(80, 350, 55);
  epd_draw_triangle(100, 450, 170, 400, 250, 450);
  epd_fill_rect(400, 500, 335, 470);
  epd_draw_line(100, 550, 700, 550);
 
  // update the display
  epd_udpate();
}

void setup(void) {
 // initialize the display
 epd_init();
 epd_wakeup();
 epd_set_memory(MEM_NAND);
}

void loop(void) {
 fillPage(); // fill the display once
 while (1) {} // do nothing more in the loop
}

Result

This is a base to start from with the next IoT project… Hopefully E-Ink displays become more affordable sooner than later!

e-ink display test, powered off

Sources

http://www.waveshare.com/4.3inch-e-paper.htm
http://www.waveshare.com/wiki/4.3inch_e-Paper

http://www.jarzebski.pl/arduino/komponenty/e-papier-waveshare-4-3.html
http://www.zoobab.com/waveshare-e-paper-and-arduino
http://zoobab.wdfiles.com/local–files/waveshare-e-paper-and-arduino/ArduinoEpd.zip

Advertisements

IoT: Collecting Weather Data

Collecting data from temperature, humidity and barometric sensors with an
Arduino is compelling when observing the weather. The idea is to create an outdoor sensor module. This outdoor module sends the measured data via WiFi to a server which stores the measurement data in a local database.

Components used

ESP-ADC DIL 18 with ESP8266 module
BMP085 Barometric Pressure & Temp Sensor
DHT22 Temperature and Humidity Sensor
220 uF 16V capacitor
Single color LED
220; 4,7k, 10k resistors
wires, switches, breadboard, breadboard power supply, 3,3 V FTDI programmer

Make it happen

Wiring

wiring of esp8266, dht22, bmp085

 

ESP8266 Parts Notes
GND GND DHT22 / GND BMP085 / GND ESP-ADC / LED – via 220 resistor
VCC 3,3 V VCC DHT22 / VCC BMP085 / VCC ESP8266
Reset switch 1 / GPIO_16 Connection to GPIO_16 required for deep sleep mode of ESP8266
GPIO_0 switch 2
GPIO_4 SDA BMP085 On ESP8266 I2C is implemented in software, could be soft-wired to any other GPIO, default for I2C clock is GPIO_4
GPIO_5 SDL BMP085 On ESP8266 I2C is implemented in software, could be soft-wired to any other GPIO, default for I2C data is GPIO_5
GPIO_7 Pin 2 DHT22, pull to 3,3 V VCC via 4,7 k resistor
GPIO_13 LED +
GPIO_16 RST ESP8266
CHPD 3,3 V VCC via 10k resistor

The capacitor is used to stabilize the electric power supply for the two sensors and the ESP8266. This is especially useful when the ESP8266 sets up a WiFi connection and its power consumption increases.

Uploading an Arduino Sketch to the ESP8266

Wiring

  • Adjust the FTDI programmer for 3,3 V logic
  • Connect the FTDI programmer’s RX and TX lines to the ESP8266.
  • Connect the FTDI programmer’s GND line to GND of the breadboard power supply.

Arduino IDE settings

Adjust the upload settings in the Arduino IDE:

Arduino IDE upload settings

Uploading

To upload an Arduino sketch to the ESP8266 module push the two buttons. Release the switch connected to Reset approx. a second before the switch connected to GPIO_0 and trigger the upload in the Arduino IDE. The timing is relevant. It may happen that this procedure has to be repeated several times until the upload succeeds.

After the successful upload of the sketch the output in the Arduino IDE looks similar to this:

...
upload message on success:
setting serial port timeouts to 1000 ms
 espcomm_send_command: receiving 2 bytes of data
 writing flash
............................................................................................................................................................................................................................
starting app without reboot
 espcomm_send_command: sending command header
 espcomm_send_command: sending command payload
 espcomm_send_command: receiving 2 bytes of data
closing bootloader
 flush start
 setting serial port timeouts to 1 ms
 setting serial port timeouts to 1000 ms
 flush complete

Sketch

Installing Adafruit Libraries

The Arduino sketch based on the examples for the unified BMP085 and DHT libraries.
The required libraries for Adafruid BMP085 Unified, Sensor and DHT Unified can be installed for the Arduino IDE via Sketch > Libraries > Manage Libraries… .

Some Code

#include <ESP8266WiFi.h> // http://esp8266.github.io/Arduino/versions/2.0.0/doc/libraries.html
#include <WiFiClient.h>

#include <Adafruit_Sensor.h>
#include <Adafruit_BMP085_U.h> // https://github.com/adafruit/Adafruit_BMP085_Unified

#include <DHT.h>
#include <DHT_U.h> // https://github.com/adafruit/Adafruit_DHT_Unified
#define DHTTYPE DHT22
#define DHTPIN 7

// WiFi network credentials
const char* ssid = "<SSID>";
const char* password = "<PASSWD>";

// IP / port weather station server
#define IPWS "192.168.145.244"
#define PORT 20016

// times for deep sleep mode
unsigned long MIN_1 = 60000000;
unsigned long MIN_15 = 900000000;
unsigned long MIN_30 = 1800000000;
unsigned long S_30 = 30000000;
unsigned long DEEP_SLEEP = MIN_30;
RFMode MODE = WAKE_RF_DEFAULT;

// Initialize DHT sensor 
// NOTE: For working with a faster than ATmega328p 16 MHz Arduino chip, like an ESP8266,
// you need to increase the threshold for cycle counts considered a 1 or 0.
// You can do this by passing a 3rd parameter for this threshold. It's a bit
// of fiddling to find the right value, but in general the faster the CPU the
// higher the value. The default for a 16mhz AVR is a value of 6. For an
// Arduino Due that runs at 84mhz a value of 30 works.
// This is for the ESP8266 processor on ESP-01 
DHT_Unified dht(DHTPIN, DHTTYPE, 11); // 11 works fine for ESP8266

Adafruit_BMP085_Unified bmp;

#define STATUSLED 13

boolean debugging = false; // enable / disable debug output

String float2String(float value) {
  char v[10];
  dtostrf(value,4,1,v);
  return String(v);
}

String readSensors() {
  if( debugging ) Serial.println("Read sensor data...");
  String str = "";
  String str2Send = "wData;";

  if( debugging ) Serial.println("DHT22");
  sensors_event_t event;
  float temperature = 0.0;
  dht.temperature().getEvent(&event);
  temperature = event.temperature;
  if( isnan(temperature) ) {
    if( debugging ) Serial.println("Error reading temperature!");
  } else {
    if( debugging ) {
      Serial.print("Temperature: ");
      Serial.print(temperature);
      Serial.println(" *C");
    }
 }
 // Get humidity event and print its value.
 dht.humidity().getEvent(&event);
 float humidity = 0.0;
 humidity = event.relative_humidity;
 if( isnan(humidity) ) {
   if( debugging ) Serial.println("Error reading humidity!");
 } else {
   if( debugging ) {
     Serial.print("Humidity: ");
     Serial.print(humidity);
     Serial.println("%");
   }
 }

 float temperature2 = 0.0;
 bmp.getTemperature(&temperature2);
 str = "Temperature: " + float2String(temperature2) + " *C\n";
 str += "Humidity: " + float2String(humidity) +" %\n";

 float pressure = 0.0;
 bmp.getPressure(&pressure);
 pressure = pressure/100.0;
 if( debugging ) {
   Serial.print("Pressure: ");
   Serial.print(pressure);
   Serial.println(" hPa");
 }
 str += "Pressure: " + float2String(pressure) + " hPa\n";

 if( debugging ) {
   Serial.print("Collected sensor data: ");
   Serial.println(str);
 } 
 str2Send += temperature;
 str2Send += ";";
 str2Send += humidity;
 str2Send += ";";
 str2Send += pressure;
 str2Send += "\0";

 if( debugging ) {
   Serial.print("Sensor data for sending to server: ");
   Serial.println(str2Send);
 }
 return str2Send;
}

// expected string: e.g. weatherdata;14.3;60.7;1018.0
void sendSensorData(String str2Send) {
 WiFiClient client;
 client.connect(IPWS, PORT);
 if( debugging ) {
   Serial.print("Sending: ");
   Serial.println(str2Send);
 }
 client.write(str2Send.c_str(), str2Send.length());
 if( client.connected() ) {
   client.stop();
 }
}

void setup(void) {
 // You can open the Arduino IDE Serial Monitor window to see what the code is doing
 Serial.begin(115200); // Serial connection from ESP-01 via 3.3v console cable

 dht.begin(); // initialize temperature sensor

 if (!bmp.begin()) {
   if( debugging ) Serial.println("Could not find a valid BMP085 sensor, check wiring!");
   while (1) {}
 }
 
 // set as station
 WiFi.mode(WIFI_STA);
 
 // connect to WiFi network
 WiFi.begin(ssid, password);
 if( debugging ) Serial.print("\n\r \n\rWorking to connect");

 // wait for connection
 while (WiFi.status() != WL_CONNECTED) {
   delay(500);
   if( debugging ) Serial.print(".");
 }

 pinMode(STATUSLED, OUTPUT);
 digitalWrite(STATUSLED, LOW);
} // setup()

void loop(void) {

 // read data from sensors
 String str = readSensors();

 if( debugging ) {
   Serial.print("Sending sensor data to server: ");
   Serial.println(str);
 }
 sendSensorData(str);

 // indicate data acquisition and sending
 digitalWrite(STATUSLED, HIGH);
 delay(1000);

 // enter deep sleep mode for x minutes
 // GPIO16 needs to be tied to RST to wake ESP8266 from deep sleep mode
 // http://russ.russmathis.com/esp8266-power-modes/
 //ESP.deepSleep(DEEP_SLEEP, MODE);
 // 30000000 ms = 30 s
 ESP.deepSleep(MIN_30, WAKE_RF_DEFAULT);
} 

Output

In debug mode the output on the serial console is similar to this:

Working to connect….
Read sensor data…
DHT22
Temperature: 22.10 *C
Humidity: 53.60%
BMP085
Temperature: 22.10 *C
Pressure: 1009.2 hPa
Collected sensor data:
Temperature: 22.10 *C
Humidity: 53.60%
Pressure: 1009.2 hPa
Sending sensor data to server: …

Notes

After measurement the ESP8266 establishes a WiFi connection. The collected data is sent as a string to a dedicated server of the desired IP within the local network.
Another possibility would be to send the data to thingspeak.com for quick visualization.

Deep sleep – saving power

After having sent the measurement data the ESP8266 enters „deep sleep“ mode until it is woken up again after the desired time. For this feature GPIO_16 has to be wired with Reset on the ESP8266.

Configuration

The ESP8266 module should be configured as a a station, not as an accesspoint (WIFI_AP). In this setup the module is used for sending data only.

Barometric sensor

Usually the barometric pressure is the ‚raw‘ value. It is calculated to match the barometric pressure at sea level. Depending on the actual level the measured value differs from the barometric values close to the location. In this case the measured barometric pressure needs to be adapted.

Temperature sensor data

Small deviations of the measured temperature are possible between the two sensors. The causes for such deviations are usually production tolerances of the sensor’s chips or even a close local heat source.

ESP8266 vs. Arduino

The inexpensive ESP8266 module looks promising for realizing own IoT projects.
However there are a couple of stumbling blocks to be found when trying to integrate this module. These are the ones I found when I tried to connect an Arduino Pro Mini (3,3 V) to the local WiFi network with this module.

Stumbling block #1

During development the ESP8266 module requires its own 3.3 V (!) power supply. The power consumption increases when a WiFi connection is established. Powering the ESP8266 module via FTDI/USB is not sufficient as soon as WiFi connections are planned.

 

ESP8266 on FTDI programmer

Stumbling block #2

To check whether the ESP8266 is flashed with firmware and understands AT commands first connect it directly to an FTDI programmer:

FTDI programmer
GND GND 3.3V power supply
VCC not connected
RX TX ESP8266
TX RX ESP8266
DTR  not connected
RST  not connected
ESP8266 module
GND GND 3.3V power supply
VCC VCC 3.3V power supply
RX TX FTDI
TX RX FTDI
CHPD VCC 3.3V power supply via 10k resistor
REST VCC 3.3V power supply via 10k resistor

esp8266onftdi_breadboard

With a terminal (e.g. from the Arduino IDE) it is now possible to send AT commands to the ESP8266. A comprehensive description of the AT command set for ESP8266 modules is found on  http://www.esp8266.com/wiki/doku.php?id=at_commands .

Stumbling block #3

New line and carriage return must be set in the terminal and the proper baud rate (115200) must be selected.

Basic AT commands

command expected result description
AT OK Test whether AT commands will work
AT+GMR e.g. AT version:0.60.0.0(Jan 29 2016 15:10:17)
SDK veróion:1.5.2(80914727)
compile time:Jan 29 2016 19:06:34
OK
Print version information
AT+RST OK Reset ESP8266 module
AT+RESTORE OK Configuration will be reset to factory defaults.
AT+CWLAP list of WIFI local networks Available WIFI access points will be displayed.
AT+CWJAP=“<SSID>“,“<WIFIpassword>“ WIFI CONNECTED
WIFI GOT IP
OK
Connects to the WIFI network with SSID + WIFIpassword
AT+CWDHCP_DEF=1,1 OK Enable DHCP, set ESP8266 as station
AT+PING=“<IPv4address>“ ping response Pings an IP address

Stumbling block #4

If the module appears to have no firmware it is necessary to flash the firmware.

ESP8266 on Arduino

An Arduino can be used to program the ESP8266. Assuming that this simple Arduino sketch was uploaded to the Arduino first:

#define SSID "<SSID>"
#define PASS "<WIFIpassword>"
#define IP "<IPv4adress>"

void setup() { 
  Serial.begin(115200);  // set baud rate
  
  Serial.println("AT");
  delay(5000);
  if( Serial.find("OK") ){
    connectToWiFi();
  }
}

void loop(){
  // generate some traffic
  ping();
  delay(10000);
}

void connectToWiFi(){
  // enable DHCP and set ESP8266 as station
  Serial.println("AT+CWDHCP_CUR=1,1");
  delay(2000);
  // connect to the WIFI network
  String cmd="AT+CWJAP=\"";
  cmd+=SSID;
  cmd+="\",\"";
  cmd+=PASS;
  cmd+="\"";
  Serial.println(cmd);
}

void ping() {
    String cmd="AT+PING=\"";
    cmd += IP;
    cmd += "\"";
    Serial.println(cmd);
}

The program sets up a WiFi connection to the desired network and generates some network traffic using ping. The network traffic can be observed using tcpdump (Linux) for example.

Stumbling block #5/6

ESP8266 must be powered off and RX/TX lines must be connected to the Arduino everytime the sketch is uploaded. 😉

Stumbling block #7

Once the Arduino is generating the AT commands for the ESP8266 the setup has to be slightly changed:

Arduino Pro Mini, 3,3 V
GND in GND 5 V power supply
VCC in VCC 5 V power supply
RX TX ESP8266
TX RX ESP8266
DTR not connected
RST not connected
ESP8266 module
GND GND 3.3V power supply
VCC VCC 3.3V power supply
RX TX Arduino
TX RX Arduino
CHPD VCC 3.3V power supply via 10k resistor
REST VCC 3.3V power supply via 10k resistor

esp8266onarduino_breadboard

Now the Arduino should be able to connect to the local WiFi network and should ping the desired IP every couple of seconds.