LILYGO® T5-4.7 inch E-Paper Display with ESP32 (16MB-Flash/8MB-PSRAM)
This module contains a 4.7-inch E-Paper Display with an onboard ESP32 SoC. This makes our development convenient and clutter-free.
Also, it has got an onboard Li-ion battery charging circuit which makes it easy to use with an onboard battery.
The module kit also comes with a battery connector and a USB-A to Type C cable.
To keep the clock running after we unplug it from our PC, I have used a 3.7 V rechargeable battery connected to the LILYGO module, using the connector provided.
Step-2: IntroductionWhat you will learn:
- Set up the environment to work with E-Paper Display and ESP32
- Show text on the E-Paper Display
- Convert a JPG Image to Bitmap using Python
- Show a bitmap image on the E-Paper display
- Show time & date (fetched from NTP server) on the display
- Show weather information (fetched from OpenWeatherMap API) on the display
- Set Do not Disturb (DND) mode using Google Assistant on your phone
- Combine all of the above to make a functional Smart Clock
I assume that you are familiar with the IoT basics and have played around with ESP development boards before. If not, I would suggest you go over the articles/videos on "IoT fundamentals" and "getting started with ESP32".
E-Paper Display
This is a type of monochrome display that looks like paper and does not require any backlight to display anything on it.
The cool thing about the E-Paper display is, it does not require any power to keep the displayed content on the screen. You need to power it only when you want to change its content.
Considering this project, we will be using an E-Paper display library that does all the hard work for us. We will just understand how to call the functions to show whatever we want on the display.
Pre-requisites
- Familiar with Arduino IDE
- Worked with any of the ESP development boards
- Basics knowledge of C/C++ programming
I assume that you have already worked with Arduino IDE and have it installed on your computer. If not, you can download it from here.
You will need the ESP32 boards to be installed on Arduino IDE. You can follow the steps here to get them installed.
Once the boards are installed, you will need to select the appropriate board for this project. Navigate to Tools -> Boards: "....." -> ESP32 Arduino and select the first option in the list, i.e. "ESP32 Dev Module"
Once you have selected the board, you will need to change the following parameters as per the module:
- Upload speed: "921600"
- Flash Size: "16MB (128Mb)"
- PSRAM: "Enabled"
Leave the rest of the parameters set to default values.
To work with E-Paper Display, you will need an E-Paper display library. The manufacturer has provided the library in the GitHub link here. You can download the zip file by navigating to Code -> Download Zip as shown in the image below.
Once downloaded, you can use the instruction here to install the library on your Arduino IDE.
Now, you are all set to connect the module to your computer. Plug the module into the computer's USB port using the USB cable provided. Once connected, you should be able to see the Port enabled in the Tools.
Note: If you are not able to see the Port, your computer might not have the required driver. You can download the driver from here and install it on your computer.Step-4: Show text on the E-paper display
We will write a simple phrase on the display. To get this done, open Arduino IDE and create a new file. Save the newly created file in an appropriate location.
Now, to display the text, you will need to add the font header first. Get the opensans18b.h file from here and add it to the same folder where your code resides. Reopen the Arduino file and you should see the font header file added as another tab on the Arduino IDE.
Next, copy the below code and paste it into the Arduino IDE editor.
// Check if the PSRAM is available and enabled
#ifndef BOARD_HAS_PSRAM
#error "Please enable PSRAM !!!"
#endif
#include "epd_driver.h"
#include "opensans18b.h"
uint8_t *framebuffer;
void setup()
{
Serial.begin(115200);
EPD_setup();
displayMessage();
epd_poweroff();
}
void loop()
{
// Do nothing in the loop
}
/*********************************************************************
Function to set buffer memory and initialize E-Paper Display
********************************************************************/
void EPD_setup() {
epd_init(); // Initialize the e-paper display
// Set framebuffer size
framebuffer = (uint8_t *)ps_calloc(sizeof(uint8_t), EPD_WIDTH * EPD_HEIGHT / 2);
// Check if the buffer memory is allocted successfully
if (!framebuffer) {
Serial.println("alloc memory failed !!!");
while (1);
}
memset(framebuffer, 0xFF, EPD_WIDTH * EPD_HEIGHT / 2); // Fill the buffer with white pixels
epd_poweron(); // Turn the E-Paper display on
epd_clear(); // clear the content on the display
}
/*********************************************************************
Function to show the text on Display
*********************************************************************/
void displayMessage() {
// Define the cursor variable and default location
int cursor_x = 0;
int cursor_y = 0;
// Define the text to be displayed
char *txt1 = "Welcome\n";
char *txt2 = "to\n";
char *txt3 = "Silken Automation\n";
// Display text on the E-Paper Display
cursor_x = 398;
cursor_y = 160;
writeln((GFXfont *)&OpenSans18B, txt1, &cursor_x, &cursor_y, NULL);
vTaskDelay(100);
cursor_x = 460;
cursor_y += 50;
writeln((GFXfont *)&OpenSans18B, txt2, &cursor_x, &cursor_y, NULL);
vTaskDelay(100);
cursor_x = 300;
cursor_y += 50;
writeln((GFXfont *)&OpenSans18B, txt3, &cursor_x, &cursor_y, NULL);
vTaskDelay(100);
}
In the above code:
- First, we are initializing the buffer to be used for loading the display content
- Then, we are setting the text that we want to display
- At last, we are bringing the cursor to the required location and printing the text on the display
Compile and upload the above code in your module and you should see the result below.
To display any image on the E-Paper display, we first need to convert that to a bitmap, and then to a header file that we can directly include in our Arduino code.
We will use a Python script that will take a JPEG/PNG image and give out a header file which you can put in your Arduino code folder.
Note: To run a Python script, you will require Python to be installed on your computer. If you do not have it installed, you can download and install it from here.
Next, copy the below code and paste it into any text editor. I have used notepad++, but you can use any other as per your preference.
#!python3
# Import the necessary packages
from PIL import Image, ImageOps
from argparse import ArgumentParser
import sys
import math
# Set the width and height of the display
SCREEN_WIDTH = 1200
SCREEN_HEIGHT = 825
if SCREEN_WIDTH % 2:
print("image width must be even!", file=sys.stderr)
sys.exit(1)
# Argument parser to pass the image, file name, and variable name in the output header file
parser = ArgumentParser()
parser.add_argument('-i', action="store", dest="inputfile")
parser.add_argument('-n', action="store", dest="name")
parser.add_argument('-o', action="store", dest="outputfile")
args = parser.parse_args()
im = Image.open(args.inputfile)
# convert to grayscale
im = im.convert(mode='L')
im.thumbnail((SCREEN_WIDTH, SCREEN_HEIGHT), Image.ANTIALIAS)
# Write out the output file.
with open(args.outputfile, 'w') as f:
f.write("const uint32_t {}_width = {};\n".format(args.name, im.size[0]))
f.write("const uint32_t {}_height = {};\n".format(args.name, im.size[1]))
f.write("const uint8_t {}_data[({}*{})/2] = {{\n".format(args.name, math.ceil(im.size[0] / 2) * 2, im.size[1])
)
for y in range(0, im.size[1]):
byte = 0
done = True
for x in range(0, im.size[0]):
l = im.getpixel((x, y))
if x % 2 == 0:
byte = l >> 4
done = False;
else:
byte |= l & 0xF0
f.write("0x{:02X}, ".format(byte))
done = True
if not done:
f.write("0x{:02X}, ".format(byte))
f.write("\n\t");
f.write("};\n")
Save the above file with the.py extension. For example; "converter.py"
Now, to run the above script, we will use a terminal tool. I am a Windows user, so I used the command prompt. You can use any terminal tool as per your OS.
Open the command prompt and navigate to the Python script location.
Also, we need to bring the image file that we need to convert, to the same folder where the Python code is located.
Now, run the following command on the command prompt to generate the header file that you will need to show the image on the E-Paper display:
python converter.py -i image.PNG -n image -o image.h
After successfully executing the above command, you should be able to see a new file "image.h" added to the same folder.
Note: In case you get the "ModuleNotFoundError: No module named 'PIL''" error, you can run the following command to install the package:
pip install Pillow
Voilà! we have the image file in the form of a header file. We will use this in the next step to show the image on the E-Paper display.
Step-6: Show the image on the E-Paper displayIt's time to get our image on the E-Paper display.
Create a new Arduino file and save it in a location of your preference. Now, copy the "image.h" file inside the newly created Arduino code folder and reopen the Arduino file. You should see the "image.h" file added as another tab in the Arduino IDE.
Copy and paste the below code into your Arduino editor.
// Check if the PSRAM is available and enabled
#ifndef BOARD_HAS_PSRAM
#error "Please enable PSRAM !!!"
#endif
#include "epd_driver.h"
#include "opensans18b.h"
#include "image.h"
uint8_t *framebuffer;
void setup()
{
Serial.begin(115200);
EPD_setup();
displayImage();
epd_poweroff();
}
void loop()
{
// Do nothing in the loop
}
/*********************************************************************
Function to set buffer memory and initialize E-Paper Display
********************************************************************/
void EPD_setup() {
epd_init(); // Initialize the e-paper display
// Set framebuffer size
framebuffer = (uint8_t *)ps_calloc(sizeof(uint8_t), EPD_WIDTH * EPD_HEIGHT / 2);
// Check if the buffer memory is allocted successfully
if (!framebuffer) {
Serial.println("alloc memory failed !!!");
while (1);
}
memset(framebuffer, 0xFF, EPD_WIDTH * EPD_HEIGHT / 2); // Fill the buffer with white pixels
epd_poweron(); // Turn the E-Paper display on
epd_clear(); // clear the content on the display
}
/*********************************************************************
Function to show the the image on E-Paper display
*********************************************************************/
void displayImage() {
// Set the position and area of the image
Rect_t area = {
.x = 100,
.y = 200,
.width = image_width,
.height = image_height,
};
epd_draw_grayscale_image(area, (uint8_t *)image_data); //Draw image on display
Delay(100);
}
In the above code:
- First, we defined the position of the image and the area it will occupy
- Then, we loaded the image data on the buffer memory to display it on the E-Paper display
Compile and upload the above code onto the module.
If things go well, you should see the below image on the E-Paper display:
To show the time and date, first, we will need to get the actual time and date data. To get this task done, we will follow the below steps:
- Connect to a WiFi network
- Get time and date data from the cloud using NTP server API
- Modify the date and time into an "E-Paper display library" acceptable format
- Show the date and time on the E-Paper display
The below code has functions to get all the above steps done. Copy and paste this on your Arduino file.
// Check if the PSRAM is available and enabled
#ifndef BOARD_HAS_PSRAM
#error "Please enable PSRAM !!!"
#endif
// Include required libraries
#include "epd_driver.h"
#include <WiFi.h>
#include "time.h"
// Include the font header file
#include "opensans24b.h"
// Declare required variables
uint8_t *framebuffer;
String Time_str = "--:--:--";
String Date_str = "-- --- ----";
enum alignment {LEFT, RIGHT, CENTER};
void setup()
{
Serial.begin(115200);
wifiSetup();
EPD_setup();
displayDateTime();
epd_poweroff();
}
void loop()
{
// Do nothing in the loop
}
/*********************************************************************
Function for Wifi setup
********************************************************************/
void wifiSetup() {
const char* ssid = "Your WiFi name";
const char* password = "Your WiFi Password";
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
}
/*********************************************************************
Function to set buffer memory and initialize E-Paper Display
********************************************************************/
void EPD_setup() {
epd_init(); // Initialize the e-paper display
// Set framebuffer size
framebuffer = (uint8_t *)ps_calloc(sizeof(uint8_t), EPD_WIDTH * EPD_HEIGHT / 2);
// Check if the buffer memory is allocted successfully
if (!framebuffer) {
Serial.println("alloc memory failed !!!");
while (1);
}
memset(framebuffer, 0xFF, EPD_WIDTH * EPD_HEIGHT / 2); // Fill the buffer with white pixels
epd_poweron(); // Turn the E-Paper display on
epd_clear(); // clear the content on the display
}
/*********************************************************************
Function to get the time/date data and store it in a global variable
********************************************************************/
boolean getLocalTime()
{
struct tm timeinfo;
char time_output[30], day_output[30], update_time[30];
const char* ntpServer = "pool.ntp.org";
const long gmtOffset_sec = 19800; //Offset for IST
const int daylightOffset_sec = 0; //No Day-Light saving
// init and get the time
configTime(gmtOffset_sec, daylightOffset_sec, ntpServer);
if (!getLocalTime(&timeinfo)) {
Serial.println("Failed to obtain time");
}
Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");
// int CurrentHour = timeinfo.tm_hour;
// int CurrentMin = timeinfo.tm_min;
// int CurrentSec = timeinfo.tm_sec;
strftime(day_output, sizeof(day_output), "%a %b-%d-%Y", &timeinfo); // Creates 'Sat May-31-2019'
strftime(update_time, sizeof(update_time), "%r", &timeinfo); // Creates: '@ 02:05:49pm'
sprintf(time_output, "%s", update_time);
Date_str = day_output;
Time_str = time_output;
return true;
}
/*********************************************************************
Function to show the the date and time on E-Paper display
*********************************************************************/
void displayDateTime() {
getLocalTime();
drawString(200, 150, Date_str, LEFT);
drawString(200, 250, Time_str, LEFT);
}
/*********************************************************************
Function to convert string to an array of charecters and
set the alignment of text
********************************************************************/
void drawString(int x, int y, String text, alignment align) {
char * data = const_cast<char*>(text.c_str());
int x1, y1; //the bounds of x,y and w and h of the variable 'text' in pixels.
int w, h;
int xx = x, yy = y;
get_text_bounds((GFXfont *)&OpenSans24B, data, &xx, &yy, &x1, &y1, &w, &h, NULL);
if (align == RIGHT) x = x - w;
if (align == CENTER) x = x - w / 2;
int cursor_y = y + h;
writeln((GFXfont *)&OpenSans24B, data, &x, &cursor_y, NULL);
}
You
would have noticed, I have used OpenSans24B font here to show the time and date on the display. You can get the font file from here and add it to your code using the method mentioned in Step-4.
Also, don't forget to change the WiFi credentials with yours.
Note: The above code has been well commented on to explain what is happening at every step. However, feel free to ask any doubts in the comments section.
Compile and upload the code into your module. If everything was done correctly, you should see the below on your display.
To display weather information of your location, you will need to follow the below steps:
- Get the OpenWeatherMap API Key from https://openweathermap.org/
- Fetch the weather data using API
- Extract the weather info from the API response
- Display weather data on E-Paper display
To start with, first, create an account at https://home.openweathermap.org/users/sign_in
Log in and go to the "My API Keys" page
Copy the API Key and save it somewhere safe
The rest of the steps have been followed in the below code. Copy the code into an Arduino file.
// Check if the PSRAM is available and enabled
#ifndef BOARD_HAS_PSRAM
#error "Please enable PSRAM !!!"
#endif
// Include the required libraries
#include "epd_driver.h"
#include <WiFi.h>
#include <HTTPClient.h>
#include <ArduinoJson.h> // https://github.com/bblanchon/ArduinoJson
// Include the font header
#include "opensans24b.h"
// set location and API key
String Location = "Your Location";
String API_Key = "2e98d6d804cccc57c78dc6c8bxxxxxxx"; // Your openweathermap API Key
// Declare the required global variables
uint8_t *framebuffer;
float main_temp = 0;
float main_pressure = 0;
int main_humidity = 0;
enum alignment {LEFT, RIGHT, CENTER}; // Creates a new data type (alignment) for the text alignement
void setup()
{
Serial.begin(115200);
delay(200);
wifiSetup();
delay(100);
EPD_setup();
delay(100);
displayWeather();
epd_poweroff();
}
void loop()
{
// Do nothing in the loop
}
/*********************************************************************
Function for Wifi setup
********************************************************************/
void wifiSetup() {
const char* ssid = "Your WiFi Name";
const char* password = "Your WiFi Password";
Serial.printf("Connecting to %s ", ssid);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
}
/*********************************************************************
Function to set buffer memory and initialize E-Paper Display
********************************************************************/
void EPD_setup() {
epd_init(); // Initialize the e-paper display
// Set framebuffer size and allocate memory for the same
framebuffer = (uint8_t *)ps_calloc(sizeof(uint8_t), EPD_WIDTH * EPD_HEIGHT / 2);
// Check if the buffer memory is allocted successfully
if (!framebuffer) {
Serial.println("alloc memory failed !!!");
while (1);
}
memset(framebuffer, 0xFF, EPD_WIDTH * EPD_HEIGHT / 2); // Fill the buffer with white pixels
epd_poweron(); // Turn the E-Paper display on
epd_clear(); // clear the content on the display
}
/*********************************************************************
Function to show the the image on E-Paper display
*********************************************************************/
void displayWeather() {
getWeatherData();
// Define the cursor variable and default location
int cursor_x = 0;
int cursor_y = 0;
String temp = "Temperature : " + String((main_temp - 273.15)) + " °C";
String hum = "Humidity : " + String(main_humidity) + " %";
String pres = "Pressure : " + String(main_pressure) + " hPa";
// Display text on the E-Paper Display
cursor_x = 200;
cursor_y = 100;
drawString((GFXfont *)&OpenSans24B, cursor_x, cursor_y, temp, LEFT);
cursor_x = 200;
cursor_y += 100;
drawString((GFXfont *)&OpenSans24B, cursor_x, cursor_y, hum, LEFT);
cursor_x = 200;
cursor_y += 100;
drawString((GFXfont *)&OpenSans24B, cursor_x, cursor_y, pres, LEFT);
}
/*********************************************************************
Function to get the weather data
********************************************************************/
void getWeatherData() {
if (WiFi.status() == WL_CONNECTED) {
WiFiClient client;
HTTPClient http;
String payload;
// specify request destination
Serial.print("[HTTP] begin...\n");
if (http.begin(client, "http://api.openweathermap.org/data/2.5/weather?q=" + Location + "&APPID=" + API_Key)) // HTTP
{
Serial.print("[HTTP] GET...\n");
// start connection and send HTTP header
int httpCode = http.GET();
// httpCode will be negative on error
if (httpCode > 0) // check the returning code
{
// HTTP header has been send and Server response header has been handled
Serial.printf("[HTTP] GET... code: %d\n", httpCode);
// file found at server
if (httpCode == HTTP_CODE_OK || httpCode == HTTP_CODE_MOVED_PERMANENTLY)
{
payload = http.getString();
Serial.println(payload);
}
}
else
{
Serial.printf("[HTTP] GET... failed, error: %s\n",
http.errorToString(httpCode).c_str());
return;
}
StaticJsonDocument<1024> doc;
DeserializationError error = deserializeJson(doc, payload);
if (error)
{
Serial.print(F("deserializeJson() failed: "));
Serial.println(error.f_str());
return;
}
JsonObject main = doc["main"];
main_temp = main["temp"]; // 301.45
main_pressure = main["pressure"]; // 1004
main_humidity = main["humidity"]; // 62
// print data
Serial.printf("Temperature = %.2f°C\r\n", main_temp);
Serial.printf("Humidity = %d %%\r\n", main_humidity);
Serial.printf("Pressure = %.3f bar\r\n", main_pressure);
}
else
{
Serial.println("[HTTP] .begin() failed");
}
http.end(); //Close connection
}
}
/*********************************************************************
Function to set the alignment of text
********************************************************************/
void drawString(const GFXfont *font, int x, int y, String text, alignment align) {
char * Data = const_cast<char*>(text.c_str());
int x1, y1; //the bounds of x,y and w and h of the variable 'text' in pixels.
int w, h;
int xx = x, yy = y;
get_text_bounds((GFXfont *)font, Data, &xx, &yy, &x1, &y1, &w, &h, NULL);
if (align == RIGHT) x = x - w;
if (align == CENTER) x = x - w / 2;
int cursor_y = y + h;
writeln((GFXfont *)font, Data, &x, &cursor_y, NULL);
}
Note: To get the above code working, you will need the ArduinoJson library. Follow the steps here, and search & install the ArduinoJson library.
Note: Ensure to add the appropriate font header file in the Arduino code folder. Also, dont forge to change the credentials with your own.
The code is well commented to explain the steps. Compile and upload the code to the module. If everything went well, you will see the below text on your E-Paper Display.
To achieve this, we will need to perform the following steps:
- Create a https://io.adafruit.com/ account and create an MQTT Feed
- Create a https://ifttt.com/ account and create an Applet
- Create a DND message image and convert it to a header file using the method in the Step-5
- Connect ESP32 to a WiFi Network
- Get the data from the Adafruit IO server to our module
- Use the data received to show the message on the E-Paper display
1.Create a https://io.adafruit.com/ account and create an MQTT Feed
Adafruit IO uses the MQTT protocol to send and receive data from the device. To understand the terminologies related to MQTT, you can go over the article here.
To simplify terms in Adafruit IO cloud,
- A Feed is simply an MQTT topic that we will use to send data from the Adafruit IO server to our module
- A user name is the user id that you set while creating an account in the Adafruit IO platform
- A key is a combination of letters and numbers and is assigned to identify the user.
Now, open https://io.adafruit.com/ and create an account by clicking on the Get started for free button.
Note: Use the same email id that you have used in you Android phone for using google services.
Fill in the details and log in to your account. You should see the home page below:
Now you will need to add an MQTT topic using which you will get the instruction sent from Google Assistant. To do this click on "Feeds" and then click on "View All".
If you are a new user, the list of feeds will be empty. Click on the "+New Feed" button to add one.
Fill in the name of the feed and description, and click on "Create"
That's all! the setup of the Adafruit IO cloud is done. Click on the "My Key" button on the navigation bar, copy the "User Name" & "Active Key", and save it somewhere safe. We are going to need it while writing Arduino code.
2. Create a https://ifttt.com/ account and create an Applet
Now we will create triggers in IFTTT to send some value to Adafruit IO when we tell our Google Assistant to turn on Do Not Disturb mode.
Go to https://ifttt.com/ and create an account.
Note: Use the same email id that you have used in you Android phone for using google services
Once you are logged in, click on the "Create" button on the home page.
On the next screen, click on the "Add" button beside "If This".
In the search bar, type "google assistant" and select the Google Assistant card.
Next, select "Say a simple phrase"
In the form that appears, fill the details as asked and click on the "Create Trigger" button at the bottom.
What do you want to say? - This is the phrase that you wish to speak on google assistant. In my case, I have used "DND mode"
On the next screen, click on the "Add" button beside "Then that". In the search bar type "Adafruit" and select the card that appears. Next, select the "Send data to Adafruit IO" card.
In the form that appears, select the Feed name that we created earlier in the Adafruit IO account. I have selected "dnd".
In the "Data to save" field, type the word that you want to send to the ESP32 module and use that to activate DND mode. I am sending "dnd". Next, click on "Create action".
On the next screen, click on the "Continue" button and then click on "Finish".
Great! your Applet to trigger DND mode is ready. You can create another Applet to turn off DND mode as well.
Now, we can move on to writing the final Arduino code.
3. Create a DND message image and convert it to a header file using the method in "Step-5"
If you wish to use the header file I have created, you can head over to the repository here.
The rest of the steps you can follow from the code below:
// Check if the PSRAM is available and enabled
#ifndef BOARD_HAS_PSRAM
#error "Please enable PSRAM !!!"
#endif
// Include the required libraries
#include "epd_driver.h"
#include <WiFi.h>
#include "Adafruit_MQTT.h"
#include "Adafruit_MQTT_Client.h"
// Include the image to be displayed
#include "dnd.h"
// Declare the required global variables
uint8_t *framebuffer;
// Wifi and server credentials
#define WLAN_SSID "Your WiFi Name"
#define WLAN_PASS "Your WiFi Password"
#define AIO_SERVER "io.adafruit.com"
#define AIO_SERVERPORT 1883
#define AIO_USERNAME "User name" // used while creating Adfruit IO Account
#define AIO_KEY "aio_zPvi77mHzVa3kAC1i0SIeexxxxxx" //Adafruit IO account key
WiFiClient client; // Create an ESP8266 WiFiClient class to connect to the MQTT server.
Adafruit_MQTT_Client mqtt(&client, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY); // Setup the MQTT client class by passing in the WiFi client and MQTT server and login details.
Adafruit_MQTT_Subscribe voiceTrigger = Adafruit_MQTT_Subscribe(&mqtt, AIO_USERNAME "/feeds/dnd"); // Define the topic to be subscribed
void setup() {
Serial.begin(115200);
EPD_setup();
wifiSetup();
mqtt.subscribe(&voiceTrigger);
}
void loop() {
MQTT_connect();
Adafruit_MQTT_Subscribe *subscription;
/*********************************************************************
Check the string received from the MQTT server on the subscribed topic
and perform action accordingly
********************************************************************/
while ((subscription = mqtt.readSubscription(5000))) {
if (subscription == &voiceTrigger) {
Serial.print(F("Got: "));
Serial.println((char *)voiceTrigger.lastread);
if (!strcmp((char*) voiceTrigger.lastread, "dnd"))
displayImage();
else epd_clear();
}
}
}
/*********************************************************************
Function for Wifi setup
********************************************************************/
void wifiSetup() {
Serial.printf("Connecting to %s ", WLAN_SSID);
WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println(" CONNECTED");
Serial.println("IP address: "); Serial.println(WiFi.localIP());
}
/*********************************************************************
Function to set buffer memory and initialize E-Paper Display
********************************************************************/
void EPD_setup() {
epd_init(); // Initialize the e-paper display
// Set framebuffer size
framebuffer = (uint8_t *)ps_calloc(sizeof(uint8_t), EPD_WIDTH * EPD_HEIGHT / 2);
// Check if the buffer memory is allocted successfully
if (!framebuffer) {
Serial.println("alloc memory failed !!!");
while (1);
}
memset(framebuffer, 0xFF, EPD_WIDTH * EPD_HEIGHT / 2); // Fill the buffer with white pixels
epd_poweron(); // Turn the E-Paper display on
epd_clear(); // clear the content on the display
}
/*********************************************************************
Function for connecting to MQTT Server
********************************************************************/
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!");
}
/*********************************************************************
Function to show the the image on E-Paper display
*********************************************************************/
void displayImage() {
// Set the position and area of the image
Rect_t area = {
.x = 50,
.y = 30,
.width = dnd_width,
.height = dnd_height,
};
epd_draw_grayscale_image(area, (uint8_t *)dnd_data); //Draw logo
delay(100);
}
In the above code:
- We first connect our module to a WiFi Network
- Once connected, we subscribe to the MQTT server of Adafruit IO with the "dnd" topic
- Once subscribed, we are continuously checking for the values received on the topic
- If the value received on the "dnd" topic is "dnd", we are displaying the DND image.
Note: If you get any error, most probaby you do not have "Adafruit MQTT Library" installed. Follow the steps here, and search & install the "Adafruit MQTT Library"
Compile and upload the above code onto your module. If things go well, you should see nothing on the E-Paper display. Open Google Assitant on your Android phone and speak "DND Mode". The DND image should appear on your E-Paper display as below.
Awesome! if you have reached this stage, you have learned all the aspects that we need to build our final IoT Smart Clock.
Step-10: Combine everything learned till now to build Smart ClockI have decided to build a Smart Clock that will look something like this:
You can follow the below links for the Arduino code of the final version of the Smart clock.
- GitHub:https://github.com/atul-dubey/Arduino_Projects/tree/master/Building_an_IoT_Smart_Clock
- YouTube:
If you have awesome ideas about how the Smart Clock might look, post the image of the Clock in the comments.
Comments
Please log in or sign up to comment.