At the time of this writing, my SO lives far away. While video conferencing can go some distance to making up for distance, its heavy-weight, demanding active engagement on both ends, making it more of a scheduled affair. Wanting something more akin to a note on the table (a physical, tangible object that indicates recent, deliberate thoughts of them), I cobbled together an interactive low-resolution display “lamp”. The project seems to have had its intended effect; we have been using it for years and find it to be an appreciated, positive presence in our homes.
All of the code for this project is available at https://github.com/AcmeTensorToys/esp-lua_lamp. Technical details are available in https://github.com/AcmeTensorToys/esp-lua_lamp/blob/main/README.rst; this page concerns itself more with the why and what.
This project is absolutely inspired by Filimin, but I wanted a little more detail at the ends and might suffer a little from NIH.
For maximal amusement, the project has two, dramatically different, pieces of hardware involved. We’ll begin with the more interesting piece, which resides in my SO’s house, and will leave my local device as an afterthought.
The lamp hardware properly consists of a waterproof box with a 4x8 grid of SMT addressable LEDs and a number of capacitive touch sense contacts. For amusement, it contains really quite an excessive LiPo battery and a water-proof-able power/USB connector. Again, the complete BOM is available at the link above. In practice, here’s what it looks like:
Overhead view with lid removed (
high resolution); this is displaying the
Semi-side view with lid on (
high resolution); this has all LEDs (
On the left is the CAP1188 touch sensor module and its breakout board; the copper tape contacts traverse the box’s seal and provide the user input events.
On top is the ESP8266 Feather HUZZAH module and USB micro breakout for the external power and control feed.
And below that in the picture, of course, is the display.
Underneath both the HUZZAH and display is a passive routing board and, further below, the LiPo battery.
Here are some examples of the device’s display, as rendered by a shoddy software approximation.
(In particular, these were made by capturing the XPM files the software
renderer makes, using
sxpm -nod -o - $i.xpm | convert - $i.png and
cwebp -lossless -o $i.webp $i.png, and then stitching them all together
webpmux -loop 0 -frame 1.webp +nnn -frame ....)
The system typically limits its brightness to
0F0F0F so as to not blind
the user. Seriously, those things can light up a room. There is, sadly,
also some as-yet-undiagnosed power glitch when sourcing a large amount of
current to the display that causes the system to lock up.
INformative SUrrogate Light And Timing Optional Remote (INSULATOR)¶
I thought I would probably be content speaking the raw MQTT messages from the command line (and indeed, so far, seem to be), but they’re less fun to read on a screen than to see effect some change in the real world. Rather than clone the LAMP hardware for my end, I put some WS2812 LEDs inside an old telegraph insulator (three waterproofed “pixels” fit in the old mounting socket snugly). Appropriately, the current insulator in use is purple glass. When a message arrives from the LAMP, the color is extracted and fed to the LEDs. The name of the drawing/animation that was selected on the LAMP is then announced in Morse code before the LEDs are left steady-on.
The software is running on the PiDP8 that lives on my desk; a Digispark ATTiny85 software-USB device running the LittleWire firmware serves as the gateway, since all the Pi’s I/O lines are used by the PiDP8 device. (And also makes the insulator “portable”; I’ve brought the hardware and run the same software on my laptop when traveling, for example).
There’s also an extremely hackish re-implementation of the LAMP framebuffer that perches itself next to my laptop’s status bar and runs the same animation/drawing code, giving me another view into the system when I am not at home. This implementation was used to make the renderings above.