Jakub Jirůtka  |  OpenAlt 2025

Electronic door signs

at FEL CVUT

System engineer and developer

Works at FEE CTU in Prague

FOSS developer & contributor

Alpine Linux developer

$~ whoami

  Source: https://lezebre.lu/en/sticker-simons-cat-claws/

@jirutka

@jakub@jirutka.cz

jakub@jirutka.cz

  Source: ChatGPT 5 (DALL-E 3)

Source: ChatGPT 5 (DALL-E 3)

Cat by: ChatGPT 5 (DALL-E 3)

  • expensive updates (paper, ink, and human labour)
  • doesn’t display non-periodic events
    • block teaching
    • exams
    • reservations
  • “what’s happening now” lookups are not O(1)

Limitations

  • display complete, up-to-date information
    • lessons, exams, reservations, study room
  • display what’s happening now / in <15 min + today
  • remote control
  • two power options:
    • over Ethernet (available in newly renovated rooms)
    • battery → LCD display is not an option
  • sufficiently large and legible display
  • frame printable on a standard 3D printer (e.g. Prusa MK3)

What we wanted

First prototypes

First lessons learned

  • 7.5” displej is too small
  • standard PoE (Power-over-Ethernet) is problematic:
    • PoE converters are quite large
    • RJ45 is quite large
    • PoE emits a lot of heat (48 V → 5 V)
    • Ethernet cable is firm
    • standard electrical installation box is small
  • gesture control doesn’t work well with e-ink
    • long delay is confusing for users

Source: ChatGPT 5 (DALL-E 3)

Cat by: ChatGPT 5 (DALL-E 3)

  • 10.2” e-ink, 2-bit grayscale
  • ESPink v2 (ESP32 board)
  • (10 Ah LiPol battery)
  • custom firmware
  • custom 3D printed frame

Final version

  • ESP32-WROOM-32 16 MiB
    • Xtensa dual-core 32-bit LX6 240 MHz
    • 448 kiB ROM / 520 kiB SRAM / 16 MiB SPI flash
    • 802.11b/g/n (WiFi), Bluetooth V4.2 & BLE
  • EPD connector (SPI)
  • USB-UART converter
  • LDO regulator (3.7–8 V)
  • battery charger
  • USB-C for programming and power
  • open hardware
    • https://github.com/LaskaKit/ESPink

ESPink v2

Power Supply

Battery

  • 10 Ah LiPol
  • last for 6–12* months
  • can be installed anywhere

Power over Ethernet

  • passive PoE 7 V
  • last “forever”
  • requires Ethernet 

Frame

Frame

Inspired by Vlad Waas’ 7.5” Bauhaus frame for Živý obraz.

  • reverse-engineered from STLs in FreeCAD
  • scaled for 10.2” display
  • two snap fits replaced with screw clips
  • adapted for wall mounting
  • added spacer corners
  • added side reset switch
  • many small adjustments

Frame (assembled)

Top part (bottom view)

Bottom part (top view)

Middle part

Architecture

“Timetable API”

Door Signs Controller

Grafana

Prometheus

MQTT broker

HTTP server

NTP server

HTTPS

MQTT

HTTPS

NTP

MQTT

firmware → (OTA update)

HTTPS

PNG, settings →

 telemetry, logs

metrics

Energy saving

Controller sends the image to be displayed, along with a timestamp indicating when the next update is expected.

 

ESP wakes up, renders the image, sets the timer and goes into deep sleep.

  • in C/C++
  • based on Arduino and ESP-IDF
  • used libraries:
    • jirutka/GxEPD2_4G 
      • Arduino display lib for SPI e-inks with 2-bit grayscale
      • fork with support for GDEM102T91
    • pngle  stream-based portable PNG decoder
    • PubSubClient – not so good MQTT client for Arduino
    • ArduinoJson – JSON (de)serializer for Arduino/C++

Firmware

Monitoring

Source: ChatGPT 5 (DALL-E 3)

{
  "ts": 1761483972,
  "wakeTs": 1761483960,
  "rstTs": 1760803498,
  "rstRsn": "SW",
  "nextWakeTs": 1761494760,
  "awake": 2336,
  "chip": "ESP32-D0WD-V3",
  "fw": { "ver": "0.2.0", "size": 1018608, "freeSpace": 1310720 },
  "disp": { "w": 480, "h": 800, "clr": "4g" },
  "heap": { "total": 273172, "free": 180408, "minFree": 168848, "maxAlloc": 110580 },
  "net": {
    "mac": "D4:8C:49:CA:FF:EE",
    "ipv4": { "addr": "192.168.123.42", "mask": 24, "gw": "192.168.123.1" },
    "dns": [ "192.168.123.1" ],
    "iface": "wlan",
    "ssid": "fel-XXX",
    "bssid": "08:96:AD:CA:FF:EE",
    "chan": 1,
    "rssi": -72
  },
  "battVolt": 4.22,
  "battPct": 100
}

Telemetry from door signs

Grafana

Grafana

Grafana

Grafana

Grafana

Fuckups Challenges

  • ESP brownout
  • RTC on ESP32 is inaccurate
  • 5 V over PoE wasn’t enough → 7 V
  • WiFi fast scan
  • PubSubClient doesn’t support QoS ≥1

Why not “Živý obraz”?

We have a specialised use case with different requirements.

Also…

  • firmware code-quality 🤢
  • custom image format 🤨
  • no support for observability (telemetry, remote logging)
  • server is closed-source(?)

Bill of Material

  • ESP board ESPink v2 (with IPEX) by LaskaKit.cz
  • 10.2" e-ink display GDEM102T91
  • (LiPol battery 10 000 mAh)
  • antenna 3dB 2.4GHz with IPEX
  • microswitch MSW-21
  • capacitor 330uF/6.3V
  • screws and dowels
  • 3D printing filament for our custom case
Item
ESP board ESPink v2 by LaskaKit.cz
10.2" e-ink display GDEM102T91
(LiPol battery 10 000 mAh)
microswitch MSW-21
capacitor 330uF/6.3V
screws and dowels
3D printing filament

Bill of Material

Item Price (CZK)
ESP board ESPink v2 by LaskaKit.cz 398
10.2" e-ink display GDEM102T91 2 020*
(LiPol battery 10 000 mAh) 230*
microswitch MSW-21 6.5
capacitor 330uF/6.3V 1.6
screws and dowels 7.4
3D printing filament (253 g) 84
Total 2748

What next?

  • optimise WiFi – full scan only on first connection
  • replace PubSubClient
  • cache logs in Flash memory
  • publish 3D models for the frame
  • publish firmware
  • deploy on more faculties, universities…?

Q&A

  Source: ChatGPT 4 (DALL-E 2) trained on art stolen from the Internet

Electronic door signs

By Jakub J.

Electronic door signs

  • 22