Geovane Fedrecheski
geonnave@
IoT
Nerves
-
IoT ?
-
Quick Demo
-
Nerves
-
Explained Demo
IoT?
The Internet
The Internet of Things
Demo
mix firmware
mix firmware.burn
defmodule HelloGpio.Blinky do
use GenServer
require Logger
@ledpin 26
def start_link do
GenServer.start_link __MODULE__, [], name: __MODULE__
end
def toggle, do: GenServer.cast(__MODULE__, :toggle)
def init(_) do
Logger.debug "Initializing.."
{:ok, pin} = Gpio.start_link(@ledpin, :output)
Gpio.write(pin, 1)
{:ok, {pin, 1}}
end
def handle_cast(:toggle, {pin, pin_state}) do
new_pin_state = if pin_state == 0, do: 1, else: 0
Gpio.write(pin, new_pin_state)
{:noreply, {pin, new_pin_state}}
end
end
IoT =~
Embedded webservices
O Elixir da IoT
Raspberry Pi
Beaglebone Black
defmodule HelloGpio.Blinky do
use GenServer
require Logger
@ledpin 26
def start_link do
GenServer.start_link __MODULE__, [], name: __MODULE__
end
def toggle, do: GenServer.cast(__MODULE__, :toggle)
def init(_) do
{:ok, pin} = Gpio.start_link(@ledpin, :output)
Gpio.write(pin, 1)
{:ok, {pin, 1}}
end
def handle_cast(:toggle, {pin, pin_state}) do
new_pin_state = if pin_state == 0, do: 1, else: 0
Gpio.write(pin, new_pin_state)
{:noreply, {pin, new_pin_state}}
end
end
wget 'http://director.downloads.raspberrypi.org/
raspbian_lite/images/raspbian_lite-2016-09-28/
2016-09-23-raspbian-jessie-lite.zip'
unzip 2016-09-23-raspbian-jessie-lite.zip
sudo dd \
if=2016-09-23-raspbian-jessie-lite.img \
of=/dev/sdc
sudo vi /etc/apt/sources.list
# deb http://packages.erlang-solutions.com/debian wheezy contrib
wget http://packages.erlang-solutions.com/debian/erlang_solutions.asc
sudo apt-key add erlang_solutions.asc
sudo apt-get update
sudo apt-get install git erlang
git clone https://github.com/elixir-lang/elixir.git
cd elixir
git checkout tags/v1.3.4
make clean test
# waaaaaaaaaaaaaait a LOT (aprox. 1h)
export PATH="$PATH:/path/to/elixir/bin"
SSH
defmodule Broker.AccessControl do
use GenServer
def start_link do
GenServer.start_link(__MODULE__, [], name: __MODULE__)
end
def authorize(request) do
GenServer.call __MODULE__, {:authorize, request}
end
def handle_call({:authorize, request}, _from, _current) do
ans = Broker.AccessControl.PDP.authorize(request)
{:reply, ans, ans}
end
end
Compile on board takes time...
host$ ssh pi@192.168.0.1
pi$ mix nerves.new hello_nerves --target rpi
pi$ cd hello_nerves
pi$ mix deps.get
pi$ mix compile
# takes TIME...
pi$ iex -S mix
But..
-
Repeat the process for each board?
-
Maybe write a script
-
-
Configuration/Compilation Takes time..
-
What if want to use another board? (will need a different setup)
Nerves
Craft and deploy bulletproof embedded software in Elixir
Based on
Buildroot is a simple, efficient and easy-to-use tool to generate embedded Linux systems through cross-compilation.
Code
Package
Run
Prepare
VM
ARM
Toolchain
=
+
+
|>
{
,
}
=
Nerves
(installation)
(have Erlang & Elixir on host)
sudo apt-get install ssh-askpass
sudo apt-get install squashfs-tools
wget 'https://github.com/fhunleth/fwup/releases/
download/v0.9.2/fwup_0.9.2_amd64.deb'
sudo dpkg -i fwup_0.9.2_amd64.deb
mix archive.install 'https://github.com/nerves-project/
archives/raw/master/nerves_bootstrap.ez'
Code
Package
Run
Prepare
mix nerves.new hello_nerves --target rpi3 cd hello_nerves mix deps.get mix compile
(write your project in Elixir)
mix firmware mix firmware.burn
NERVES_TARGET=bbb mix compile
How does it compare?
Image sizes
Nerves
Raspbian
~300MB
~20MB
Boot time
Nerves
Raspbian
~30 sec.
~6 sec.
Multiple Boards
Nerves
Raspbian
All drivers included
Nerves
Raspbian
How about other frameworks?
?
The VM
Concurreny
Fault tolerance
Data structures
Consistent libs
Modern tooling
+
Small images
Multiple boards
Quick iteration
Cases
Demo
(explained)
HTTP
WiFi
GPIO
mix new hello_nerves --umbrella
cd sample/apps
mix nerves.new fw --target rpi3
mix phoenix.new ui --no-ecto --no-brunch
mix new hello_gpio --sup
cd fw
mix deps.get
mix compile
├── apps
│ ├── fw
│ ├── hello_gpio
│ └── ui
├── config
│ └── config.exs
├── mix.exs
├── mix.lock
└── README.md
Prepare
Code
apps/hello_gpio
├── config/
├── lib
│ ├── hello_gpio.ex
│ └── blinky.ex
├── mix.exs
├── README.md
└── test/
# mix.exs
defp deps do
[{:elixir_ale, "~> 0.5.5"}]
end
# lib/blinky.ex
defmodule HelloGpio.Blinky do
use GenServer
require Logger
@ledpin 26
def start_link do
GenServer.start_link __MODULE__, [], name: __MODULE__
end
def toggle, do: GenServer.cast(__MODULE__, :toggle)
def init(_) do
{:ok, pin} = Gpio.start_link(@ledpin, :output)
Gpio.write(pin, 1)
{:ok, {pin, 1}}
end
def handle_cast(:toggle, {pin, pin_state}) do
new_pin_state = if pin_state == 0, do: 1, else: 0
Gpio.write(pin, new_pin_state)
{:noreply, {pin, new_pin_state}}
end
end
apps/ui
├── config/
├── lib/
├── mix.exs
├── priv/
├── README.md
├── test/
└── web
├── channels/
├── controllers
│ └── page_controller.ex
├── gettext.ex
├── router.ex
├── templates/
├── views/
└── web.ex
# web/controllers/page_controller.ex
defmodule Ui.PageController do
use Ui.Web, :controller
require Logger
def index(conn, _params) do
render conn, "index.html"
end
def update(conn, _params) do
Logger.debug "Will toggle LED!"
HelloGpio.Blinky.toggle
render conn, "index.html"
end
end
# web/router.ex
scope "/", Ui do
pipe_through :browser
get "/", PageController, :index
put "/", PageController, :update
end
apps/fw
├── config
│ └── config.exs
├── lib
│ └── fw.ex
├── mix.exs
├── README.md
└── test/
mix deps.get
mix compile
# mix.exs
def deps do
[
{:hello_gpio, in_umbrella: true},
{:ui, in_umbrella: true},
{:nerves_interim_wifi, "~> 0.1.0"},
{:nerves_firmware_http,
github: "nerves-project/nerves_firmware_http"},
{:nerves, "~> 0.3.0"}
]
end
# lib/fw.ex
Nerves.InterimWiFi.setup "wlan0",
ssid: "eu sei oqvc fez no verao passado",
key_mgmt: :"WPA-PSK",
psk: "3neeszombees"
Package
mix firmware
mix firmware.burn
apps/fw
├── config
│ └── config.exs
├── lib
│ └── fw.ex
├── mix.exs
├── README.md
└── test/
$ ls -lah _images/rpi3/fw.fw
-rw-rw-r-- 21M _images/rpi3/fw.fw
Run
FOTA (Firmware Over the Air) Upgrades!
$ http POST "192.168.0.121:8988/firmware" \
content-type:application/x-firmware \
x-reboot:true < firmware.fw
Run
# mix.exs
def deps do
[
{:hello_gpio, in_umbrella: true},
{:ui, in_umbrella: true},
{:nerves_interim_wifi, "~> 0.1.0"},
{:nerves_firmware_http,
github: "nerves-project/nerves_firmware_http"},
{:nerves, "~> 0.3.0"}
]
end
Remote Debugging
├── apps
│ ├── fw
│ │ ├── _build
│ │ ├── config
│ │ ├── deps
│ │ ├── _images
│ │ ├── lib
│ │ ├── mix.exs
│ │ ├── mix.lock
│ │ ├── README.md
│ │ ├── rel
│ │ └── test
# rel/vm.args
-name raspi@192.168.0.7
-setcookie secret
iex --name host1@192.168.0.6 \
--remsh raspi@192.168.0.7 \
--cookie secret
Remote Debugging
remsh
Remote Debugging
iex --name host1@192.168.0.6 \
--cookie secret
:observer
iex(host2@192.168.0.6)> :observer.start
Nodes
-> Connect node
-> input "raspi@192.168.0.7"
For more Information
Obrigado
geonnave@
Elixir of IoT with Nerves
By Geovane Fedrecheski
Elixir of IoT with Nerves
- 1,509