From a510673221fe872a75ed1f868ba6d3a1a762615e Mon Sep 17 00:00:00 2001
From: uvok
Date: Sun, 10 Aug 2025 18:29:01 +0200
Subject: Finish article
---
_drafts/building-an-epaper-badge.md | 260 ++++++++++++++++++++++++++++++------
1 file changed, 222 insertions(+), 38 deletions(-)
(limited to '_drafts/building-an-epaper-badge.md')
diff --git a/_drafts/building-an-epaper-badge.md b/_drafts/building-an-epaper-badge.md
index 866e0e8..43cd56b 100644
--- a/_drafts/building-an-epaper-badge.md
+++ b/_drafts/building-an-epaper-badge.md
@@ -14,32 +14,33 @@ Two weeks before [Awoostria]({% post_url 2025-07-30-awoostria-con-report %}):
So it begins… The story how I built myself an ePaper badge.
-Actually, the story begins way earlier, when I still had a physical Raspberry
-Pi running stuff in my home network. I wanted to tinker around a bit and bought
-myself a Waveshare ePaper. These are simple black-and-white displays which
-maintain their content when the power switches off. They are also inside eBook
-readers.
+Actually, the story begins way earlier (unrelated, when I still had a physical
+Raspberry Pi running stuff in my home network). I wanted to tinker around a bit
+and bought myself a Waveshare ePaper. These are simple black-and-white displays
+which maintain their content when the power switches off. They are also inside
+eBook readers.
-Some years ago I wanted to build myself an electronic door sign for the EAST
-convention with these, and I wanted to go "as minimal as possible". I wanted to
-use one of the MSP430 controllers I had laying around, and I wanted to switch
-motives via MiFare RFID transponders (using an MFRC5xx reader). Work on that
-development never really took off.
+This was also when I wanted to build myself an electronic door sign for the
+EAST convention with these, and I wanted to go "as minimal as possible". I
+wanted to use one of the MSP430 controllers I had laying around, and I wanted
+to change motives via MiFare RFID transponders (using an MFRC5xx reader). Work
+on that development never really took off. (Ugh, too little flash for all the
+pictures, too much stuff to code myself!)
## Requirements
So this time, I simply said "fuck it", and threw an ESP32 on the problem.
Also, I decided to use [PlatformIO](https://platformio.org/), a
toolchain/SDK/library manager. I started with the Arduino framework, which is…
-pretty wasteful in terms of resources (Flash/RAM/…), but speeds up development
-significantly.
+pretty wasteful in terms of resources (Flash, RAM, CPU etc.), but speeds up
+development significantly.
I had a simple ESP32 devboard, and one of the Waveshare modules, and started
coding.
…
-But wait, what to I even want to achieve? Well, I wanted to "mood badge", i.e.
+But wait, what do I even want to achieve? Well, I wanted to "mood badge", i.e.
show my current mood with funny pictures. I couldn't get one on previous
conventions, so I was just gonna build one myself.
@@ -64,7 +65,8 @@ support *some* Waveshare displays. The problem with Waveshare displays is, they
don't disclose which display controller they use. So it's kind of an
trial-or-error procedure. Or rather, you can look at their example code, figure
out which commands they are using, and compare what commands GxEPD2 uses.
-That's a bit cumbersome.
+That's a bit cumbersome. But still better than writing everything myself. Also,
+it supports graphics primitives!
## Get the picture on the display
@@ -76,13 +78,15 @@ but that makes it even more complicated, actually. Even when you don't use it,
refresh is slow.
So, you definitely can't throw a color picture on the display, nor a monochrome
-one. There are displays which support a few gray-levels, though.
+one. There are displays which support a few gray-levels, but I don't have one
+of those.
So. What to? The solution is "dithering". I.e. you trick your eye into
perceiving grey by having clusters of black and white pixels. There is some
-background to dithering (see below), but I simply used either GIMP, the
-Floyd-something algorithm, or one of the "ordered" modes of ImageMagick. It was
-a bit of trial-and-error and seeing-what-looks-best.
+technical background to dithering (see the Reference section), but I simply
+used either GIMP with the Floyd-something algorithm, or one of the "ordered"
+modes of ImageMagick. It was a bit of trial-and-error and
+seeing-what-looks-best.
The result, then, looks like this:
@@ -100,26 +104,30 @@ rotation first, though.
## How to attach the badge to myself
I have a Waveshare module/PiHat (which is too heavy), and a simple "ePaper
-sheet" including a housing for it. The housing can only fit the ePaper, not the
-devboard, though. Also, it would be too cumbersome to attach to the devboard -
-loose wires! So, at this point, I decided to switch from the prototyping
-platform onto something better.
+sheet" including a plastic housing for it. The housing can only fit the ePaper,
+not the devboard, though. Also, it would be too cumbersome to attach to the
+devboard - loose wires! So, at this point, I decided to switch from the
+prototyping platform onto something better.
Fortunately, Elecrow provides a
-[CrowPanel](https://www.elecrow.com/crowpanel-esp32-2-9-e-paper-hmi-display-with-128-296-resolution-black-white-color-driven-by-spi-interface.html),
+[CrowPanel](https://www.elecrow.com/wiki/CrowPanel_ESP32_E-paper_2.9-inch_HMI_Display.html),
which is exactly what I need. It has a display, a built-in ESP32 controller, a
housing, and even some switches! As a huge plus, they even specify which
display controller they use. I had to try some of the GxEPD2 display classes,
but finally found one working.
I decided to glue magnets onto the housing, and attach the display via magnets
-on the inner side of my shirt &emdash; not ideal. I positioned the magnets in
+on the inner side of my shirt — not ideal. I positioned the magnets in
the (vertical) middle of the housing, so it wobbles and is not readable. Also,
I accidentally washed the shirt after Awoostria with the magnets still sticking
-inside &emdash; and now there's a hole in it. :( This problem is still
+inside — and now there's a hole in it :( . This problem is still
unsolved. I can kinda attach the magnets to the housing screws at the top, but
that's not *very* stable.
+When starting to work with the Elecrow display, at first nothing would work.
+When I looked at their example code I noticed there's an additional power pin
+that needs to be toggled.
+
## Set what is displayed
@@ -129,10 +137,10 @@ something "more direct", so I added the
of coding, I added a service and some characteristics, so the available motives
could be read via BLE. Also, the motive could be selected via another
characteristic. I started writing the characteristic with *nRF Connect For
-Mobile*, but started writing an app later.
+Mobile*, but started writing an app [later](#theapp).
Actually, the switch-selection was a bit troublesome. Redrawing the whole
-display takes around 2 seconds &emdash; but that is not acceptable when
+display takes around 2 seconds — but that is not acceptable when
navigating the presets one-by-one. By looking at the API, I found out you can
select a "partial region".
@@ -142,14 +150,14 @@ vertical-center-right of the display with the mood text. The picture stays the
same, but the text reflects the selected mood. The selection is confirmed my
pressing the rotary switch.
-This is still not ideal. The first update must be a full one, and I don't save
-the selected preset in NVS &emdash; I don't want to destroy the flash by
-hundreds/thousands of write cycles. I don't have a solution to this, yet. Maybe
-I'm gonna integrate an microSD card (there's a slot for that!n the CrowPanel).
-I'm gonna research a good wear-levelling file system for that. Probably not
+This is still not ideal. The first update after power-up must be a full one,
+and I don't save the selected preset in NVS — I don't want to destroy the
+flash by lots of write cycles. I don't have a solution to this, yet. Maybe I'm
+gonna integrate an microSD card (there's a slot for that in the CrowPanel).
+I'm gonna research a good wear-levelling file system for that. Probably not
FAT. That doesn't need to be readable on the PC. (And even if, simple stuff
-can be written in FUSE). Drawing the first motive on power-up would also be an
-option, but I don't like it that much.
+can be written in FUSE). Alternatively, drawing the first motive on power-up
+would also be an option, but I don't like it that much.
## Power saving
@@ -170,7 +178,15 @@ why!
Apropos of powering: The badge is normally unpowered and only powered if I need
to change the motive. I don't want to have an USB cable hanging on me the whole
-time!
+time! Using a battery might be an option, but I had problems with mismatched
+connectors — the Elecrow display doesn't have a standard JST connector
+like the LiPo battery I bought (Li-Ion might even be the safer option? I have
+no clue about this stuff. With a quick search, I only found these cyclindric
+Li-Ion batteries and have no idea how I would connect them). The badge seems to
+have a "mini" variant of that connector.
+
+For the time being, I power it with a USB powerbank, but this I still consider
+an unsolved problem.
## The app
@@ -1020,9 +1036,177 @@ settled for Flutter.
Again, this was completely new to me. I started off with a popular BLE library,
which turned out to be an unfortunate choice, as Linux support had a few
quirks. That was probably a good thing in hindsight, as this made me abstract
-away the BLE stuff in implementation classes, and only use the abstract base
-classes in the code. Well, you can see what the code looks like, I linked my
-repo below.
+away the BLE stuff in implementation classes, so I could easily try out
+different libraries, and only use the abstract base classes in the code. Well,
+you can see what the code looks like, I linked my repo below. This is what the
+motive selection looks like:
+
+
## Resources
--
cgit v1.2.3