Inkplate 10 Weather Calendar
Display weather forecasts and a stylised map of your city on an Inkplate 10 that can last for months on a single battery. Four page layouts are available: a simplified today/tomorrow view, an hourly forecast table, and a 5-day daily summary.
Using a different e-paper display? The firmware is built around a hardware-agnostic
IBoardinterface. See doc/custom-board.md to integrate your own device.
![]() Today view: Current weather, map, and summary for Dublin |
![]() Tomorrow view: Forecast for Stockholm with icon and phrase |
![]() Hourly view: 9-hour forecast table for Reykjavik |
![]() Daily view: 5-day summary for Lisbon with icons and highs/lows |
- Getting Started
- Documentation
- Background
- How it Works
- Bill of Materials
- Client Configuration
- Firmware
- License
Documentation
- Server guide: server/README.md
- Weather provider API setup: doc/weather-apis.md
- Google Static Maps setup: doc/google-static-maps.md
- Integrating a custom board — implement the
IBoardinterface to use any e-paper device: doc/custom-board.md - Contributor guide: CONTRIBUTING.md
Getting Started
This project has two main parts: a server (image generator) and a client (firmware for the Inkplate 10). Follow these steps to get up and running.
Prepare your server configuration
For API keys, environment variables, schedule configuration, and advanced server setup, see server/README.md.
Before starting the server, copy the example config and fill in your API keys, Google Maps Map ID, and location:
cp server/config.example.yaml server/config.yaml
# Edit server/config.yaml and set your weather API key, Google Maps API key, map ID, and location
1. Server Setup
You can run the server using Docker (recommended) or directly with Python. The server generates weather/calendar images and serves them to the Inkplate client.
Run with Docker Compose (Recommended)
A sample docker-compose.yml is included in the repository. Most configuration is done in server/config.yaml, which is volume-mounted into the container. Only LOCATION and SERVER_PORT are set as environment variables (and are optional overrides):
version: '3'
services:
weather-cal-server:
image: ghcr.io/chrisjtwomey/inkplate10-weather-cal-server:latest
restart: unless-stopped
ports:
- "8080:8080"
# Recommended: mount your config.yaml for server configuration
volumes:
- ./server/config.yaml:/app/server/config.yaml:ro
# Only override these if needed
environment:
LOCATION: "Dublin, IE" # Optional: override location
SERVER_PORT: "8080" # Optional: override port
Then start the server:
docker compose up -d
Run with Docker (single command)
docker run -d --restart unless-stopped \
-p 8080:8080 \
-e WEATHER_SERVICE=accuweather \
-e WEATHER_APIKEY=<your_key> \
-e GOOGLE_APIKEY=<your_key> \
-e GOOGLE_STATICMAPS_MAPID=<your_map_id> \
-e LOCATION="Dublin, IE" \
-e SERVER_TIMEZONE="Europe/Dublin" \
ghcr.io/chrisjtwomey/inkplate10-weather-cal-server:latest
Run from Source
See server/README.md.
2. Client (Firmware) Setup
Pre-built firmware binaries in the releases are SD-card firmware only.
Recommended path (pre-built firmware):
- Place a
config.yamlin the root of your SD card (see doc/config.yaml for an example). - Download
firmware.binfrom the latest release. - Flash it using
esptool.py:
pip install esptool
esptool.py --chip esp32 --port /dev/ttyUSB0 write_flash 0x10000 firmware.bin
- Insert the SD card and boot the device. The firmware reads
config.yamlfrom SD card on startup.
No SD card setup:
If you want firmware configured via src/defaults.cpp (no SD card), build from source instead. See CONTRIBUTING.md.
Notes:
- SD card support is intended for SolderedElectronics Inkplate 10 hardware.
- Older E-Radionica Inkplate 10 boards can have higher deep-sleep drain when SD card is enabled.
- Using a different e-paper device? See doc/custom-board.md for how to implement the
IBoardinterface and swap it in.
Background
Back in late 2021, I came across a project called MagInkCal that uses a Raspberry Pi Zero WH to retrieve events from a Google calendar and display them on an e-ink display. One of the drawbacks of the project however is power consumption and I thought of porting the project over to use the ESP32 platform instead. What resulted eventually was this project, though I decided to focus on more of a weather station aspect rather than Google calendar events.
I recommend taking a look at the author's other project MagInkDash which has a similar architecture to this.
How it Works
Both a server and client are required. The main workload is in the server which allows the client to save power by not generating the image itself.
Client (Inkplate 10)
- Wakes from deep sleep and attempts to connect to WiFi.
- Attempts to get current network time and update real-time clock.
- (Optional) Attempts to connect to an MQTT topic to publish logs. This allows you to see what the ESP32 is doing without needing to monitor the serial connection.
- Downloads the PNG image the server is hosting.
- (Optional, SD card only) Writes the downloaded PNG image to SD card.
- Reads the PNG image and writes it to the e-ink display.
- Returns to deep sleep for the number of seconds the server dictated via
X-Next-Refresh-Seconds. If the server doesn't provide a value, backs off exponentially (2 min → 6 min → … → 24 h) until it does.
Features:
- Ultra-low power consumption:
- approx 24µA in deep sleep
- approx 120mA awake
- approx 10-20 seconds awake time daily
- 1 - 2 years+ of battery life using a 2000mAh cell.
- Real-time clock for precise sleep/wake times.
- Daylight savings time (DST) handled entirely server-side — the server sends seconds-until-next-refresh so the client never needs to reason about timezones for scheduling.
- Can publish to a MQTT topic for remote logging.
- Renders messages on the e-ink display for critical errors (battery low, WiFi timeout, etc.). The previous calendar image stays visible behind the banner (cached in SPIFFS on first successful refresh).
- Exponential back-off on server failures: 2 min → 6 min → 18 min → … → 24 h cap, resetting on the next successful server-dictated refresh.
- Optional: SD card support for loading client config from
config.yamlwithout reflashing (see doc/config.yaml).
Power Consumption
See doc/power-consumption.md for details on power consumption and battery performance.
Server
See server/README.md for full server documentation.
Bill of Materials
-
Inkplate 10 by Soldered Electronics ~€150
The Inkplate 10 is an all-in-one hardware solution. It has a 9.7" 1200x825 display with integrated ESP32, real-time clock, and battery power management. You can get it directly from Soldered Electronics or from a UK reseller like Pimoroni.
-
Optional: 2 GB microSD card ~€5
Note: SD card support is disabled by default. Use build flag
USE_SDCARDto enable.Only needed if you want to load client config (
config.yaml) from the card without reflashing. Image caching for error banners is handled automatically via internal SPIFFS flash. -
3000mAh LiPo battery pack ~€10
Any Lithium-Ion/Polymer battery with a JST connector. Some Inkplate 10s are sold with a 3000mAh battery (~1-2+ years of life). See doc/power-consumption.md for real-world numbers.
-
CR2032 3V coin cell ~€1
Powers the real-time clock during deep sleep.
-
A server to run the image generator
Anything that can run Docker or Python 3.10+. A Raspberry Pi Zero 2W is a good low-power option; any always-on computer works.
-
Black photo frame 8"x10" ~€10
The mount needs to fit an 8"x10" frame but expose only the e-ink area (~5.5"x7.5").
Client Configuration
The client (Inkplate 10) configuration can be loaded from config.yaml on the SD card root when firmware provided in the latest release. Use doc/config.yaml as the starting template.
There is on-firmware defaults in src/defaults.cpp. These are are compiled into the binary. Any missing keys from config.yaml will fall back to the firmware defaults.
If you are not using an SD Card to configure the client, see Choose your configuration mode for how to build firmware to only use defaults.cpp.
Parameters
| Key | Type | Default (firmware) | What it does |
|---|---|---|---|
server.url |
string | http://YOUR_SERVER_HOST:8080/calendar.png |
Initial image URL to fetch (/today.png, /tomorrow.png, /hourly.png, /daily.png). |
server.retries |
integer | 3 |
Number of retry attempts for image download and draw operations. |
server.default_refresh_seconds |
integer | 3600 |
Fallback sleep interval in seconds when the server has not provided X-Next-Refresh-Seconds. |
wifi.ssid |
string | XXXX |
WiFi SSID used by the client. |
wifi.pass |
string | XXXX |
WiFi password used by the client. |
wifi.retries |
integer | 10 |
Number of WiFi connection attempts before timeout. |
ntp.host |
string | pool.ntp.org |
NTP server host for RTC synchronization. |
ntp.timezone |
string (IANA timezone) | Europe/Dublin |
Local timezone used for client-side timestamps/logging. |
mqtt_logger.enabled |
boolean | false |
Enables client MQTT logging. |
mqtt_logger.broker |
string | localhost |
MQTT broker host for client log publishing. |
mqtt_logger.port |
integer | 1883 |
MQTT broker port. |
mqtt_logger.clientId |
string | inkplate10-weather-client |
MQTT client ID used by the device. |
mqtt_logger.topic |
string | mqtt/eink-cal-client |
MQTT topic used for client log publishing. |
mqtt_logger.retries |
integer | 3 |
Number of MQTT connection retries before timeout. |
Example
server:
url: http://YOUR_SERVER_HOST:8080/today.png
retries: 3
wifi:
ssid: YOUR_WIFI
pass: YOUR_WIFI_PASSWORD
retries: 6
ntp:
host: pool.ntp.org
timezone: Europe/Dublin
mqtt_logger:
enabled: false
broker: localhost
port: 1883
clientId: inkplate10-weather-calendar
topic: mqtt/inkplate10-weather-calendar
retries: 3
For a fully annotated example, see doc/config.yaml.
License
All code in this repository is licensed under the MIT license.
Weather icons by lutfix from www.flaticon.com.



