Edit – Updated 12th July 2021 to Include the new Inkplate10 eink display
***
Sometimes there is a need to step back and do things as simply as possible. EInk / Epaper screens are amazing, they carrying on showing an image with zero power and the screens have a certain clarity that is hard to achieve with more standard LED offerings. The more difficult part is getting content onto them, especially content that is well designed and fits the screen.
To make the most of eInk/epaper screens you generally grab some information using a microcontroller, such as a Node MCU or ESP32, send it to the screen and then power down. This means you can check for new information over a period of time, say, every 15 minutes, display it and then sleep, allowing your screen to be battery powered for weeks on end.
At the moment we are using the amazing InkPlate 6. The InkPlate 6 is built around a recycled Kindle Screen and has a built-in ESP32 controller, a lithium battery connecter/charger and perhaps, more importantly, an easy to understand library to display an image and then sleep. In the world of eInk screens, the importance of an easy to understand library really cannot be understated, some of them are notably complex. We have published the 3D printable case to Thingiverse so all you need is the InkPlate (or any other screen you want to display an image on), a script to load a webpage and some Node JS to grab the information you want to display.
As an update we are now also using the Inkplate10, inserted into a picture frame, with a mount size of 10×8 inches (this is slightly sub-optimal but a full mount could be simply cut). Below is an example using the script to display a feed from BBC News, this updates every 15 minutes with a battery life of around 1 month.
The information can of course be any web page you want to display, from a news site, a social network feed, transport information or anything you want to show.
Ingredients
- You will need a device capable of running Node JS, we are using a Raspberry Pi 4. We assume here that you have a Pi up and running with the full operating system installed, if not then take a look at the main Pi site for details on how to set up. If you need any help then drop us a line in the comments and we can expand this section as needs be.
- Optional: An eInk screen and controller – we are using both the InkPlate 6 and the inkplate 10, our code to load the image once grabbed is now available on GitHub. There are a number of eInk/epaper screens, the most popular ones being made by WaveShare. These will also work if you edit the example code from the libraries that allow the display of online images. Of course, you may simply want to have an automated screengrab of a webpage. Such things are useful in Unity3D to make Augmented Reality displays, for example.
Installing Node JS
The first part is to install Node.JS, thankfully Node is quick and easy to install – in your terminal enter:
$ curl -sL https://deb.nodesource.com/setup_15.10.0 | sudo -E bash -
The 15.10.0 represent the current version as of February 2021, change this number to the latest version as needs be – you can find out the current release via the main Node JS site. You have now made your Pi aware of where to find Node.
The next step is to install it:
sudo apt install nodejs
To check all is in place you can run:
node -v
This will tell you the version of Node you are running. You have installed Node, well done, now for the Puppeteer library.
Installing and Configuring Puppeteer
Puppeteer is a library for Node.js that allows for the control of the Chrome browser in headerless mode (i.e. you dont see it happening). This allows you to open a web page, do something with it – in our case take a screenshot – and then close chrome, all via a simple script.
Installing Pupperteer is all via a single line in the terminal:
npm i puppeteer --save
Now you have Node.js and Puppeteer installed, all you need now is to create a script to tell Node what to do:
We like to start a new script in a new directory called ‘Scripts’ (although it can be anywhere).
So firstly create a new directory via the terminal:
mkdir Scripts
Now create your first empty script, we are going to call ours ‘webpage.js’:
sudo nano webpage.js
Below is the javascript to cut and paste into your new script:
const puppeteer = require('puppeteer');
async function timeout(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
(async () => {
let browser = await puppeteer.launch({
headless: true,
executablePath: '/usr/bin/chromium-browser',
// args: ['--no-sandbox', '--disable-setuid-sandbox']
});
const page = await browser.newPage();
await page.goto('http:YourWebPageURL');
// 5 second timeout: allows the page to fully render before taking the screenshot
await timeout(5000);
// Note for the inkplate 10 use width: 1200, height: 825 below:
await page.setViewport({ width: 800, height: 600});
await page.screenshot({path: '/home/pi/Scripts/eink.jpg'});
await browser.close();
})();
The main parts to note above are the http: where you need to add in the webpage you want to capture and the width and height of the page. This should be changed according to the resolution of your screen, the InkPlate 6 runs at 800×600 resolution.
To run the script:
node webpage.js
The script opens the URL, waits 5 seconds for it to fully load and then saves a screenshot as a jpg to the location of your choice.
If you are running your eInk display direct from your Pi (such as using a Waveshare screen) you can stop here and point your display to the new image. If however, you are using a screen elsewhere on your network you will need to host it, this is where Node Express comes in.
Installing Node Express
As with Node and Puppeteer installing is via a simple one line command:
npm install express --save
To start the server and host the image, you need another script. So the same as before, create a script, we called ours server.js:
sudo nano server.js
Cut and paste the following:
var express = require('express');
var app = express();
var path = require('path');
var public = path.join(__dirname, 'public');
// viewed at http://localhost:8080
app.get('/', function(req, res) {
res.sendFile(path.join(public, 'index.html'));
});
app.use('/', express.static(public));
app.listen(8080);
The above script runs a server at http://localhost:8080 where you can install a welcome page (index.html) if you wish but more importantly you can serve static files, in our case our screen grab eink.jpg. Note that the folder address is ‘public’ this is where you will host your files.
In our first script we now want to edit the folder where our image is saved, so we can host it as soon as it is created, so simply edit the file, (again using sudo nano webpage.js) to include the ‘public’ directory -ie /home/pi/Scripts/public/eink.jpg
If you now go to either http://localhost:8080/eink.jpg on the host machine or your http://Your IP of the PI:8080/eink.jpg you should be able to view the jpg.
All that needs to be done now is to start the server when the Pi boots and to run the webpage script every set period of time. To load different webpages simply clone the webpage.js script but with a different URL to grab and run it at a different time, as mentioned, we run 4 scripts an hour via cron jobs.
Cron Jobs
The final part is to run the server at boot and the script every 15 minutes.
Firstly go to your root directory by typing:
cd:
Now we want to install a new Cron Job, or edit one we have already set up:
sudo crontab -e
At the end of the file that opens add the following lines:
@reboot sudo /usr/bin/node /home/pi/Scripts/server.js
15 * * * * /usr/bin/node /home/pi/Scripts/webpage.js
Whenever the Pi reboots it will now start the server – via your server.js script and every 15 minutes run your webpage.js script to take an image of a webpage, which you can subsequently point your eInk screen to load.
It may feel like a number of hoops to jump through for a simple screengrab, but once running it opens up the wider world of Node.js and Puppeteer as well as the ability to use your eInk screen to display any webpage you want.
I hope this has been useful, do drop me a line in the comments with any thoughts or tweet me @digitalurban. It’s part of a series of new ‘how to’s’ here on digitalurban.org and over at https://connected-environments.org/