Just yesterday I attended another edition of great workshop-conference Warsjawa. The tracks I went to were – vert.x + raspberry pi by Bartek Zdanowski and Effective Presentation by Małgorzata Majewska.

Enjoyed them both equally, but in this post I will focus on what I have learned in the first one and what have I done with it.

So few words about the two things from the subject of this post.

From the project’s webpage “Vert.x is a lightweight, high performance application platform for the JVM that’s designed for modern mobile, web, and enterprise applications.”. The philosophy is that with actor-like based model you ale able to write bits in the languages you want (given they work on JVM or… browser!).

RaspberryPi in case you have not heard yet is low-cost tiny computer with ARM processor comparable to Pentium II, graphic accelerator, HDMI output, ethernet port and, what is most interesting, a set of input-output pins which you can read and write to (we’ll get there). Those inputs and outputs are called GPIO (General Purpose Input/Output).

What are we going to do? TL;DR

So the idea is simple – I’d like to have raspberry pi with attached button to it. Now on my laptop I’d like to have a web serve that will server a page. On that page I would like to have a simple box that will tell me in realtime what is the state of the button (up/down). Simple.

And the code should be equally simple. The idea of this post is to show you that vert.x makes it really simple to achieve it.

How does the vert.x work?

What you do is you write Verticles or Workers (the difference is that Verticle will be always working on a specific thread, while Worker will be able to switch to finish it’s work as soon as CPU resources are free anywhere).

Each verticle is a piece of code, executed in completely separate ClassLoader. They all have two ways of communicating with each other – one is Shared Data, which allows you to access Maps or Sets to pass data over. Second way is Event Bus – a black box which you send messages to (identified by a string) and that you can listen on in other verticles (think JMS).

When you run your application you can instantiate many instances of the same verticle – so If you have a parallelizable work, you can have many workers doing it and have another verticle coordinating the work and aggregating the results.

Vert.x is designed to make it as easy as possible to write asynchronous, parallel applications and has a lot of goodies for that. Go and read the docs If you find the above interesting enough :-)

Setup RaspberryPi and connect the button

You will need a raspberry pi. Obviously.

Then you need to install some linux on the SD card. I’ve used newest Raspbian (which is RaspberryPi-friendly Debian) Wheezy.

On your raspbian we’re gonna need few things

  • Java JDK for ARM
  • vert.x – the easiest is to install via gvm. Just install gvm and then type gvm install vertx
  • optionaly webipoi to have nice web-based access to GPIO

Then you will either need to solder, or use a breadboard to attach your button. What you need to do is to get a button that short-circuits it’s legs when pressed and then attach one of the legs to one of the GPIO pins (I have used pin number 22 – you can see the full “map“) and the other to 3.3V (which is pin number 1).

Connect to ethernet, attach power and Voila!

raspberry

Setup your laptop/desktop

JDK you probably already have, IDE you have as well. What you might be missing is vertx. You install it the same way as on RaspberryPi.

Let’s write some code!

Ok the hardware is ready. Now let’s write some verticles.

Hardware Part – RaspberryPi button monitor

So the first verticle will be the one deployed on the raspberry pi. What it will do is one thing and one thing only. It will monitor the button for changes and send messages to event bus, when it happens.

For reading and writing to GPIO we are going to use Pi4J library.

To start off I have used a maven archetype which will create you a bootstrap build in maven with all needed dependencies. It also uses vertx maven plugin to create vertx modules, which are ziped packages with all dependencies that you can easily run.

Add the maven dependency to mentioned Pi4J to pom.xml

<dependency>
      <groupId>com.pi4j</groupId>
      <artifactId>pi4j-core</artifactId>
      <version>0.0.5</version>
</dependency>

Ok let’s get to the code

public class HardwareVerticle extends Verticle {

