DEV Community

Cover image for An Unusual Pomodoro Timer on Elixir and Nerves
Dimitris Zorbas
Dimitris Zorbas

Posted on • Originally published at zorbash.com on

An Unusual Pomodoro Timer on Elixir and Nerves

In my previous post about "Organising Book Highlights and Notes",
I wrote:

"Some day I may build a gadget for my desk to display a daily quote".

A few days later, it's on my desk and it couldn't have been a better
pretext to give Livebook on Nerves a try.

Finished Product

actual image of Brain
It's alive! 🧟

The case is not made of flesh, but working with clay is not my forte. I should buy a 3D printer at some point..

Goal

The scope of this weekend-project was to build some sort of smart desktop
ornament. It should periodically display a random quote from my Kindle
highlights and notes on an E Ink screen.
The quote is fetched via bookworm 🪱📚.
The display should refresh every 25 minutes and flash, marking the end of a time
block.

As the title hints, this is an unusual pomodoro timer. It deviates
from the standard pomodoro technique, but it suits me.

Name

A project needs a name. The obvious choice for something built on Nerves is
no other than Brain 🧠!

And here's a sample quote Brain would display:

The function of the brain and nervous system is to protect us from
being overwhelmed and confused by this mass of largely useless and irrelevant
knowledge, by shutting out most of what we should otherwise perceive or
remember at any moment, and leaving only that very small and special selection
which is likely to be practically useful.

Aldous Huxley, The Doors of Perception

The combination this name and Elixir's fault tolerance reminds me this excellent cult horror film:

brain poster

Optional Features

Display the week number

I tend to make daily plans and thinking in terms of numbered weeks, it
drives me to make them memorable.

Display the temperature outside

