Create a beautiful medium for weather information using Particle's cloud services and IFTTT.
Things used in this project
Hardware components
Hand tools and fabrication machines
Hot glue gun (generic)
Story
If you have an E-Reader such as a Barnes & Noble NOOK or an Amazon Kindle then you're already familiar with e-paper. The e-paper display on your e-reader is what allows you to read it in direct sunlight without any glare. However, you also know that the e-paper screen takes a really long time to update. This means that you can't use it for gaming, but it's perfect for providing you with timely weather information wherever you need it! This super-simple project creates just that with minimal assembly and coding time. Let's dive in!
Step 1: The Parts
This project has only four components, all of which can be obtained from DFRobot. Check 'em out below:
E-Paper Display: https://www.dfrobot.com/product-1312.htmlMicro SD Card: https://www.dfrobot.com/product-1191.htmlParticle Photon: https://www.dfrobot.com/product-1324.htmlMicro USB Cable: https://www.dfrobot.com/product-770.html
Other than a computer, this is literally all you need. Both the Photon and E-Paper display are highly integrated components, meaning that they need very little external support hardware to function. Go embedded systems! The display actually has its own integrated 32-bit microcontroller as a driver - this is part of the reason why it has a somewhat large price tag as compared to other displays.
Step 2: Assembly
Assembly is a piece of cake. The connections are as follows:
E-Paper -> Photon
RST -> UnconnectedWake_Up -> D2DIN -> TXDOUT -> RXGND -> GNDVCC -> 3V3There is some setup for your Photon that you need to do. Particle provides a great resource for this that you can check out here: https://docs.particle.io/guide/getting-started/start/photon/
That's it! Now let's move on to flashing your SD card with the required images for this project.
Step 3: Preparing Your SD Card
I'm going to preface this part by saying that if you really don't want to use an SD card, you don't have to. The display has a few MB of memory that you can use to store images. However, the program that allows you to load in these images is a bit, well, janky. I had a really tough time getting it to install on Windows 7, Windows 10, and macOS in wine bottler, so I decided to just give up and use the SD card. Here's how you can prepare yours:
Plug your micro SD card into the provided adapter and plug it into your computer. If you're on Mac you can utilize Disk Utility to easily format your card into the required FAT32 format. Name the card whatever you want. I'm sure Windows has a comprable program for formatting SD cards. If your card is new, it's also likely that it's already in FAT32. Download the .zip file linked in this step, and extract it. Load all those bitmaps onto the SD card, eject it, and put it in your display. You should now be good to go!
Making your bitmap images in the correct format for the display is a little bit of trial and error. If you would like a tutorial on it let me know and I can create one. The biggest thing to remember is that the white pixels are actually the ones that are black on the display, and vice-versa.
Download Link: SD Card Package.zip
Step 4: IFTTT: Get Connecting!
The way your Photon will be getting weather information is from IFTTT. This mainly out of laziness on my part; IFTTT + Photon is practically a thing of magic and works with an extremely minimal amount of setup. I won't be explaining the process of signing up for an account or connecting the Particle service to your IFTTT account - Particle already has great documentation.
The basic flow for IFTTT is that Weather Underground sends data to your Photon at the same time every morning. This is done in two separate applets - one that sends over the high and low temperature information, and another that sends over the condition information.
If you don't already have it, add the Weather Underground service to IFTTT. It will ask you a bunch of questions that help it to deliver accurate weather information.
Now click the button to create a new applet. Choose Weather Underground as the service, and select Today's Weather Report as the trigger. Set the time to whenever you want your Particle to receive weather information each day. Select create trigger, then choose Particle for the "then" part of your applet. Select publish an event.
The name of your event should be something unique that no one else is likely to use. If it isn't unique enough, you will get events from other peoples' services. We'll be sending over the temperature information in this applet, so have it include something about temperature. A possibility could be "NewTemperatureInfoUpdate."
In the data field you need to use exactly what is shown in the above photo. This is, not including the quotes, "{{HighTempFahrenheit}},{{LowTempFahrenheit}}". If it is not exactly like this then your particle won't be able to process the incoming data. Lastly, change the event type to public, and create the applet.
This is only half of what needs to be done. You also need to create the applet that passes the condition information. The Weather Underground part is exactly the same. Create a new applet, and setup the Weather Underground service section in the same way. Choose Particle again for the "that" section, and select publish an event. It's the same deal for the name of your event. Make it unique, and something that has to do with condition. A possibility could be "GotNewConditionInformation"
In the data field of your event you need to have exactly the following (without quotes): "{{TodaysCondition}}". Press create, and you should be all set with IFTTT.
Step 5: Flashing Your Particle
Luckily for you I did all the complicated setup to get the E-Paper display to interface correctly with your Photon. All you need to do is click on this link and copy the Particle Build app: https://go.particle.io/shared_apps/5995bb8f077992ee5d000c79
Once the app is copied to your Particle account you can perform the final setup. The only parts of the code that you need to change are lines 30 and 31. Change the name of the event to be the event that you created inside of IFTTT, and you're done! Flash you Photon and with any luck the above screen should appear.
Once the set time of your applet passes the display will update with the correct weather info. To make this update interval more frequent all you need to do is create more applets with the same event name. The clock will update every minute automatically. To change the time zone you need to configure line 26 with your UTC offset.
Step 6: Final Thoughts
You can mount the display however you like. As shown in the video at the beginning of this tutorial, I glued my Photon to the back of my display. This has the added benefit of acting as a little kickstand to prop up the whole project!
If you have any questions don't hesitate to comment below or send me a message. You can check out my projects on my Hackster profile, my Maker Share profile, and my Instructables profile. I also have written a bunch of interesting blog posts. Read them on Medium.
Code
ParticleStationEpaper.ino
Arduino
#include "epd.h"
//Code produced by Alex Wulff - www.AlexWulff.com
void setup(void)
{
//Initialize E-Paper display, set memory to flash card, change the font, and set the foreground and background colors.
epd_init();
epd_wakeup();
epd_set_memory(MEM_TF);
epd_set_color(BLACK, WHITE);
epd_set_en_font(ASCII64);
epd_clear();
//Put the initial graphics on-screen
epd_disp_bitmap("PRT.BMP", 475, 25);
epd_disp_bitmap("BTM.BMP", 0, 324);
epd_disp_string("No Data", 25, 25);
epd_disp_string("High Temp: 00", 25, 100);
epd_disp_string("Low Temp: 00", 25, 175);
//The author of this library spelled update wrong. It bugs me, but not enough to go in and change it
epd_udpate();
// Set time zone to Eastern USA daylight saving time
Time.zone(-4);
displayTime();
//Subscribe to the two actions from IFTTT. Change the string to be the name that you chose
Particle.subscribe("NAME_OF_CONDITION_ACTION", conditionHandler);
Particle.subscribe("NAME_OF_TEMP_ACTION", tempHandler);
}
//Is called when you receive temperature data
void tempHandler(const char *event, const char *data) {
int high, low;
//Retrieve the two temperature values from the string using C++'s sscanf() fct
if (sscanf(data, "%d,%d", &high, &low) == 2) {
//Create two strings with the temp values added in
char highBuffer[64];
char lowBuffer[64];
sprintf(highBuffer, "High Temp: %d", high);
sprintf(lowBuffer, "Low Temp: %d", low);
//I don't want to clear the display, so I'm overwriting that line instead
epd_disp_string("High Temp: ", 25, 100);
epd_disp_string("Low Temp: ", 25, 175);
epd_udpate();
//Finally display the two strings
epd_disp_string(highBuffer, 25, 100);
epd_disp_string(lowBuffer, 25, 175);
epd_udpate();
}
else {
//This means there was an error. This probably happened because your action name wasn't unique enough and you're getting someone else's action
epd_disp_string("Error w/ temp", 0, 450);
epd_disp_string(" ", 0, 525);
epd_disp_string(data, 0, 525);
epd_udpate();
}
}
void conditionHandler(const char *event, const char *data) {
//The width of spaces is small, so in order to clear the line I need a ton of them
epd_disp_string(" ", 25, 50);
epd_udpate();
//Display the condition name
epd_disp_string(data, 25, 25);
//This matches the images on the SD card with specific conditions. All the conditions in that link
//https://www.wunderground.com/weather/api/d/docs?d=resources/phrase-glossary&_ga=2.68020689.1328253466.1502822638-1300575137.1434505073&MR=1
if(strstr(data, "Drizzle") != NULL || strstr(data, "Rain") != NULL) {
epd_disp_bitmap("RAIN.BMP", 475, 25);
}
else if(strstr(data, "Clear") != NULL || strstr(data, "Sun") != NULL) {
epd_disp_bitmap("SUN.BMP", 475, 25);
}
else if(strstr(data, "Part") != NULL) {
epd_disp_bitmap("PRT.BMP", 475, 25);
}
else if(strstr(data, "Cloudy") != NULL) {
epd_disp_bitmap("RAIN.BMP", 475, 25);
}
else if(strstr(data, "Freezing") != NULL || strstr(data, "Snow") != NULL) {
epd_disp_bitmap("SNOW.BMP", 475, 25);
}
epd_udpate();
}
void displayTime() {
//See http://strftime.org for formatting info. This displays the time.
epd_disp_string(Time.format(Time.now(), "It's %I:%M%p."), 25, 250); //It's 12:57PM.
epd_udpate();
}
int lastChecked = 0;
void loop() {
//Every minute sync the clock with the cloud and update the time on the display.
if (millis() - lastChecked > 60000) {
Particle.syncTime();
displayTime();
lastChecked = millis();
}
}
epd.h
C/C++
/*********************************************************************************************************
*
* File : epd.h
* Hardware Environment:
* Build Environment : RealView MDK-ARM Version: 4.74
* Version : V1.0
* By : V
*
* (c) Copyright 2005-2015, WaveShare
* http://www.waveshare.net
* All Rights Reserved
*
*
* Please note: this library has been modified by Alex Wulff (www.AlexWulff.com)
* to be compatible for the Particle Photon. It is not in its original form.
*********************************************************************************************************/
#ifndef EPD_H
#define EPD_H
#define CMD_SIZE 512
/*
frame format
*/
#define FRAME_B 0xA5
#define FRAME_E0 0xCC
#define FRAME_E1 0x33
#define FRAME_E2 0xC3
#define FRAME_E3 0x3C
/*
color define
*/
#define WHITE 0x03
#define GRAY 0x02
#define DARK_GRAY 0x01
#define BLACK 0x00
/*
command define
*/
#define CMD_HANDSHAKE 0x00 //handshake
#define CMD_SET_BAUD 0x01 //set baud
#define CMD_READ_BAUD 0x02 //read baud
#define CMD_MEMORYMODE 0x07 //set memory mode
#define CMD_STOPMODE 0x08 //enter stop mode
#define CMD_UPDATE 0x0A //update
#define CMD_SCREEN_ROTATION 0x0D //set screen rotation
#define CMD_LOAD_FONT 0x0E //load font
#define CMD_LOAD_PIC 0x0F //load picture
#define CMD_SET_COLOR 0x10 //set color
#define CMD_SET_EN_FONT 0x1E //set english font
#define CMD_SET_CH_FONT 0x1F //set chinese font
#define CMD_DRAW_PIXEL 0x20 //set pixel
#define CMD_DRAW_LINE 0x22 //draw line
#define CMD_FILL_RECT 0x24 //fill rectangle
#define CMD_DRAW_CIRCLE 0x26 //draw circle
#define CMD_FILL_CIRCLE 0x27 //fill circle
#define CMD_DRAW_TRIANGLE 0x28 //draw triangle
#define CMD_FILL_TRIANGLE 0x29 //fill triangle
#define CMD_CLEAR 0x2E //clear screen use back color
#define CMD_DRAW_STRING 0x30 //draw string
#define CMD_DRAW_BITMAP 0x70 //draw bitmap
/*
FONT
*/
#define GBK32 0x01
#define GBK48 0x02
#define GBK64 0x03
#define ASCII32 0x01
#define ASCII48 0x02
#define ASCII64 0x03
/*
Memory Mode
*/
#define MEM_NAND 0
#define MEM_TF 1
/*
set screen rotation
*/
#define EPD_NORMAL 0 //screen normal
#define EPD_INVERSION 1 //screen inversion
void epd_init(void);
void epd_reset(void);
void epd_wakeup(void);
void epd_handshake(void);
void epd_set_memory(unsigned char mode);
void epd_enter_stopmode(void);
void epd_udpate(void);
void epd_screen_rotation(unsigned char mode);
void epd_load_font(void);
void epd_load_pic(void);
void epd_set_color(unsigned char color, unsigned char bkcolor);
void epd_set_en_font(unsigned char font);
void epd_set_ch_font(unsigned char font);
void epd_draw_pixel(int x0, int y0);
void epd_draw_line(int x0, int y0, int x1, int y1);
void epd_fill_rect(int x0, int y0, int x1, int y1);
void epd_draw_circle(int x0, int y0, int r);
void epd_fill_circle(int x0, int y0, int r);
void epd_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2);
void epd_fill_triangle(int x0, int y0, int x1, int y1, int x2, int y2);
void epd_clear(void);
void epd_disp_char(unsigned char ch, int x0, int y0);
void epd_disp_string(const void * p, int x0, int y0);
void epd_disp_bitmap(const void * p, int x0, int y0);
#endif
epd.cpp
C/C++
/*********************************************************************************************************
*
* File : epd.c
* Hardware Environment:
* Build Environment : RealView MDK-ARM Version: 4.74
* Version : V1.0
* By : V
*
* (c) Copyright 2005-2014, WaveShare
* http://www.waveshare.net
* All Rights Reserved
*
*
* Please note: this library has been modified by Alex Wulff (www.AlexWulff.com)
* to be compatible for the Particle Photon. It is not in its original form.
*********************************************************************************************************/
#include "epd.h"
#include "Particle.h"
const int wake_up = 2;
// const int reset = 3;
/*
command define
*/
static const unsigned char _cmd_handshake[8] = {0xA5, 0x00, 0x09, CMD_HANDSHAKE, 0xCC, 0x33, 0xC3, 0x3C}; //CMD_HANDSHAKE
static const unsigned char _cmd_read_baud[8] = {0xA5, 0x00, 0x09, CMD_READ_BAUD, 0xCC, 0x33, 0xC3, 0x3C}; //CMD_READ_BAUD
static const unsigned char _cmd_stopmode[8] = {0xA5, 0x00, 0x09, CMD_STOPMODE, 0xCC, 0x33, 0xC3, 0x3C}; //CMD_STOPMODE
static const unsigned char _cmd_update[8] = {0xA5, 0x00, 0x09, CMD_UPDATE, 0xCC, 0x33, 0xC3, 0x3C}; //CMD_UPDATE
static const unsigned char _cmd_load_font[8] = {0xA5, 0x00, 0x09, CMD_LOAD_FONT, 0xCC, 0x33, 0xC3, 0x3C}; //CMD_LOAD_FONT
static const unsigned char _cmd_load_pic[8] = {0xA5, 0x00, 0x09, CMD_LOAD_PIC, 0xCC, 0x33, 0xC3, 0x3C}; //CMD_LOAD_PIC
static unsigned char _cmd_buff[CMD_SIZE];
/*
private function
*/
static void _putchars(const unsigned char * ptr, int n);
static unsigned char _verify(const void * ptr, int n);
/*******************************************************************************
* Function Name : static void _putchars(const unsigned char * ptr, int n)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
static void _putchars(const unsigned char * ptr, int n)
{
int i, x;
for(i = 0; i < n; i++)
{
x = ptr[i];
Serial1.write(x);
}
}
/*******************************************************************************
* Function Name : static unsigned char _verify(const void * ptr, int n)
* Description :
* Input : ptr
n
* Output : None
* Return :
*******************************************************************************/
static unsigned char _verify(const void * ptr, int n)
{
int i;
unsigned char * p = (unsigned char *)ptr;
unsigned char result;
for(i = 0, result = 0; i < n; i++)
{
result ^= p[i];
}
return result;
}
/*******************************************************************************
* Function Name : void epd_init(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_init(void)
{
Serial1.begin(115200);
pinMode(wake_up, OUTPUT);
// pinMode(reset, OUTPUT);
}
/*******************************************************************************
* Function Name : void epd_reset(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_reset(void)
{
digitalWrite(reset, LOW);
delayMicroseconds(10);
digitalWrite(reset, HIGH);
delayMicroseconds(500);
digitalWrite(reset, LOW);
delay(3000);
}
/*******************************************************************************
* Function Name : void epd_init(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_wakeup(void)
{
digitalWrite(wake_up, LOW);
delayMicroseconds(10);
digitalWrite(wake_up, HIGH);
delayMicroseconds(500);
digitalWrite(wake_up, LOW);
delay(10);
}
/*******************************************************************************
* Function Name : void epd_handshake(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_handshake(void)
{
memcpy(_cmd_buff, _cmd_handshake, 8);
_cmd_buff[8] = _verify(_cmd_buff, 8);
_putchars(_cmd_buff, 9);
}
/*******************************************************************************
* Function Name : void epd_set_baud(long baud)
* Description : set uart baud
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_set_baud(long baud)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0D;
_cmd_buff[3] = CMD_SET_BAUD;
_cmd_buff[4] = (baud >> 24) & 0xFF;
_cmd_buff[5] = (baud >> 16) & 0xFF;
_cmd_buff[6] = (baud >> 8) & 0xFF;
_cmd_buff[7] = baud & 0xFF;
_cmd_buff[8] = FRAME_E0;
_cmd_buff[9] = FRAME_E1;
_cmd_buff[10] = FRAME_E2;
_cmd_buff[11] = FRAME_E3;
_cmd_buff[12] = _verify(_cmd_buff, 12);
_putchars(_cmd_buff, 13);
delay(10);
Serial1.begin(baud);
}
/*******************************************************************************
* Function Name : void epd_read_baud(void)
* Description : read uart baud
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_read_baud(void)
{
memcpy(_cmd_buff, _cmd_read_baud, 8);
_cmd_buff[8] = _verify(_cmd_buff, 8);
_putchars(_cmd_buff, 9);
}
/*******************************************************************************
* Function Name : void epd_set_memory(unsigned char mode)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_set_memory(unsigned char mode)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0A;
_cmd_buff[3] = CMD_MEMORYMODE;
_cmd_buff[4] = mode;
_cmd_buff[5] = FRAME_E0;
_cmd_buff[6] = FRAME_E1;
_cmd_buff[7] = FRAME_E2;
_cmd_buff[8] = FRAME_E3;
_cmd_buff[9] = _verify(_cmd_buff, 9);
_putchars(_cmd_buff, 10);
}
/*******************************************************************************
* Function Name : void epd_enter_stopmode(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_enter_stopmode(void)
{
memcpy(_cmd_buff, _cmd_stopmode, 8);
_cmd_buff[8] = _verify(_cmd_buff, 8);
_putchars(_cmd_buff, 9);
}
/*******************************************************************************
* Function Name : void epd_udpate(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_udpate(void)
{
memcpy(_cmd_buff, _cmd_update, 8);
_cmd_buff[8] = _verify(_cmd_buff, 8);
_putchars(_cmd_buff, 9);
}
/*******************************************************************************
* Function Name : void epd_screen_rotation(unsigned char mode)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_screen_rotation(unsigned char mode)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0A;
_cmd_buff[3] = CMD_SCREEN_ROTATION;
_cmd_buff[4] = mode;
_cmd_buff[5] = FRAME_E0;
_cmd_buff[6] = FRAME_E1;
_cmd_buff[7] = FRAME_E2;
_cmd_buff[8] = FRAME_E3;
_cmd_buff[9] = _verify(_cmd_buff, 9);
_putchars(_cmd_buff, 10);
}
/*******************************************************************************
* Function Name : void epd_load_font(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_load_font(void)
{
memcpy(_cmd_buff, _cmd_load_font, 8);
_cmd_buff[8] = _verify(_cmd_buff, 8);
_putchars(_cmd_buff, 9);
}
/*******************************************************************************
* Function Name : void epd_load_pic(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_load_pic(void)
{
memcpy(_cmd_buff, _cmd_load_pic, 8);
_cmd_buff[8] = _verify(_cmd_buff, 8);
_putchars(_cmd_buff, 9);
}
/*******************************************************************************
* Function Name : void epd_set_color(unsigned char color, unsigned char bkcolor)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_set_color(unsigned char color, unsigned char bkcolor)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0B;
_cmd_buff[3] = CMD_SET_COLOR;
_cmd_buff[4] = color;
_cmd_buff[5] = bkcolor;
_cmd_buff[6] = FRAME_E0;
_cmd_buff[7] = FRAME_E1;
_cmd_buff[8] = FRAME_E2;
_cmd_buff[9] = FRAME_E3;
_cmd_buff[10] = _verify(_cmd_buff, 10);
_putchars(_cmd_buff, 11);
}
/*******************************************************************************
* Function Name : void epd_set_en_font(unsigned char font)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_set_en_font(unsigned char font)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0A;
_cmd_buff[3] = CMD_SET_EN_FONT;
_cmd_buff[4] = font;
_cmd_buff[5] = FRAME_E0;
_cmd_buff[6] = FRAME_E1;
_cmd_buff[7] = FRAME_E2;
_cmd_buff[8] = FRAME_E3;
_cmd_buff[9] = _verify(_cmd_buff, 9);
_putchars(_cmd_buff, 10);
}
/*******************************************************************************
* Function Name : void epd_set_ch_font(unsigned char font)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_set_ch_font(unsigned char font)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0A;
_cmd_buff[3] = CMD_SET_CH_FONT;
_cmd_buff[4] = font;
_cmd_buff[5] = FRAME_E0;
_cmd_buff[6] = FRAME_E1;
_cmd_buff[7] = FRAME_E2;
_cmd_buff[8] = FRAME_E3;
_cmd_buff[9] = _verify(_cmd_buff, 9);
_putchars(_cmd_buff, 10);
}
/*******************************************************************************
* Function Name : void epd_draw_pixel(int x0, int y0)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_draw_pixel(int x0, int y0)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0D;
_cmd_buff[3] = CMD_DRAW_PIXEL;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
_cmd_buff[8] = FRAME_E0;
_cmd_buff[9] = FRAME_E1;
_cmd_buff[10] = FRAME_E2;
_cmd_buff[11] = FRAME_E3;
_cmd_buff[12] = _verify(_cmd_buff, 12);
_putchars(_cmd_buff, 13);
}
/*******************************************************************************
* Function Name : void epd_draw_line(int x0, int y0, int x1, int y1)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_draw_line(int x0, int y0, int x1, int y1)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x11;
_cmd_buff[3] = CMD_DRAW_LINE;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
_cmd_buff[8] = (x1 >> 8) & 0xFF;
_cmd_buff[9] = x1 & 0xFF;
_cmd_buff[10] = (y1 >> 8) & 0xFF;
_cmd_buff[11] = y1 & 0xFF;
_cmd_buff[12] = FRAME_E0;
_cmd_buff[13] = FRAME_E1;
_cmd_buff[14] = FRAME_E2;
_cmd_buff[15] = FRAME_E3;
_cmd_buff[16] = _verify(_cmd_buff, 16);
_putchars(_cmd_buff, 17);
}
/*******************************************************************************
* Function Name : void epd_fill_rect(int x0, int y0, int x1, int y1)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_fill_rect(int x0, int y0, int x1, int y1)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x11;
_cmd_buff[3] = CMD_FILL_RECT;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
_cmd_buff[8] = (x1 >> 8) & 0xFF;
_cmd_buff[9] = x1 & 0xFF;
_cmd_buff[10] = (y1 >> 8) & 0xFF;
_cmd_buff[11] = y1 & 0xFF;
_cmd_buff[12] = FRAME_E0;
_cmd_buff[13] = FRAME_E1;
_cmd_buff[14] = FRAME_E2;
_cmd_buff[15] = FRAME_E3;
_cmd_buff[16] = _verify(_cmd_buff, 16);
_putchars(_cmd_buff, 17);
}
/*******************************************************************************
* Function Name : void epd_draw_circle(int x0, int y0, int r)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_draw_circle(int x0, int y0, int r)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0F;
_cmd_buff[3] = CMD_DRAW_CIRCLE;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
_cmd_buff[8] = (r >> 8) & 0xFF;
_cmd_buff[9] = r & 0xFF;
_cmd_buff[10] = FRAME_E0;
_cmd_buff[11] = FRAME_E1;
_cmd_buff[12] = FRAME_E2;
_cmd_buff[13] = FRAME_E3;
_cmd_buff[14] = _verify(_cmd_buff, 14);
_putchars(_cmd_buff, 15);
}
/*******************************************************************************
* Function Name : void epd_fill_circle(int x0, int y0, int r)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_fill_circle(int x0, int y0, int r)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x0F;
_cmd_buff[3] = CMD_FILL_CIRCLE;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
_cmd_buff[8] = (r >> 8) & 0xFF;
_cmd_buff[9] = r & 0xFF;
_cmd_buff[10] = FRAME_E0;
_cmd_buff[11] = FRAME_E1;
_cmd_buff[12] = FRAME_E2;
_cmd_buff[13] = FRAME_E3;
_cmd_buff[14] = _verify(_cmd_buff, 14);
_putchars(_cmd_buff, 15);
}
/*******************************************************************************
* Function Name : void epd_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_draw_triangle(int x0, int y0, int x1, int y1, int x2, int y2)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x15;
_cmd_buff[3] = CMD_DRAW_TRIANGLE;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
_cmd_buff[8] = (x1 >> 8) & 0xFF;
_cmd_buff[9] = x1 & 0xFF;
_cmd_buff[10] = (y1 >> 8) & 0xFF;
_cmd_buff[11] = y1 & 0xFF;
_cmd_buff[12] = (x2 >> 8) & 0xFF;
_cmd_buff[13] = x2 & 0xFF;
_cmd_buff[14] = (y2 >> 8) & 0xFF;
_cmd_buff[15] = y2 & 0xFF;
_cmd_buff[16] = FRAME_E0;
_cmd_buff[17] = FRAME_E1;
_cmd_buff[18] = FRAME_E2;
_cmd_buff[19] = FRAME_E3;
_cmd_buff[20] = _verify(_cmd_buff, 20);
_putchars(_cmd_buff, 21);
}
/*******************************************************************************
* Function Name : void epd_fill_triangle(int x0, int y0, int x1, int y1, int x2, int y2)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_fill_triangle(int x0, int y0, int x1, int y1, int x2, int y2)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x15;
_cmd_buff[3] = CMD_FILL_TRIANGLE;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
_cmd_buff[8] = (x1 >> 8) & 0xFF;
_cmd_buff[9] = x1 & 0xFF;
_cmd_buff[10] = (y1 >> 8) & 0xFF;
_cmd_buff[11] = y1 & 0xFF;
_cmd_buff[12] = (x2 >> 8) & 0xFF;
_cmd_buff[13] = x2 & 0xFF;
_cmd_buff[14] = (y2 >> 8) & 0xFF;
_cmd_buff[15] = y2 & 0xFF;
_cmd_buff[16] = FRAME_E0;
_cmd_buff[17] = FRAME_E1;
_cmd_buff[18] = FRAME_E2;
_cmd_buff[19] = FRAME_E3;
_cmd_buff[20] = _verify(_cmd_buff, 20);
_putchars(_cmd_buff, 21);
}
/*******************************************************************************
* Function Name : void epd_clear(void)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_clear(void)
{
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = 0x00;
_cmd_buff[2] = 0x09;
_cmd_buff[3] = CMD_CLEAR;
_cmd_buff[4] = FRAME_E0;
_cmd_buff[5] = FRAME_E1;
_cmd_buff[6] = FRAME_E2;
_cmd_buff[7] = FRAME_E3;
_cmd_buff[8] = _verify(_cmd_buff, 8);
_putchars(_cmd_buff, 9);
}
/*******************************************************************************
* Function Name : void epd_disp_char(unsigned char ch, int x0, int y0);
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_disp_char(unsigned char ch, int x0, int y0)
{
unsigned char buff[2];
buff[0] = ch;
buff[1] = 0;
epd_disp_string(buff, x0, y0);
}
/*******************************************************************************
* Function Name : void epd_disp_string(const void * p, int x0, int y0)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_disp_string(const void * p, int x0, int y0)
{
int string_size;
unsigned char * ptr = (unsigned char *)p;
string_size = strlen((const char *)ptr);
string_size += 14;
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = (string_size >> 8) & 0xFF;
_cmd_buff[2] = string_size & 0xFF;
_cmd_buff[3] = CMD_DRAW_STRING;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
strcpy((char *)(&_cmd_buff[8]), (const char *)ptr);
string_size -= 5;
_cmd_buff[string_size] = FRAME_E0;
_cmd_buff[string_size + 1] = FRAME_E1;
_cmd_buff[string_size + 2] = FRAME_E2;
_cmd_buff[string_size + 3] = FRAME_E3;
_cmd_buff[string_size + 4] = _verify(_cmd_buff, string_size + 4);
_putchars(_cmd_buff, string_size + 5);
}
/*******************************************************************************
* Function Name : void epd_disp_bitmap(const void * p, int x0, int y0)
* Description :
* Input :
* Output : None
* Return :
* Attention : None
*******************************************************************************/
void epd_disp_bitmap(const void * p, int x0, int y0)
{
int string_size;
unsigned char * ptr = (unsigned char *)p;
string_size = strlen((const char *)ptr);
string_size += 14;
_cmd_buff[0] = FRAME_B;
_cmd_buff[1] = (string_size >> 8) & 0xFF;
_cmd_buff[2] = string_size & 0xFF;
_cmd_buff[3] = CMD_DRAW_BITMAP;
_cmd_buff[4] = (x0 >> 8) & 0xFF;
_cmd_buff[5] = x0 & 0xFF;
_cmd_buff[6] = (y0 >> 8) & 0xFF;
_cmd_buff[7] = y0 & 0xFF;
strcpy((char *)(&_cmd_buff[8]), (const char *)ptr);
string_size -= 5;
_cmd_buff[string_size] = FRAME_E0;
_cmd_buff[string_size + 1] = FRAME_E1;
_cmd_buff[string_size + 2] = FRAME_E2;
_cmd_buff[string_size + 3] = FRAME_E3;
_cmd_buff[string_size + 4] = _verify(_cmd_buff, string_size + 4);
_putchars(_cmd_buff, string_size + 5);
}
The article was first published in hackster, August 17, 2017
cr: https://www.hackster.io/AlexWulff/e-paper-weather-display-with-photon-and-ifttt-cc37a0
author: Alex Wulff
