Firmware for an ESP32-C6 based E-Paper display device, featuring BLE provisioning, AWS IoT connectivity, and OTA updates. We use the firmware in our paperlesspaper OpenPaper 7. Check paperlesspaper Github for hardware source files.
- Microcontroller: ESP32-C6-DevKitM-1
- Display: Spectra 6 7.3 (EL073TF1)
- Sensors: KXTJ3-1057 Accelerometer
- Other: Battery, Charger circuit (see Hardware Settings below)
- IDE: Visual Studio Code
- Extension: PlatformIO
- Framework: Arduino (via PlatformIO)
This project is released under the GNU General Public License v3.0 (GPL-3.0). See the LICENSE file for the full license text.
-
Clone the Repository
git clone <repository-url> cd epaper-espc6-firmware
-
Environment Configuration Create a
.envfile in the root directory with the following variables:ENV_OTA_URL="https://your-ota-server.com/firmware.bin" ENV_OTA_URL_DEV="https://your-dev-ota-server.com/firmware-dev.bin" ENV_WIFI_PW_DEPLOY="default_wifi_password" ENV_WIFI_SSID_DEPLOY="default_wifi_ssid" ENV_AWS_IOT_ENDPOINT="your-aws-iot-endpoint.iot.region.amazonaws.com"
-
AWS IoT Certificates & SPIFFS The device requires AWS IoT certificates to connect to the cloud service. These are stored in the SPIFFS filesystem.
ℹ️ Important Note on Certificates: Device-specific AWS IoT certificates are not included in this open repository for security reasons. Certificates are exclusively available directly via paperlesspaper Customer Support.
-
Naming Convention: The certificates must be named using the device's unique ID, which is
epd7-followed by the MAC address (hex, uppercase, no colons).- Example MAC:
A0:B1:C2:D3:E4:F5-> UID:epd7-A0B1C2D3E4F5 - Private Key:
epd7-A0B1C2D3E4F5.key - Certificate:
epd7-A0B1C2D3E4F5.crt
- Example MAC:
-
Upload via PlatformIO:
- Create a
datafolder in the project root if it doesn't exist. - Place your renamed
.keyand.crtfiles in thedatafolder. - Run the PlatformIO task:
Platform->Upload Filesystem Image.
- Create a
-
Upload via Web-UI:
- Open the Web Flasher UI (under Firmware Update -> USB-Kabel (COM-Port)).
- Use the "SPIFFS / Zertifikat per USB übertragen (.bin)" button to flash a pre-packaged certificate
.binimage obtained from Support.
Warning: These certificates are stored in the SPIFFS partition. If you change the partition table or erase the flash, the certificates will be lost, and the device will no longer connect to the cloud.
-
-
Build and Upload Firmware
- Run the PlatformIO task:
General->Upload.
- Run the PlatformIO task:
- Web Serial Flashing: Flash official/custom firmware
.binfiles or SPIFFS certificate images directly in your browser over USB-C. - Web Serial Debug Monitor: Open a live Web Serial terminal at 115200 baud directly in the Web UI to monitor UART debug logs without external software.
- Web-BLE Image Upload: Wirelessly preview, dither (Floyd-Steinberg, Atkinson, Sierra 2, etc.), auto-optimize, and send images directly to the frame.
- AWS IoT: This firmware heavily relies on AWS IoT Core for activation, status updates, and image retrieval. Ensure your AWS account is set up and limits/costs are monitored.
- BLE Advertising: The device advertises via BLE for provisioning and OTA updates. Advertising restarts automatically after a client disconnects.
- Deep Sleep: The device enters deep sleep to save power. It wakes up via:
- Timer (configurable via MQTT).
- Accelerometer (motion).
- Button press.
The ESP32-C6 firmware exposes a GATT server (implemented via NimBLE) primarily for WiFi onboarding / provisioning and OTA firmware updates.
- Advertised Device Name: Matches the unique device ID (e.g.
epd7-A0B1C2D3E4F5orepd13-A0B1C2D3E4F5). - Advertised Service UUIDs:
- Device Data Service (
7f74170e-7b0e-11ed-a1eb-0242ac120002) - WiFi Configuration Service (
0515c086-7b0c-11ed-a1eb-0242ac120002) - E-Paper Settings / Firmware Update Service (
10000000-0000-0000-0000-000000000001)
- Device Data Service (
- When BLE is Active:
- On first boot or when no valid WiFi credentials exist in flash.
- When WiFi connection fails and the device was woken up via button (
buttonWake). - BLE terminates automatically after successful WiFi connection or when the timeout is reached (device returns to deep sleep).
| Service | Service UUID | Characteristic | Characteristic UUID | Properties | Format / Data Type | Description & Function |
|---|---|---|---|---|---|---|
| Device Data Service | 7f74170e-7b0e-11ed-a1eb-0242ac120002 |
WiFi Connected Status | 4c578d4c-7b0e-11ed-a1eb-0242ac120002 |
READ |
uint8 (0 or 1) |
Connection state (1 = connected / connecting, 0 = disconnected / failed). Set to 1 during the connection attempt, reverts back to 0 if connection fails after 10s. Remains 1 upon success until BLE shuts down. |
| WiFi Scan Results | 5131a3fc-7b0e-11ed-a1eb-0242ac120002 |
READ |
UTF-8 String (Descriptor 2904) |
List of scanned networks in the format SSID´RSSI´´SSID´RSSI´´... (max. ~460 bytes). |
||
| WiFi Configuration Service | 0515c086-7b0c-11ed-a1eb-0242ac120002 |
WiFi SSID | 090b0ef2-7b0d-11ed-a1eb-0242ac120002 |
READ, WRITE |
UTF-8 String (Descriptor 2904) |
Target WiFi SSID. Writing sets the SSID for connection and flash storage (max. 35 chars). |
| WiFi Password | a62eed84-7b0d-11ed-a1eb-0242ac120002 |
READ, WRITE |
UTF-8 String (Descriptor 2904) |
Target WiFi Password (max. 65 chars). Writing both SSID and password triggers immediate WiFi connection. | ||
| E-Paper & Firmware Update Service | 10000000-0000-0000-0000-000000000001 |
Upload Data (OTA Chunks) | 10000003-0000-0000-0000-000000000001 |
WRITE, WRITE_NR |
Binary ([4-Byte CRC32 LE] + [Payload]) |
Firmware OTA data chunks. Each chunk begins with a 4-byte little-endian CRC32 of the payload, checked before copying into the 19.2 KB RAM buffer. |
| Upload Command / Status | 10000004-0000-0000-0000-000000000001 |
READ, WRITE |
READ: uint16 LE (Buffer Pos or 0xFFFF on error)WRITE: String Command |
Controls OTA update lifecycle via commands: START_FW, FLUSH, CLEAR, END_FW. |
- Scan & Discover: Scan for BLE devices with name prefix
epd7-orepd13-. - Connect: Establish GATT connection to the device.
- (Optional) Read Nearby Networks: Read characteristic
5131a3fc-7b0e-11ed-a1eb-0242ac120002to retrieve the list of detected SSIDs and RSSI values (separated by´´). - Write Credentials:
- Write target SSID as UTF-8 string to
090b0ef2-7b0d-11ed-a1eb-0242ac120002. - Write target Password as UTF-8 string to
a62eed84-7b0d-11ed-a1eb-0242ac120002.
- Write target SSID as UTF-8 string to
- Verify Connection & Status Behavior:
- Once both SSID and password are received, the firmware sets
4c578d4c-7b0e-11ed-a1eb-0242ac120002to1and attempts to connect for up to 10 seconds (WiFi.waitForConnectResult(10000)). - If connection succeeds: The characteristic remains
1. Credentials are saved permanently to Flash (EEPROM addresses 0 & 40), and the ESP32 disables BLE (BleInit(..., false)). - If credentials are wrong / connection fails: The firmware disconnects from WiFi, clears the temporary password buffer, and resets the status characteristic back to
0. The device remains in BLE advertising mode to allow a retry. - Client Tip: Clients should poll the status characteristic for 10–12 seconds. If it drops back to
0, prompt the user to re-enter credentials. If it stays1(or the BLE connection closes upon successful handover), provisioning succeeded.
- Once both SSID and password are received, the firmware sets
(A ready-to-use Python client implementing this validation logic is provided in testbench/ble_provisioner.py.)
- Start Update: Write command string
"START_FW"to10000004-0000-0000-0000-000000000001. This initializes the OTA partition update and allocates an internal 19,200-byte RAM buffer. - Stream Binary Chunks: Send chunks to
10000003-0000-0000-0000-000000000001. Each packet must be prefixed with a 4-byte CRC32 (little-endian) of the chunk payload. The firmware verifies the CRC before accepting the bytes into the buffer. - Flush Buffer: Periodically send command string
"FLUSH"to10000004-...before the 19.2 KB buffer fills up, writing buffered bytes to flash. - Finish Update: Send command string
"END_FW"to10000004-.... Remaining bytes are written, the firmware binary is validated, and the ESP32 automatically reboots into the new firmware. If validation fails, reading10000004-...returns0xFFFF.
0-39: WiFi Name40-105: WiFi Password140: Reconnect Count150: File Version160: Activated Flag170: Activation Counter190: Display Revision Store200: WiFi Lost State210: Sleep Time220: Dispay Orientation Store500+: Settings Store
- Charger: Safety TMR 4h, 4-cell intermittent.
- Reset: 5+ presses
- OTA Force (Dev Firmware): 3-4 presses
- Boot Mode: Hold the small button, short press the reset button (big button) while holding the small button, then release the small button.