I tend to hit the gym after work, so this is mostly to inform me whether to wear shorts.
(plot twist: I'll wear shorts anyway).

Why E Ink?

The slow refresh rate of E Ink devices is ideal for something I'll keep
right in from of me. It can be useful even when powered off.
It's not even backlit and it doesn't distract me at all.
I was sceptical of having yet another "screen" to look at. I've
even ditched my multi-monitor setup for a single monitor with the
laptop's monitor solely for messaging apps like Slack.
Oh and the energy ⚡️ consumption is minimal, Pisugar could power it for a couple of days (untested
assumption
).

What you'll need

  • Raspberry Pi 2 model B (that's what I had lying around)
  • SD card
  • WiFi USB dongle (Raspberry Pi 2 doesn't have on-board WiFi)
  • Pimoroni Inky wHat E Ink Display
  • A JSON file with notes to display (see bookwork)

You might notice there's a camera on my device, it's not required for
the features discussed in this post. A future next one will be about it
though, stay tuned!

Instructions

Follow the instructions below to build one yourself.

1. Burn the Nerves Livebook Firmware

Install prerequisites for packaging firmware images

MacOS

brew update
brew install fwup squashfs coreutils xz pkg-config
Enter fullscreen mode Exit fullscreen mode

Linux (Debian)

sudo apt install build-essential automake autoconf git squashfs-tools ssh-askpass pkg-config curl
Enter fullscreen mode Exit fullscreen mode

Then install nerves_bootstrap with:

mix archive.install hex nerves_bootstrap
Enter fullscreen mode Exit fullscreen mode

You can find more detailed information about getting started with Nerves
here.

Burn the Image

Follow the instructions on the nerves_livebook repo
to burn the firmware using fwup or run the code below in your shell:

wget https://github.com/livebook-dev/nerves_livebook/releases/download/v0.2.26/nerves_livebook_rpi2.fw

# Mind to replace with your SSID and passphrase
sudo NERVES_WIFI_SSID='access_point' NERVES_WIFI_PASSPHRASE='passphrase' fwup nerves_livebook_rpi2.fw
Enter fullscreen mode Exit fullscreen mode

2. Mount the E Ink Screen Hat on the Pi

mounted screen

At this point you can already power on your Pi.

Point your browser to http://nerves.local ..and voila!

livebook auth



The password is "nerves".

🙌 You have an easily accessible instance of Livebook running on a tiny computer.
It runs in embedded mode by default which means that code evaluated in
your notebooks runs in the context of the Livebook node.

This is ideal, as it allows us to redefine Scene modules from within a
notebook and trigger a screen refresh without uploading firmware changes and rebooting the Pi.
More about that further below.

3. Clone the Brain Repo

Hang tight, we're halfway there, run:

git clone git@github.com:zorbash/brain.git
Enter fullscreen mode Exit fullscreen mode

4. Add Some Notes

You can use bookwork to download your Kindle highlights in a
format Brain understands or simply copy mine from https://github.com/zorbash/notes/blob/main/books.json
and place them in priv/notes/.

5. Deploy! 🚀

Then run:

export MIX_TARGET=rpi2

mix deps.get
mix firmware
mix firmare.gen.script
./upload.sh livebook@nerves.local
Enter fullscreen mode Exit fullscreen mode

When it asks for a password, type in nerves.

That's it, a few moments later the screen should flash and your Brain
will have come to life.

Making Changes

Brain is open-source and it's easy to tweak it according to your needs.
The UI is built using Scenic which makes it trivial to
preview changes locally without re-uploading firmware.

Start Scenic to preview your changes:

MIX_ENV=dev MIX_TARGET=host iex -S mix scenic.run
Enter fullscreen mode Exit fullscreen mode

You should see a window like this:

scenic preview

The Scene to modify is NervesLivebook.Scenes.Main and you can trigger
an update with:

send :main_scene, :update
Enter fullscreen mode Exit fullscreen mode

To trigger a screen refresh remotely run:

ssh livebook@nerves.local 'send :main_scene, :update'
Enter fullscreen mode Exit fullscreen mode

💡 Since Brain runs Livebook (http://nerves.local), you can trigger an update by evaluating an
Elixir cell with send :main_scene, :update in a notebook.

Debugging

You can connect to your Brain with:

ssh livebook@nerves.local
Enter fullscreen mode Exit fullscreen mode

Then you can inspect the logs with:

RingLogger.next
Enter fullscreen mode Exit fullscreen mode

For further debugging, check out toolshed which bundles a
variety of helpful utility helpers.

use Toolshed
import IEx.Helpers

h(Toolshed)
Enter fullscreen mode Exit fullscreen mode

Caveats

The Pimoroni E Ink screen afaik does not support partial refresh, it'd
be cool to partially refresh the header (week, temperature, time) every
minute.

Scenic's text wrapping could support break-word, see scenic#118.

Future Enhancements

  • Get it to show notes per bookshelf, for example it could be configured to show only notes from the computer science bookshelf between 10 and 11 AM and from philosophy between 6 and 7 PM.

Livebook

Livebook is an incredible piece of technology, improving at a mind-blowing
rate.

A couple of months ago I started work on an enhancement to be
able to show the documentation for any module / function in a notebook.
My intention was to expose a Livedoc.render(:plug) to fetch and
render the documentation of the given hex package.

Thankfully, I was surprised to find out that this has already been
implemented in livebook#453 🙌.

If you haven't tried Livebook yet, please check out livebook.dev.
You can even configure the default Livebook location where notebooks
will open. I've set mine to http://nerves.local where Brain lives.

With your notes loaded in Brain, you can quickly browse and search them with the following notebook:

# Notes

<!-- livebook:{"livebook_object":"cell_input","name":"search","reactive":true,"type":"text","value":""} -->

Enter fullscreen mode Exit fullscreen mode
query = IO.gets("search: ") |> String.trim()
notes = NervesLivebook.Notes.all() |> Enum.filter(&String.contains?(&1.text, query))

Kino.DataTable.new(notes)
Enter fullscreen mode Exit fullscreen mode

Reactive inputs make this possible.

Watch a video if it in action here

Acknowledgements

This project wouldn't be as enjoyable and painless without nerves,
nerves_livebook, scenic, inky.

Thank you @mobileoverlord, @fhunleth, @boydm,
and @lawik and all of the contributors to this amazing part of the Elixir ecosystem.


Top comments (0)