Building a Lightning candy dispenser

The candy dispenser in action

Back in September I attended the 3rd Lightning Network Hackday in Berlin organized by fulmo. It was a rather loose gathering of people working on all sorts of Bitcoin and Lightning related projects. One of the most fun applications of Lightning I saw there was a little electronic candy dispenser. The concept was simple but yet fascinating: a Raspberry Pi, embedded in the candy dispenser, ran lnd and served a website with an invoice displayed as QR code. Every time one sent money some M&Ms dropped out of the machine and a new invoice was generated. This turned out to be so much fun that I decided to build one myself.

The mechanics

The market for electric candy dispensers is not that big. When looking on amazon there were about three choices: two fancy machines and one cheapish. Since I didn't know if the device would survive my attempts to disassemble it and put in a bunch of electronic components I chose the cheaper one. And that's how it looks under the hood:

As you can see it consists of a simple screw-conveyor powered by a small electric motor. What you can't see in the pictures is the pedestal. It contains a battery compartment which can be sawed out to make room for the electronics. It's probably much easier with the appropriate tools, but I managed to do it with my Leatherman.

The electronics

The workflow of the candy dispenser goes as follows:

  1. Display a BOLT-11 invoice as a QR code
  2. Process the payment
  3. Make the motor turn to dispense candy

Since I didn't want to rely on an external device for displaying the invoice I used a e-ink display for that. In theory this has the big advantage that it only consumes energy when its content changes. In practice it also has the disadvantage of being relatively slow and if the machine is turned off by cutting the power it doesn't reset itself and keeps displaying a long obsolete invoice till it gets restarted. But even with these caveats it's still fun to play with e-ink displays.

The "brain" of the machine was a Rapberry Pi Zero at first. But due to some software choices it hadn't sufficient CPU power and I replaced it with a Raspberry Pi 3B+.

The software

I'm currently interning at Blockstream, so I decided to use our very light-weight lightningd, mainly developed in house. Unfortunately it requires a bitcoind to monitor the blockchain which left me with three choices (I am aware of):

  1. Use spruned: This was my firs approach: spruned is a little python script that connects to the bitcoin p2p network and electrum servers and answers queries to a bitcoind-like RPC interface. Unfortunately it's rather slow (I thought about RIIRing it, but it's quite some work and won't get rid of all the slowness), needs too much time to find enough peers and generally doesn't seem production ready.
  2. Run bitcoind: Although bitcoind is quite efficient validating blocks takees a long time and the only practical approach is to sync a node on a faster machine, transfer the datadir and then don't leave it turned off for to long, so that it doesn't have to sync too much once you start it again (blocks take multiple seconds to validate). Currently I don't have a big enough SD card for that (and it would probably fail rather quickly anyway) and I can't fit a usb SSD into the pedestal of the candy dispenser, so this Option doesn't work for me either right now.
  3. Do it the hacky way: Well, that's how I ended up solving my problem: ssh -L8332: <my_server> -N. It's not elegant, it trusts the bitcoind on <my_server> completely (so I could run my lightningd there too), but it works for now (and I didn't have to change my dispenser software).

I can only hope that neutrino will be available to all lightning implementations at some point.

Once lightningd is running and synced the only pieces left are an infinite loop that generates new invoices using the invoice RPC call and waiting for them getting paid or expiring using waitinvoice and some systemd scripts starting these.

Future plans

Currently I'm working on integrating a nfc shield (PN532) to avoid the QR code scanning which can be quite hard if the light conditions aren't optimal.

Writing this blog post was kind of a moving target since I kept iterating on the design of the device. I'll probably write a second part going more into detail once the soft- and hardware stack stabilize.

Published: Tags: