We now have the base ready and can continue with implementing the project-specific parts. The Raspberry Pi that is connected with the circuit and the lamp will act as a server. It will run a tiny web server that can be reached through a client of your choice using a web browser.
For the server side, we will adapt and evolve the server example used in Chapter 9, Making a Media Hub on the Raspberry Pi, and combine it with an updated version of the gpio-packt
recipe from Chapter 5, Creating, Developing, and Deploying on the Raspberry Pi, . To start with, we need to add the meta-packt_rpi
layer used in earlier chapters of the book. We have already ensured that our newly created layer has a higher priority then meta-packt_rpi
, but let's also add it in a dependency order in bblayers.conf
. Here is the complete bblayers.conf
file that will be used in this project:
# LAYER_CONF_VERSION is increased each time build/conf/bblayers.conf # changes incompatibly POKY_BBLAYERS_CONF_VERSION = "1" BBPATH = "${TOPDIR}" BBFILES ?= "" BBLAYERS ?= " /path/to/poky/meta /path/to/poky/meta-poky /path/to/poky/meta-yocto-bsp /path/to/meta-raspberrypi /path/to/meta-openembedded/meta-oe /path/to/meta-packt_rpi /path/to/meta-packt-iot " BBLAYERS_NON_REMOVABLE ?= " /home/path/to/git/poky/meta /home/path/to/git/poky/meta-yocto "
Next, we should make some minor changes to gpio-packt
in order to make it more suitable for our project. These changes will be made as a integration patch. The original code uses GPIO4, which is one of the pins that are set high by default. We will instead use GPIO17, which is one of the pins that defaults to low.
To change the gpio_example
code to use GPIO17 instead, we can create a new integration patch that changes the behavior only when we apply the meta-packt-iot
layer. The minor changes required are as follows:
--- gpio_example.c.orig 2016-03-10 16:55:04.334832221 +0100 +++ gpio_example.c 2016-03-10 16:54:13.400537071 +0100 @@ -39,7 +39,7 @@ /*=================================================*/ #define LENGTH 128 #define SYSFS_GPIO_DIR "/sys/class/gpio/" -#define GPIO_PIN 4 +#define GPIO_PIN 17 #define BUFFER_SIZE 255 #define DEBUG 1 #define VERSION 1.00
The patch can be generated by using the diff
command. This will result in a difference between the original version of gpio_example.c
and the updated version.
$ diff -Naur gpio_example.c.orig gpio_example.c > use_gpio17.patch
Next, we must add the patch to meta-packt-iot
. Start by creating the structure for appending gpio_example
in meta-packt-iot
:
./recipes-custom ./recipes-custom/gpio-packt ./recipes-custom/gpio-packt/gpio-packt ./recipes-custom/gpio-packt/gpio-packt/use_gpio17.patch ./recipes-custom/gpio-packt/gpio-packt_0.1.bbappend
The content of the bbappend
will be very small and will only be required to apply the patch:
FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" SRC_URI += " file://use_gpio17.patch;striplevel=0 "
Time to start with the web server. We need to make some modifications to our project for the server part as well. Most of the basic setup can be kept as is for the webserver-packt
recipe. However, the server JavaScript (server.js
) and the main webpage (index.html
) need new logic and content. Since the new content is not really suitable to add to the existing code, we will create a new bbappend
file for the web server and then override the package with new versions of the index.html
and server.js
files that are suitable for this specific project. Start by creating a new structure within meta-packt-iot
that looks like this (index.html
, server.js
, and webserver-packt_0.1.bbappend
can be empty for now):
./recipes-custom ./recipes-custom/webserver-packt ./recipes-custom/webserver-packt/webserver-packt_0.1.bbappend ./recipes-custom/webserver-packt/webserver-packt ./recipes-custom/webserver-packt/webserver-packt/index.html ./recipes-custom/webserver-packt/webserver-packt/server.js
When the new structure is in place, we can start with adding content to the bbappend
file:
DESCRIPTION = "Remote lighting control" FILESEXTRAPATHS_prepend := "${THISDIR}/${PN}:" SRC_URI += " file://server.js file://index.html " do_install_append() { install -d ${D}${datadir}/server-packt/server install -m 0755 ${WORKDIR}/index.html ${D}${datadir}/server-packt/server/public/index.html install -m 0755 ${WORKDIR}/server.js ${D}${datadir}/server-packt/server/server.js }
The logic in webserver-packt_0.1.bbappend
is quite simple. It appends the SRC_URI
variable with our new versions of index.html
and server.js
and then overrides the old files in the install stage.
Let's take a deeper look at the code modifications needed for our project. Just like in the media hub example in Chapter 9, Making a Media Hub on the Raspberry Pi we will continue to serve an HTML file that will act as the client. We will also continue to listen on the same port (3344
) to avoid confusion. The functional logic in the server code lies within the io.on() {...}
function. Here, we will receive a message from the client (index.html
) and execute it on the server. In our example, the command to execute is either gpio_example --led=1
or gpio_example --led=0
, which will cause the light to turn on and off, respectively. The complete code for server.js
looks like this:
var express = require('express') , app = express() , server = require('http').createServer(app) , path = require('path'), fs = require('fs'), sys = require('util'), exec = require('child_process').exec, child, child1; http://192.168.1.13:3344/light.html io = require('socket.io').listen(server), io.set('log level', 1); /* DEBUG MODE */ app.use(express.static(path.join(__dirname, 'public'))); app.get('/', function(req, res) { res.sendFile(__dirname + '/public/index.html'); }); io.on('connection', function(socket) { socket.on('light', function(msg) { child = exec(msg, function (error, stdout, stderr) { if (error !== null) { console.log('exec error: ' + error); } }); }); }); server.listen(3344, function() { console.log('listening on *:3344'); });
To get the whole picture of the solution, we also need to look at the client, index.html
. The look and feel of the web page from Chapter 9, Making a Media Hub on the Raspberry Pi is kept, but the CPU monitoring has been replaced by a green/red button, used to turn the light on or off. Depending on which button is pushed, a socket message using socket.emit
is used. The message contains the exact Unix command required to turn the light on or off:
<body> <nav class="navbar navbar-inverse navbar-fixed-top" role="navigation"> <div class="container-fluid"> <div class="navbar-header"> <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1"> <span class="sr-only">Toggle navigation</span> <span class="icon-bar"></span> <span class="icon-bar"></span> <span class="icon-bar"></span> </button> <ul class="nav navbar-nav"> <li class="active"> <a href="EB9781785281952_3.html">HOME</a> </li> </ul> </div> </div> </div> </nav>' <hr> <div class="container-fluid"> <div class="well well-lg text-center"> <h1><b>Raspberry-Pi</b><b></b></h1> <p><b>Remote lighting</b> control</p> <h4><span class="label label-info"></span></h4> </div> <button class="button buttonON" onclick="lighton()">ON </button> <button class="button buttonOFF" onclick="lightoff()">OFF</button> <script src="/socket.io/socket.io.js"></script> <script> var socket = io.connect('http://'+ location.host); function lighton() { socket.emit('light', 'gpio_example --led=1'); return false; } function lightoff() { socket.emit('light', 'gpio_example --led=0'); return false; } </script> </body>
If you look at index.html
in a web browser, it should look like this:
Lastly, we must not forget to add gpio-packt
and webserver-packt
to our image:
$ cat recipes-core/images/packt-iot-image.bb # Base this image on rpi-basic-image include recipes-core/images/rpi-basic-image.bb SPLASH = "psplash-raspberrypi" IMAGE_FEATURES += "ssh-server-dropbear splash" IMAGE_INSTALL_append = " rpi-gpio gpio-packt webserver-packt"
3.19.29.89