Homeboard: Versioning frames

Post by Nico Brailovsky @ 2025-03-23 | Permalink | Leave a comment

Since I've been fixing plenty of bugs, figured I should also start versioning my frame mount designs.

The Ikea-frame version should look something like this:

The design for this one lives here

You can download it an open it with Inkscape; remember to switch to outline mode in Inkscape, otherwise you're unlikely to see anything. The frames are designed for a laser engraver, and the cuts are about 1/100'th of a mm.

And the standalone vesion will hopefully look a bit less terrible than this, since this picture is from a few bug-revisions before:

The design for the standalone version:


Homeboard: A Hardware bug!

Post by Nico Brailovsky @ 2025-03-16 | Permalink | Leave a comment

I found my first hardware bug! Can you spot it? It's the big red circle:

The mmwave sensor was mounted too close to either the screen, or the power source (something I thought was a brilliant idea yesterday). Turns out that mounting it so close has an affect on this sensor: when the display is on, it blocks the sensor (and reads it as no-presence). When the display is off, for some reason the sensor picks it up as someone being present. This is bad, because on presence I turn the display on, and on vacancy off. I guess my living room put on a light show for my cats last night.

I suspect I could fix this in the firmware of the sensor, but that's pointless because I can't reverse engineer the sensor protocol anyway. What's the next best fix?

I moved the sensor out of the way, while I think of a better placement.


Homeboard: eInk display

Post by Nico Brailovsky @ 2025-03-15 | Permalink | Leave a comment

Homeboard gained a new form factor: slightly less crappy frame.

I now keep two Homeboards, one in my office -mostly for hacking- and one to display pictures. The one in my office didn't have a good space for the eInk display (spoiler alert: it still doesn't) making it awkward to see both the "real" display and the eink one. To fix this, I built a new mount based on a picture frame. This time all of the elements are mounted directly on the front frame (spoiler alert: this was a huge mistake), and I used transparent perspex material to cut it, so that all elements are visible (I do like this bit, the boards that make up Homeboard are quite pretty).

Mechanics

The build uses an Ikea picture frame, but replaces the front plate with my laser-cut front.

The back of the frame:

Some things I need to improve:


Homeboard: eInk display

Post by Nico Brailovsky @ 2025-02-23 | Permalink | Leave a comment

What's better than one display? Two displays, of course.

When I see a picture in my Homeboard, I often remember when and where I took it (photos are, after all, a form of exomemory), but not always. In wwwslide, my home slideshow service, I workaround this with a QR code: a small QR code is displayed in a corner of the image, and I can scan it to read the metadata of the picture being displayed. This is a good solution, but I'm not entirely happy with it.

Today, I added an eInk display to my Homeboard project. I can show picture metadata (and maybe even a QR code!) without taking up valuable picture real-estate. I chose an eInk display because they are easy to source and work with, relatively cheap, and require very little power (Homeboard is powered by PoE). Some day, I'm hoping to use it as an extra low-power mechanism to show actual homeboard info (a clock? weather? price of memecoins? The options are endless!)

I couldn't get all of the manufacturer's examples to work (especially the partial refresh), but it works well enough to display a thing rendered with Cairo. The original manufacturer's examples had a custom rendering library which was quite unnecessary; my version of lib-eInk gets rid of all the custom rendering code, and uses Cairo to create graphics. Here's an example:

struct EInkDisplay display = eink_init();
cairo_t cr = eink_get_cairo(display);
// Get display's surface
cairo_surface_t *surface = cairo_get_target(cr);
const size_t width = cairo_image_surface_get_width(surface);
const size_t height = cairo_image_surface_get_height(surface);
// Configure "pen"
cairo_set_source_rgba(cr, 0, 0, 0, 1);
cairo_select_font_face(cr, "Sans", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD);
cairo_set_font_size(cr, 20);
// Calculate text position
cairo_text_extents_t extents;
cairo_text_extents(cr, "Hola mundo", &extents);
double x = (width - extents.width) / 2 - extents.x_bearing;
double y = (height - extents.height) / 2 - extents.y_bearing;
// Draw
cairo_move_to(cr, x, y);
cairo_show_text(cr, text);
eink_render(display);
eink_delete(display);

Github repo here.


Sidenote: my multiline code rendering seems to be eating pointers for breakfast, so struct S* may be rendered as struct S. I should fix this.


Homeboard V1, bootstrap V2

Post by Nico Brailovsky @ 2025-02-16 | Permalink | Leave a comment