    public void start() {

        // create gpio controller
        final GpioController gpio = GpioFactory.getInstance();

        System.out.println("GPIO LOADED");

        final GpioPinDigitalInput myButton = gpio.provisionDigitalInputPin(RaspiPin.GPIO_06, PinPullResistance.PULL_DOWN);

        // create and register gpio pin listener
        myButton.addListener(new GpioPinListenerDigital() {
            @Override
            public void handleGpioPinDigitalStateChangeEvent(GpioPinDigitalStateChangeEvent event) {
                System.out.println(new Date() + "Button change");

                vertx.eventBus().publish("buttonbus", String.valueOf(event.getState().getValue()));
            }
        });
    }
}

On line 6 I am instantiating the Pi4J GpioController, and then using it to add a listener that will fire off every time state changes on GPIO06. Please note on line 10 that I am setting up PinPullResistance.PULL_DOWN – If you don’t use it, it’s not gonna work ;-)

The main thing happens on line 18 – we’re sending the state of the button to the event bus on the “buttonbus” address. publish method means that all receivers subscribed to that address will get exactly one copy of this message.

Last thing you need to do is to edit mod.json in src/main/resources and change the "main" attribute to point to this HardwareVerticle with full package. This will instruct vertx about the “main” verticle to start when you run the code.

So now the only thing you need to do is to build it with mvn clean install and copy target/your-package-name-version-mod.zip to the raspberry pi, and then run it there with

sudo ~/.gvm/vertx/current/bin/vertx runzip your-package-name-version-mod.zip -cluster

