Distributed programming made easy with Elixir

Elixir of Life

© Lead Image © Andrejs Pidjass, 123RF.com

© Lead Image © Andrejs Pidjass, 123RF.com

Article from Issue 255/2022
Author(s):

The Elixir programming language on a Raspberry Pi lets you create distributed projects in just a few lines of code.

Creating distributed and concurrent applications doesn't have to be difficult. Elixir [1] allows hobbyists and new programmers to create projects that can work across multiple nodes. A general-purpose programming language, Elixer runs on top of the Erlang virtual machine (VM) [2], which is known for running low-latency, distributed, and fault-tolerant systems.

In this article, I look at three projects (Figure 1) that use basic Elixir functions, with no custom project setup or imported libraries. The first project employs remote functions between a PC and a Raspberry Pi, the second project uses multinode requests to get Pi statistics, and the final project looks at dynamic sharing of data between three nodes.

Figure 1: Three Elixir projects.

These projects require only 10 to 25 lines of Elixir code, showing that distributed projects don't have to be complicated.

Getting Started

For instructions on how to install Elixer on your particular system, refer to the Elixir website [3]. The process installs the Erlang VM and three new executables: iex (interactive Elixir shell), elixir (Elixir script runner), and elixirc (Elixir compiler).

A good first example is to use the interactive Elixir shell (iex) on a Raspberry PI to write to a general purpose input/output (GPIO) pin. To begin, open the shell with iex and call the Raspberry Pi gpio [4] command-line tool from the base Erlang :os.cmd function to write a value of 1 to pin 7; then, read it back:

$ iex
iex> :os.cmd(:"gpio write 7 1")
[]
iex> :os.cmd(:"gpio read 7")
'1\n'

Elixir calls Erlang functions when you place a colon (:) in front of the Erlang function or custom variable.

Remote GPIO Control

The next step is to control a Pi's GPIO from a different node. A two-node network can be configured by defining a username with a node address and a common cookie between the two nodes.

For my setup, I logged in to the Raspberry Pi iex shell with the name pi3@192.168.0.105 and a cookie named pitest (Figure 2, top). Next, I logged in to the PC iex session with the name pete@192.168.0.120 and the same cookie, pitest.

Figure 2: An Elixir remote function call.

From my PC iex session, I only need two lines of Elixir code to write remotely to a Pi GPIO pin (Figure 2, bottom). The first line connects to the Pi Elixir node, and the second line issues a remote procedure call (RPC) to run an :os.cmd statement on the Pi node:

$ iex --name pete@192.168.0.120 --cookie pitest
iex> Node.connect :"pi3@192.168.0.105"
true
iex> :rpc.call(:"pi3@192.168.0.105",:os,:cmd ,[:"gpio write 7 1"])
[]

It's important to note that the underlying Erlang VM on the Raspberry Pi managed the RPC request, and for this example, no Elixir code was required on the Pi node.

User Interface

Now you will want to create a simple way for the user to enter a GPIO pin and value. Elixir tends to be used for back-end applications, but you also have a number of good web server options from which to choose and an Erlang wx graphical module (a wxWidgets port).

One user interface approach is to use the Elixir IO module to do text console reads and writes. The IO.gets() function gets user input, and IO.puts writes to the console. Variables can be inserted into a string with #{<the_variable>}:

iex> thepin = IO.gets("Select the Pi GPIO pin: ")
Select the Pi GPIO pin: 7
"7\n"
iex> IO.puts "Selected GPIO pin: #{thepin}"
Selected GPIO pin: 7

For simple dialogs, I like to use the Bash Zenity [5] command-line package. Zenity support a number of different dialog types, and it is preloaded on Raspian and most Linux distributions.

The zenity --forms command can be configured with a presentation that asks for a GPIO pin number and value. After the user enters data and presses OK, Zenity returns a string of the GPIO pin number and pin value (Figure 3).

Figure 3: A Zenity form called from Bash.

The Zen2gpio.exs script in Listing 1 launches a Zenity form to get user input – a pin number and value – that is passed to the :rpc.call function to do a remote GPIO write.

Listing 1

Zen2gpio.exs

01 #-------------
02 # Zen2gpio.exs - Use a Zenity form to set the GPIO pin and value input
03 #-------------
04 defmodule Zen2gpio do
05   def show_form (pnode) do
06     thecmd = "zenity --forms --title='Set Pi GPIO Pins' --separator=' ' --add-entry='GPIO Pin (0-26)' --add-entry='New Value (0-1)' "
07     pininfo = :os.cmd(:"#{thecmd}")
08     # If data is entered in form, write to GPIO and refresh
09     if byte_size("pininfo") > 0 do
10       :rpc.call(:"pi3@192.168.0.105",:os,:cmd ,[:"gpio write #{pininfo}"])
11       show_form (pnode)
12     end
13   end
14 end
15
16 # Connect to the Pi node
17 pnode = :"p34@192.168.0.105"
18 Node.connect  pnode
19
20 # Show the dialog
21 Zen2gpio.show_form(pnode)

For this script, the Zen2gpio module is created with the function show_form. Elixir does not support a while statement; instead, loops are implemented by recursion. In this script, the show_form function is called initially to open a dialog. An if statement checks for feedback from the dialog; if present, the RPC call is executed, and the show_form function is called again. No feedback or a press of the Cancel button exits the script.

The Elixir script runner launches the code with the common project cookie and a unique username (Figure 4).

Figure 4: Elixir/Zenity remote GPIO write dialog.

Buy this article as PDF

Express-Checkout as PDF
Price $2.95
(incl. VAT)

Buy Linux Magazine

SINGLE ISSUES
 
SUBSCRIPTIONS
 
TABLET & SMARTPHONE APPS
Get it on Google Play

US / Canada

Get it on Google Play

UK / Australia

Related content

  • Elixir 1.0

    Developers will appreciate Elixir's ability to build distributed, fault-tolerant, and scalable applications.

  • Xonsh

    Create lightweight Raspberry Pi scripts with Xonsh, a Python shell that lets you write scripts in Python with Bash commands mixed in.

  • RaspPi-Controlled Toy Sailboat

    With Node-RED, you can create a web dashboard that instructs a Raspberry Pi to set the rudder position on a toy sailboat.

  • WiFi Thermo-Hygrometer

    A WiFi sensor monitors indoor humidity and temperature and a Node-RED dashboard reports the results, helping you to maintain a pleasant environment.

  • Whiptail

    Whiptail interfaces add menus and information pages to your Raspberry Pi projects.

comments powered by Disqus