With ~most~ some of the bugs fixed in the industrial design, it's time to setup a second Homeboard. That way I can experiment on one, while the other shows pretty pictures. Because my computer is also a new install, it's now a good opportunity to document the full bootstrap process from an almost brand new and clean Ubuntu 24.04.

Bootstrap a new devenv

Bootstrap the OS

This article has been updated to work, but the gist of it is:

dtoverlay=vc4-kms-v3d
gpu_mem=128

Build things

Build harder things

Install services

The homeboard doesn't do much nowadays, only show images; once you reached this point, and if things build and run, your build environment and target are ready to use. Just a few more arcane spells and we're done:

The target should be ready for production, in only about 30 simple steps!

Appendix: it hangs!


Homeboard: Industrial Design (bonus: Inkscape)

Post by Nico Brailovsky @ 2025-02-09 | Permalink | Leave a comment

My Homeboard project has officially left its cardboard pizza phase. Almost:

The 2 or 3 pixels above show the first "industrial design" of the homeboard. Or at least the parts that "work". It's hanging from a wall, like a real picture frame. Unfortunately it has bugs, and all its guts are hanging from the top.

I spent some time working on a mount, cut with a laser engraver. The mount has two main pieces: a frame for the display, and a horizontal mount that can be hanged from a hook in the wall. The vertical display frame slots into the horizontal mount, meaning there is no flimsy glue holding expensive equipment: gravity does the job. There are some screws and Ls to give it a nice shape, but the main stress between the hook in the wall and the display is supported by the material strength, not by glue. All the cool electronics fit in a small box on top of the horizontal mount. Or at least that's the idea.

As nice as my design is, it has bugs: You can see in the picture I forgot to consider that wires, especially fat cables such as HDMIs, have physical properties, such as bend radius. Without a slot for wiring, the electronics that fit nicely on the top box in my drawing, actually protrude from the top. The ribbon cable was mirrored in my drawing, meaning a weird 180-degree twist was needed to fit the screen to the main board. The box itself doesn't lock, because the "teeth" are slightly misaligned. And the screw holes for the Raspberry Pi are about a quarter mm out of alignment.

Attached to this post is my SVG design, with theoretical bug-fixes for the problems (version 3, if anyone is counting). I haven't tried printing it yet, and I wouldn't be surprised if V4 is required too.

Image above shows the outline; clicking on it should open the original svg, which is probably mostly blank because vector laser cuts have 0.001mm strokes. Download and open with Inkscape to see it (you may need to change the view mode to outline, too).

Bonus: misc Inkscape tips

My experience with anything that has colors is zero, and I had to spend time learning how Inkscape works to build the design above. Seeing a mechanical design you have in your head come to life with a laser cutter is incredibly rewarding, and I can see myself embarking in more ambitious designs some day, when I have more free time. Here's a list of things I learned and should remember next time I'm using Inkscape:


Zigbee Boiler: bugfix addendum

Post by Nico Brailovsky @ 2025-01-07 | Permalink | Leave a comment

I came back from holidays with a mystery to solve: my automated heating system kept, for hours, trying to shut down heating. Why wasn't it turning off?

After a few weeks, once home (because my home automation has no inbound internet access, only message publishing to Telegram) the puzzle got more interesting: the logs said it was trying to shut heating down, however its state was never "on" in the first place. To top it off, the temp charts showed this: Crazy high spikes, as high as 25 degrees. Why did the system think it was off while the boiler was running?

I tried a few lines of investigation. Sometimes sensors misreport data, saying a room is 0, or Nan, or 50 degrees (C!), or some other unreasonable value, however those are filtered out. Maybe a bit flipped and the Zigbee name/alias is different, but no, I could control the boiler normally if I manually turned it on when it was off. It was like something else was controlling the device... and then I re-read my own article.

Turns out I never disconnected the original RF controller, I only added a new parallel one. I figured it'd be useful, should my Zigbee controller ever fail! Turns out I chucked the original RF control in a drawer, in a cold corner of my house where I have the heating off. In a cold week, the room where the controller was never reached the minimum temperature to turn the heating off, despite my careful network of sensors shouting "it's hot in here, turn it off".

Fun fact: I bought current sensor to detect when the boiler is on, but it doesn't match the Zigbee state. It was sitting in a drawer, next to the original RF controller. This would make a great fail of the week, too bad the Embedded Muse is no longer running.

I'm not looking forward to the gas bill next month, but at least my cats got to enjoy a balmy 24C winter break for a few weeks.


Homeboard: Wayland on X

Post by Nico Brailovsky @ 2024-10-28 | Permalink | Leave a comment