A little explanation

  • you need to run it as sudo to be able to access GPIO pins
  • runzip is a command that allows you to run those special packages I’ve mentioned before
  • -cluster will run vertx in a mode that can cluster with other vertxes with shared event bus
    • Now try pressing that button – you should see output on the sysout like this:
      guzikpress

      Server Part – HTTP server

      The other verticle will be our web server, that we will run on the laptop. Start again with generating a new vertx project from the maven archetype and create a verticle like this

      public class ServerVerticle extends Verticle {
      
          public void start() {
              HttpServer server = vertx.createHttpServer();
      
              server.requestHandler(new Handler<HttpServerRequest>() {
                  public void handle(HttpServerRequest req) {
                      String file = "";
                      if (req.path().equals("/")) {
                          file = "index.html";
                      } else if (!req.path().contains("..")) {
                          file = req.path();
                      }
                      req.response().sendFile("web/" + file);
                  }
              }).listen(9999, "localhost");;
      
              vertx.eventBus().registerHandler("buttonbus", new Handler<Message>() {
                  @Override
                  public void handle(Message message) {
                      System.out.println("Button state is: "+message.body());
                  }
              });
      
              System.out.println("Server started");
          }
      }
      

      There are two things worth mentioning.

      Between lines 4 and 16 we are starting a HTTP server. This is a full blown HTTP server, implemented in vert.x that you need only few lines to start. Basically in the handle we are serving all the requested files from the “web” directory in resources and if the file is not provided, we’re showing index.html. And that is it.

      Create a simple index.html

      <html>
      <head><title>Hey lol</title></head>
      <body>Raspberry LOL xD</body>
      </html>
      

      Start the module as described in the raspberry pi part and go to http://localhost:9999/. You should see the above page.

      Second thing starts on line 18 – we’re registering a handler for messages send to the buttonbus. Now If you have started your module with “-cluster” and the vertxs were able to see each-other on the network via multicast, you should already see output on the console on your laptop, when pressing the button on the rapsberry pi. Wasn’t that hard to make them talk to each other, was it?

      If that doesn’t work, then probably something somewhere is blocking the muticast, or your cluster on the laptop (or the pi) could’ve attached to the wrong interface (not the common one between the two).

      You can try two things

      • Specify another parameter on the commandline -cluster-host (but leave the -cluster as well!) and provide explicitly the IP you want to use on the machine (do it for both the laptop and the pi).
      • If that still does not work, edit on your laptop’s ~/.gvm/vertx/current/conf/cluster.xml, and under network/join disable multicast, enable tcp/ip and point to your rapsberry pi IP (see snippet below)
      <network>
              <port auto-increment="true">5701</port>
              <join>
                  <multicast enabled="false">
                      <multicast-group>224.2.2.3</multicast-group>
                      <multicast-port>54327</multicast-port>
                  </multicast>
                  <tcp-ip enabled="true">
                      <interface>YOUR RASPBERRY PI IP</interface>
                  </tcp-ip>
                  <aws enabled="false">
                      <access-key>my-access-key</access-key>
                      <secret-key>my-secret-key</secret-key>
                      <region>us-east-1</region>
                  </aws>
              </join>
      

      Browser Part – SockJS server and client

      Ok the last thing is to put some data to the browser. “LOL xD” is not enough for us.

      The absolute mind-blowing thing about vert.x is that you can actually listen and write to the eventbus from the browser using javascript. Which is awesome.

      There are two ways – either use websockets, which works well, but unfortunately only with the newest browsers. Or use SockJS that can transparently fall back to other ways of communication (polling in the worst scenario) if the websockets are not available.

      So we need to do two things – enable SockJS on our 9999 server, we have just created and then use javascript to read messages from the buttonbus.

      Let’s see how our server looks like now.

      public class ServerVerticle extends Verticle {
      
          public void start() {
              HttpServer server = vertx.createHttpServer();
      
              server.requestHandler(new Handler<HttpServerRequest>() {
                  public void handle(HttpServerRequest req) {
                      String file = "";
                      if (req.path().equals("/")) {
                          file = "index.html";
                      } else if (!req.path().contains("..")) {
                          file = req.path();
                      }
                      req.response().sendFile("web/" + file);
                  }
              });
      
              JsonObject config = new JsonObject().putString("prefix", "/comm");
      
              JsonArray permitted = new JsonArray();
              permitted.add(new JsonObject());
      
              //watch out, this means ALLOW-ALL messages via JS. not production friendly!
              vertx.createSockJSServer(server).bridge(config, permitted, permitted);
      
              server.listen(9999, "localhost");
      
              vertx.eventBus().registerHandler("buttonbus", new Handler<Message>() {
                  @Override
                  public void handle(Message message) {
                      System.out.println("Button state is: "+message.body());
                  }
              });
      
              System.out.println("Server started");
          }
      

      It isn’t changed very much – the only differences is that on line 24 we’re creating SockJSServer that will listen on http://localhost:9999/comm for our vert.x specific communication. Note how we’re providing two “permitted” objects there, which means basically that our browser can read and write from and into any bus. This is a potential security risk, so in the real world we would’ve secured it – you can read more about this in the vert.x manual.

      So now we can use the event bus from javascript – how to do it?

      <html>
      <head>
          <title>Vert.x + RapsberryPI + web</title>
      
          <script src="http://cdn.sockjs.org/sockjs-0.3.4.min.js"></script>
          <script src='vertxbus.min.js'></script>
          <script src='jquery-2.0.3.min.js'></script>
      </head>
      <body>
          This is raspberry on vertx lol xD.
      
          <form>
              <label for="box">The button state is: </label>
              <span id="box">UP</span>
          </form>
      
          <script>
      
              var eb = new vertx.EventBus('http://localhost:9999/comm');
      
              eb.onopen = function() {
                  eb.registerHandler('buttonbus', function(message) {
                      console.log("Message from the button: "+message);
                      $("#box").text(message == "1" ? "DOWN" : "UP");
                  });
              }
      
          </script>
      </body>
      </html>
      

      On line 21 you can see how we are registering a handler for “buttonbus” messages that will change the span “box” content to the appropriate message. Obviously you can user vertx.publish() to send messages to the bus, same way we do from Java.

      And that’s it. If all went well you should now have a setup where when pressing a button on your RaspberryPi, you get a message on your server with the state of the button and the same shows up on you web page.

      allofthem

      Conclusion

      I have tried to show you how easy it is to use vert.x as a communication platform between different nodes and how you can you make your rapsberry pi talk to the browser.

      Hope you enjoyed this lengthy post. If you have any comments, or you have found glitches in the text, please give me a shout.

      The full source code can be found on my github.

One thought on “How to use vert.x to make your RaspberryPi talk to your browser?

  • May 24, 2014 at 11:00 pm
    Permalink

    Thanks! Great article, lots of cool ideas, and their implementation!

    Reply

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>