From 669f3bf7b63a50d09b4004f405697eb6d227c40f Mon Sep 17 00:00:00 2001
From: uvok
Date: Sun, 10 Aug 2025 18:31:06 +0200
Subject: Publish!
---
_drafts/building-an-epaper-badge.md | 1217 -----------------------------------
1 file changed, 1217 deletions(-)
delete mode 100644 _drafts/building-an-epaper-badge.md
(limited to '_drafts/building-an-epaper-badge.md')
diff --git a/_drafts/building-an-epaper-badge.md b/_drafts/building-an-epaper-badge.md
deleted file mode 100644
index 39f3203..0000000
--- a/_drafts/building-an-epaper-badge.md
+++ /dev/null
@@ -1,1217 +0,0 @@
----
-layout: post
-title: Building an ePaper badge
-date: 2025-08-06 19:53 +0200
-lang: en
-categories: tech
----
-
-## Foreword
-
-Two weeks before [Awoostria]({% post_url 2025-07-30-awoostria-con-report %}):
-
-> Hey, I should build something for my Tinkering Projects Show And Tell panel!
-
-So it begins… The story how I built myself an ePaper badge.
-
-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.
-
-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, 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 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.
-
-This involves several sub-problems:
-
-* [Control the ePaper display](#control)
-* [Get the pictures on the display](#pic)
-* [Set what is displayed](#setdisp)
-* [Power-saving](#powersave)
-* [Attach the badge to myself](#attach)
-
-
-## Control the display
-
-Usually, you never talk to the displays themselves, but to a display
-controller. You talk to these via a digital interface, e.g. SPI. There are
-different display controllers with different command sets.
-
-But why bother with implementing this myself? There are ready-made libraries.
-For myself, I decided to use [GxEPD2](https://github.com/ZinggJM/GxEPD2). They
-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. But still better than writing everything myself. Also,
-it supports graphics primitives!
-
-
-## Get the picture on the display
-
-You can't just simply throw a JPEG onto the display. The display doesn't
-understand that. It only understands pixel data. Also, the display can only
-draw black and white pixels. I also have a display with yellow color support,
-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, 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
-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:
-
-
-
-Now, about the image format… GxEPD2 supports "XBitmaps", or XBMs, which are
-basically just a C array declaration, so you can GCC that file and throw in the
-array into the GxEPD2 function call. And voilá, it works. You need to set the
-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 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/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 — 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 — 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
-
-In addition to these switches, which allow choosing the motive, I wanted
-something "more direct", so I added the
-[NimBLE-Arduino](https://github.com/h2zero/NimBLE-Arduino) library. With a bit
-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](#theapp).
-
-Actually, the switch-selection was a bit troublesome. Redrawing the whole
-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".
-
-What I didn't mention yet, the text that shows the mood is drawn at runtime,
-not integrated into the picture. So, I simply update a region in the
-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 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). Alternatively, drawing the first motive on power-up
-would also be an option, but I don't like it that much.
-
-
-## Power saving
-
-I first measured the current and was shocked. The whole thing draws around
-80-100 mA. Not a big surprise, given that Arduino basically calls `loop()` over
-and over again.
-
-Using a bit of experimenting, and failing to cancel light sleep with a GPIO
-interrupt, I implemented power saving by using a timer-based light sleep (10
-ms, gives good user response) and reducing the CPU frequency to 80 MHz. And lo
-and behold, my USB current measuring equipment (resolution 10mA) showed 0 mA.
-Success.
-
-Actually, reducing the CPU frequency was a requirement! If I didn't do that,
-the CPU would constantly crash when entering or exiting light sleep. No idea
-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! 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 cylindrical
-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 power bank, but this I still consider
-an unsolved problem.
-
-
-## The app
-
-Writing the BLE characteristics with nRF Connect is all and well, but not
-really user-friendly. I didn't want to install the Android SDK, so I looked at
-cloud based development for a start. I found [MIT
-AppInventor](https://appinventor.mit.edu/). First, I was disgusted, because
-apparently they require Login with Google. But I found [an alternative
-way](https://code2.appinventor.mit.edu/) by which you simply get a
-"Passphrase-like" codeword you use for login.
-
-The graphical programming is unusual to me. I used Scratch shortly in the past,
-so it was not completely foreign. Actually, it was kinda fun coding this, in
-"event style", once I figured out how to to like stripping, list filtering,
-etc.
-
-
-
-This was good enough for a while, but then I decided I wanted to actually have
-the source code available. So I looked again at development options, and
-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, 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
-
-- [surma.dev about dithering](https://surma.dev/things/ditherpunk/)
-- [git repo with badge source code](https://git.uvok.de/espadge/)
-- [git repo with app source code](https://git.uvok.de/espadge-flutter/)
-
-
--
cgit v1.2.3