Besides cross-compiling to RaspberryPi, at times it's also useful to just run things locally. While faster than building on the target, the cycle of xcompile and deploy is still cumbersome for short sessions (i.e. when the target is usually offline, unpowered, and possibly lost somewhere in my house). For these situations, I found out I can run Wayland based apps on top of my X-based desktop, using Weston.

Weston is an implementation of Wayland. If you don't have it already, you can apt-get install weston. If you do this in an X based desktop, you can still run weston in a terminal, inside X.

Between Wayland on X and cross-compiling to RaspberryPi, I can test my fork (hack) of Swayimg for RaspberryPi Zero.


Crosscompiling to RaspberryPi Zero

Post by Nico Brailovsky @ 2024-10-12 | Permalink | Leave a comment

Homeboard continues progressing, albeit at a snail pace. Using a RaspberryPi Zero as the base board means not only the project runs at a leisurely pace, but so do any attempts at compiling software in the target itself. Because I got tired of measuring my build times in minutes, I decided it's time to set up a cross-compiler from my PC to my homeboard. This means I can now build things in my reasonably fast PC, and deploy the resulting binary to the RaspberryPi Zero.

Setting up a cross compiler from scratch can be challenging, as it requires replicating a large chunk of your target. Luckily, the Raspberry Pi is a popular platform and plenty of articles explaining how to set up a x-compiler are available. Unluckily, I found most of them didn't work for me, with my host being Debian Bookworm. In the end I managed to find a combination of arcane spells to make x-compiling work.

First, get a Raspberry Pi Zero image, and mount it locally. This will be the sys-root of the target when x-compiling:

wget https://downloads.raspberrypi.com/raspios_armhf/images/raspios_armhf-2024-07-04/2024-07-04-raspios-bookworm-armhf.img.xz
xz -d 2024-07-04-raspios-bookworm-armhf.img.xz
# Find out the mount-start offset (multiply by 512)
fdisk -lu "$IMG_FNAME" | grep Linux | awk '{print $2}'
mkdir -p mnt
mount -o loop,offset=541065216 2024-07-04-raspios-bookworm-armhf.img.xz ./mnt

And to build things:

clang -target arm-linux-gnueabihf -mcpu=arm1176jzf-s --sysroot ./mnt/ test.c

That's all; this should create a binary in armv6 format, ready to be deployed to your target. A few things I discovered:

I wrapped this in a convenient bash script so you can build a makefile that will x-compile easily, have a look here: https://github.com/nicolasbrailo/rpiz-xcompile


Homeboard: wwwslide

Post by Nico Brailovsky @ 2024-09-10 | Permalink | Leave a comment

Homeboard hasn't seen much progress during the holidays, except for a small but useful piece of software: I created a hacky way to serve pictures over a web interface. This is a fairly fundamental piece of infrastructure for my homeboard project; most of the time these will be displaying some ambient information, but most of the screen's real estate will be used to show my (reasonably large and decades spanning) personal picture collection.

wwwslide looks like this:

From the readme:

wwwslide is a client/server for LAN slideshows. If you have a large picture collection and want a way to display them in multiple places, wwwslide server will create a web interface to retrieve random pictures from a single url. The web client can display these pictures, but there is no reason to use the included client: you could curl wwwslide and pipe it to an image viewer.

wwwslide has a server that can be pointed to a local pictures directory. It expects that pictures will be grouped in albums, sorted by /$year/$arbitrary_name/.jpg (eg 2019/foo/bar/album/.jpg). On startup, it will pick up one album, randomly, and serve a few pictures from this album to anyone calling its /get_image web endpoint. Once it runs out of pictures for this album, it will select a new random album (with a new random subset of pictures).

The included client (which can be accessed on the root of the server) can be used to browser this picture (just point your browser to your wwwslide LAN address). It's not very smart, but it should work!

Remote control: each picture includes a QR code. Scanning the QR will take you to a local page with metadata of the shown image. This page can also be used to control wwwslide (eg to request that this album is displayed from the start, or to select a new album)

Reverse geolocation: the metadata of each picture includes a reverse-geolocation. No need to guess where you took a picture, wwwslide will guess for you (as long as your pictures have geotags in their exif data)

wwwslide v0 was just a Flask service sending local-disk jpg's, and I found I frequently wondered where a particular picture was taken, or wish I had a way to see more pictures from a specific location. I'm quite proud of the idea to implement this: wwwslide will watermark pictures with a qr-code that can be used to get more info on the shown picture, and to display more picture of a specific album.