Monday, December 17, 2012

ArduinoFX: A JavaFX GUI for Home Automation with Raspberry Pi and Arduino. Part II

Hi There!

If you haven't read the first part of this series, please take your time, and read about the basic configuration required for the application I'm blogging about in this second part.

Briefly, as a recap, we have an Arduino with a RHT03 temperature and relative humidity sensor and a XBee antenna, plugged in an Arduino shield. The measures are sent wirelessly to a second XBee antenna, plugged via a XBee Explorer to a Raspberry Pi USB port.

In the Raspberry Pi, with soft-float Debian wheezy distro, we have installed Java Embedded Suite 7.0. For now, we are just reading the measures.

Now, if you keep on reading this second part, we are going to create the embedded server in the Raspberry Pi, with the following main tasks: 
  • Back-end task: it will repeatedly read the serial port to get the measures from the Arduino and store them in a database.
  • Web services: it will respond to web requests returning the current values measured.
  • RESTful web services: it will respond to REST requests returning lists in json format with the data measured between two dates.
And then we will create the JavaFX based client application, that will mainly:
  • Connect to the server to get last measures and show them in a LED Matrix Panel control.
  • Connect to the server to get a list of measures between two dates, showing them in a chart. 
  • Show the status of the connection anytime.
Embedded application development is fundamentally cross-platform work. The target device on which the application will be deployed, the Raspberry Pi in this case, doesn't have the hardware resources to support development tools such as Netbeans. Therefore, we must build on our host computer, copy the required build artifacts to the target, and debug and tune the application running on the target. 

1. Setting the Environment

Basically, we should recreate the embedded environment in our PC, so we can create the project in our favourite Java IDE, compile and build it, and then move the jar/war files by ssh to the Raspberry Pi, where we'll use the provided scripts by the Java EmbeddedSuite to run the application. 

As pointed out here, we need at least JDK 1.7, NetBeans 7.1 and Ant 1.8. In that case, follow the next steps to add the required Ant variable JES_HOME:
  • Download JES from here, in case you haven't done it yet following Part I of this series.
  • Unzip jes-7.0-ga-bin-b11-linux-arm-runtime-15_nov_2012 and move all its content to a local folder like C:\Java
  • In Netbeans go to Tools, select Ant Variables, click Add, and define JES_HOME and browse to the folder "jes7.0", and click Ok.

Now we can open the embedded samples projects on NetBeans and build them. We can make any change, rebuild again, and send them by ssh to the Pi, and run them.

2. Modifying HelloService sample

Open this project and check the content of the Ant file build.xml. You will see several customized targets. The first one is used to set the javac compiler arguments, specifying the rt.jar from JES_HOME instead from the regular JAVA_HOME.

<target depends="-pre-init,-init-private" name="-init-user">
    <property file="${user.properties.file}"/>
    <property name="javac.compilerargs" value="-bootclasspath ${var.JES_HOME}/jre/lib/rt.jar"/>
    <property name="default.javac.source" value="1.7"/>
    <property name="default.javac.target" value="1.7"/>
</target>

Now I'm going to make a slight change in the Message string of HelloService.java:

@Path("/")
public class HelloService {

    public static final String MESSAGE = "Hello World from <b>ArduinoFX</b> Embedded Server!";
    
    @GET
    @Produces({MediaType.TEXT_HTML, MediaType.TEXT_PLAIN})
    public String getText() {
        return MESSAGE;
    }

    @GET
    @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
    public HelloBean getTextAsBean() {
        return new HelloBean(MESSAGE);
    }
}

Build the project, and send jar/war files to /usr/java/jes7.0/samples/helloservice/dist/ in your Pi, by ssh. Please check Installation in the first post in case you haven't installed Java Embedded Suite on your Raspberry Pi yet.



Now on your Pi run the sample with the gfhost script and the path to the war file:

cd /usr/java/jes7.0/samples/dist/run/
./gfhost.sh ../../helloservice/dist/helloservice.war


Note it takes around one minute to deploy, so be patient.

Now invoke the service from your web browser. The first time it's called, takes around 15 seconds to respond, but subsequent calls are faster.



Finally, on the server, click Enter to undeploy.
 
3. Embedded Server

Now it's time to create from the scratch our server, with a little help of the provided samples.

These are the steps you need to follow carefully in order for the server to run in your Pi with Java Embedded Suite 7.0.

1. Copy RXTXcomm-2.2pre2.jar to JES_HOME/jre/lib/ext local folder. Do the same in the Pi, copying it to /usr/java/jes7.0/jre/lib/ext.

2. In your Pi, edit /usr/java/jes7.0/samples/dist/run/config.sh and create this variable:

JES_EXT_CLASSPATH="$JES_HOME/jre/lib/ext/RXTXcomm-2.2pre2.jar"

and add it to the classpath:

JES_CLASSPATH="$JES_JAVADB_CLASSPATH:$JES_GLASSFISH_CLASSPATH:

   $JES_JERSEY_SERVLET_CLASSPATH:$JES_EXT_CLASSPATH"

3. Now in Netbeans create a new Java SE application. I'll name it Embedded. Uncheck Create main class.

4. Edit project properties. In Sources, change Source Packages to src/java. In Libraries, add the following jars:
  • JES_HOME/javadb/lib/derby.jar
  • JES_HOME/glassfish/lib/glassfish-jes.jar
  • JES_HOME/jersey/lib/jsr311-api.jar
  • JES_HOME/jre/lib/ext/RXTXcomm-2.2pre2.jar
Finally, in Build/Packaging, uncheck Copy Dependency Libraries

5. Create Embedded/src/webapp and Embedded/src/webapp/WEB-INF folders, and copy web.xml from HelloSuite/src/webapp/WEB-INF.
 
6. Edit build.xml from HelloSuite sample, copy the four last targets, and paste them at the end of Embedded/build.xml. In this way rt.jar will be selected from JES_HOME to compile the project, and the war will be created. In the last two targets change hellosuite.jar for embedded.jar and hellosuite.war for embedded.war.

7. Add a class with all the required JAX-RS web services, com.jpl.embedded.EmbeddedREST. Basically it should have two services: 
  • Return the last reading of the sensor, in json format.
  • Return an array of readings between two dates, in json format.
8. Add a class com.jpl.embedded.JAXRXConfig to register this latter class:

@ApplicationPath("/")
public class JAXRXConfig extends Application {

    @Override public Set<Class<?>> getClasses() {
        final Set<Class<?>> classes = new HashSet<Class<?>>();
        // register root resource the first time there is a REST request
        classes.add(EmbeddedREST.class);
        return classes;
    }
}

This servlet must be registered in the web.xml file, modifying the servlet from HelloSuite:

<servlet>
   <servlet-name>com.jpl.embedded.JAXRXConfig</servlet-name>
</servlet>

9. Finally, add a servlet com.jpl.embedded.ConfigServlet. It must be loaded just after deploying the project, so the database is created (only the first time) and the connection is established. Also we start a scheduled task to read the serial port, and storing the measures periodically. When the project is undeployed, it should stop this task and close the serial port.

In order to load RXTXcomm, which uses native code, a system property must be set before starting the task:

@WebServlet(urlPatterns={"/ArduinoOnline"}, loadOnStartup=0)
public class ConfigServlet extends HttpServlet {

    static {
        System.setProperty( "java.library.path", "/usr/lib/jni" );
    }
    
    private XBee xbee;
    
    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        
        // Initialize BDD
        CStore.getInstance();
        
        // Initialize Serial communication, starts reading port
        xbee=new XBee();
    }
    
    @Override public void destroy() {
        xbee.disconnect();
    }
}

10. The rest of auxiliary classes we'll use are:
  • com.jpl.embedded.comms.Serial. Connect to serial port and read measures from Arduino, via XBee antennas.
  • com.jpl.embedded.model.BeanHT. JavaBean with temperature and humidity values and time of reading.
  • com.jpl.embedded.model.CSensor. Singleton with the most recent BeanHT read.
  • com.jpl.embedded.service.CStore. Singleton to open and close the connection to the database, and to write and read BeanHT values.
  • com.jpl.embedded.service.XBee. Open and close the connection to the serial port, and start a scheduled task to record BeanHT values every 30 seconds in the database.
All the source code for java classes mentioned in points 7 to 10 can be found in my GitHub repository. Feel free to clone it and use the code to test your own embedded server.

So finally, we can compile and build the project. If everything is in place, we could send embedded.jar and war to /usr/java/jes7.0/samples/embedded/dist in the Pi by ssh.

11. To deploy the server, in your Raspberry Pi:

cd /usr/java/jes7.0/samples/dist/run/
./gfhost.sh ../../embedded/dist/embedded.war

Note the deploy takes around one minute. After that, the servlet is initialized, so the database connection is established and the serial port connection is opened. The background task starts and the measures coming from the Arduino are read and stored in the database.



12. Now we can test the different web services, from a browser. 

Test the servlet. It takes around 18 seconds to load, but only the first time.



Test the RESTful web services. The first run takes around 80 seconds to complete.





Finally, to undeploy the server, just press <Enter> twice on the terminal. All the tasks will be smoothly stopped, and serial port and database connections will be closed.



4. The JavaFX GUI

Now we are going to design the JavaFX based client, a simple UI with three main tasks:
  • Connect to the embedded server to get last measures and show them in a MatrixPanel control.
  • Show the status of the connection anytime.
  • Connect to the server to get a list of measures between two dates, showing them in a chart. 
User Interface

First, let's start by describing the user interface. With the help of the JavaFX Scene Builder the basic layout is done.


There're three main boxes, ready to hold several custom controls from the JFXtras project, that will be added from the controller:
  • A top VBox for the MatrixPanel control. This LED panel like control will show the last values of temperature and relative humidity read from the server every 30 seconds.
  • A central HBox for the CalendarTextField and ChoiceBox controls. These controls will allow the user to choose an initial date and an ending date to ask for the values stored in the database in the server. The ChoiceBox allows you to select the number of items readed between these two dates.
  • A bottom HBox for the SimpleIndicator. It will simply show if the connection is established to the server (green) or not (red).
In the controller class, these controls are first created, and later are added when the initialize method is called.
 
    private final MatrixPanel animatedPanel = 
          MatrixPanelBuilder.create()
                            .ledWidth(192).ledHeight(18)
                            .prefWidth(650.0).prefHeight(400.0)
                            .frameDesign(FrameDesign.DARK_GLOSSY)
                            .frameVisible(true)
                            .build();
    
    private final CalendarTextField lStartCalendarTextField = 
                                new CalendarTextField().withShowTime(true);
    private final CalendarTextField lEndCalendarTextField = 
                                new CalendarTextField().withShowTime(true);
        
    private final SimpleIndicator indicator = SimpleIndicatorBuilder.create()
                               .prefHeight(40).prefWidth(40)
                               .innerColor(Color.rgb(0,180,0).brighter())
                               .outerColor(Color.rgb(0,180,0).darker())
                               .build();
    @Override
    public void initialize(URL url, ResourceBundle rb) {
   
        vbox.getChildren().add(0,animatedPanel);
        hbox.getChildren().addAll(lStartCalendarTextField,lEndCalendarTextField);
        hbox.getChildren().add(sizeChoiceBox);
        hboxStatus.getChildren().add(0, indicator);

        ...
    }

So when the application is launched, it will look like this:


Rest services

When the application starts, a scheduled task is launched with the purpose of repeatedly ask the server for the last values of temperature and humidity. This values are then passed to the content of the matrixpanel.

    private long EVENT_CYCLE = 30000; // ms
    private final ScheduledExecutorService scheduler = 
                    Executors.newSingleThreadScheduledExecutor();
    private ScheduledFuture scheduleAtFixedRate = null;
    
    @Override
    public void start(Stage stage) throws Exception {
        
        scheduleAtFixedRate = scheduler.scheduleAtFixedRate(new LastHT(), 0, 
                               EVENT_CYCLE, TimeUnit.MILLISECONDS);
        ...
   }

Where LastHT class perform a web request to http://<IP>:<PORT>/embedded/last REST service and reads the last measured values from response in json format, deserializing it to a BeanHT object.

This object is then stored, and if any of temperature or humidity have changed, the matrixpanel content is updated. For that, a JavaFX thread must be used.
 
Platform.runLater(new Runnable() {

    @Override
    public void run() {
        Content contentTemp = ContentBuilder.create()
                        .color(MatrixColor.GREEN)
                        .type(Type.TEXT)
                        .txtContent("Temperature: " + String.format("%.1f",
             MonitoringServiceStub.getInstance().getLastMeasure().getTemp()) + " ºC")
                        .font(MatrixFont.FF_8x16).fontGap(Gap.SIMPLE)
                        .origin(0, 1).area(0, 0, 191, 18)
                        .align(Align.RIGHT).effect(Effect.SCROLL_LEFT)
                        .lapse(20).postEffect(PostEffect.PAUSE)
                        .pause(3000).order(RotationOrder.FIRST)
                        .build();
        ...
        animatedPanel.setContents(Arrays.asList(contentTemp, contentHum));
    }
});

When the user clicks on the Evaluation button, the request for a list of values between two dates starts. But since the server is a tiny computer with low CPU power, it will take some time to be performed. For that reason, we need to set this as a task from a service.

Service<void> chartService=new Service<void>(){

    @Override
    protected Task<void> createTask() {

        return new Task<void>(){

            @Override
            protected Void call() throws Exception {

                ChartHT ht=new ChartHT(
                      lStartCalendarTextField.getValue().getTimeInMillis(),
                      lEndCalendarTextField.getValue().getTimeInMillis(),
                      sizeChoiceBox.getSelectionModel().getSelectedItem().toString());
                
                ht.run();

                return null;
            }                    
        };
    }
};

@FXML
public void getEvolution(ActionEvent a){        
    chartService.restart(); 
}

The way we will know the task has been completed (maybe a minute later) is looking for changes in the stateProperty of the service. 

When its value reach State.SUCCEEDED, we can proceed with creating the chart and plotting the data deserialized from the json array returned by the server, again in a new JavaFX thread:

chartService.stateProperty().addListener(new ChangeListener<state>(){

    @Override
    public void changed(ObservableValue ov, State t, State t1) {
        if(t1==State.SUCCEEDED) {

            Platform.runLater(new Runnable() {

                @Override
                public void run() {

                    final CategoryAxis xAxis = new CategoryAxis();
                    final NumberAxis yAxis = new NumberAxis();

                    final LineChart<String,Number> lineChart = new 
                             LineChart<String,Number>(xAxis,yAxis);

                    XYChart.Series series1 = new XYChart.Series();
                    series1.setName("Temperature (ºC)");
                    XYChart.Series series2 = new XYChart.Series();
                    series2.setName("Relative Humidity (%)");

                    for(IObservableMeasure d : 
                          MonitoringServiceStub.getInstance().getChartMeasures()){
                        series1.getData().add(new XYChart.
                                  Data(d.getTime(),d.getTemp()));
                        series2.getData().add(new XYChart.
                                  Data(d.getTime(),d.getHum()));
                    }

                    lineChart.getData().addAll(series1,series2);

                    hbox2.getChildren().add(1,lineChart);
                }
            });
        }                
    }
});

All the source code of this project is in my GitHub repository. Feel free to clone it, and test it. Once you have installed the embedded server in your Raspberry Pi, you will need to set the IP address and port in the client:

public class MonitoringServiceStub implements MonitoringService {    
    /* SET YOUR SERVER IP AND PORT HERE */
    public static final String urlServer="http://192.168.0.39:8080";  
    ...

Finally, this is a short video of the JavaFX client in action.


Conclusion

Here I conclude this new proof of concept. As a recap, we have communicated an Arduino with a RHT03 temperature and relative humidity sensor and a XBee antenna, wirelessly to a second XBee antenna, plugged via a XBee Explorer to a Raspberry Pi USB port.

In the Raspberry Pi, with soft-float Debian wheezy distro, we have installed Java Embedded Suite 7.0. We have created an embedded server in the Pi, with the following main tasks: 
  • Back-end task: it repeatedly reads the serial port to get the measures from the Arduino and store them in a database.
  • Web services: it responds to web requests returning the current values measured.
  • RESTful web services: it responds to REST requests returning lists in json format with the data measured between two dates.
And then we have created the JavaFX based client application, that mainly:
  • Connects to the server to get last measures and show them in a LED Matrix Panel control.
  • Connects to the server to get a list of measures between two dates, showing them in a chart. 
  • Shows the status of the connection anytime.
If you have followed this two part series post, I hope it has caught your attention, and you're willing to give it a try. Let me say here: PLEASE, DO IT AT HOME!!

I'd love to hear from you if you have any questions regarding the setup of this project, or any part of it.

Thursday, December 13, 2012

ArduinoFX: A JavaFX GUI for Home Automation with Raspberry Pi and Arduino. Part I

Hi there!

I'll make a little break to the NXTLegoFX series posts, and blog about a very similar application I've made the last week: ArduinoFX. It's a JavaFX based simple GUI for remote monitoring and control of sensors, intended mainly for home automation. Though, to be fair, it's mainly a proof of concept.

More or less, both JavaFX applications share the same architecture, though the difference is now the back-end: instead of the Mindstorms Lego NXT now we've got an Arduino Uno with a low cost digital humidity and temperature sensor, RHT03.

Also, as a server, instead of a regular computer, I'll be using a Raspberry Pi, a single-board tiny computer with an ARM1176JZF-S CPU, powered with the new Java Embedded Suite 7.0, just released by Oracle in October 2012.

And for comunnications, instead of leJOS and Bluetooth, Arduino and Raspberry Pi will be connected wirelessly by two XBee antennas, using ZigBee protocol.

I'll try to describe briefly each and everyone of this components, focusing in how to install what's needed, and with each one ot them I'll make a simple test, so this could serve as a guide for thouse of you who want to give it a try.

This first part deals with all the hardware stuff, and the basic software required to work out, and I leave for Part II the JavaFX application and the embedded server development. 

Disclaimer: I'm not responsible in any way for what you do on your spare time with what I say here! The following procedures are provided without any warranty. Also, you should know by now that I'm not related to any of the companies mentioned in this blog.

Bill of Materials

Main components requiered to follow this guide:




 1. Arduino

I'm using an Arduino Uno, revision 3, a microcontroller board based on the ATmega328, with 14 digital input/output pins, 6 analog input pins, USB connection, power jack, operating at 5 V, with 32 kB of flash memory and a 16 MHz clock speed. 

It can be programmed easily with its own IDE. Its language is an implementation of Wiring. Programs are written in a simplified version of the C++ language, although only two main functions are needed to make a runnable program: setup(), a function run once at the start of a program, and loop(), a function called repeatedly until the board is powered off. 

For monitoring temperature and relative humidity values in my room, I have a DHT22 sensor, also known as RHT03. You can find here the schematics and here an open source library to read these values. You must install it in the libraries folder of Arduino IDE, before compiling your project.

Using a breadboard, connect pin 1 of the sensor to the 5 V pin of Arduino board. Pin 2 goes to Arduino pin 7, using a 1 kΩ pull-up resistor. Pin 4 goes to Arduino board ground. There're few blogs out there where you can find more detailed instructions, like this.

Let's add now a XBee antenna, so the data can be send remotely to a second antenna plugged in another Arduino or in a XBee Explorer plugged in the USB port of a computer. To connect the antenna with the Arduino I'll use an Arduino XBee Shield, from Libellium, though you can use other similar shields, or even plug the XBee on the breadboard through a breakout board.

Here it's the schematics done with the open-source tool Fritzing. The XBee is plugged on to the shield, and this is plugged on Arduino (according to the dotted purple line in the picture below). Note also the wire from pin 2 is reconnected through pin 7 on the shield.

Important tips (that work for me, at least): 
  • Never plug/unplug the shield with the Arduino powered on. 
  • Always power off, and then unplug the shield before loading the code to the Arduino. 
  • Then plug the board to the USB port, download the code, and unplug the USB. 
  • Finally, plug the shield and then power on. 
  • Remember that the jumpers on the shield must be on the XBee pins (on the two pins towards the interior of the board, see the picture below).

And this is how I did it.

Code

This is the code to make the Arduino microcontroller print the values of the measures taken by the sensor through the serial port:

#include <dht22.h>
#include <stdio.h>

// Data wire is plugged into port 7 on the Arduino
#define DHT22_PIN 7
// Setup a DHT22 instance
DHT22 myDHT22(DHT22_PIN);
char buf[128];

void setup(void)
{
  Serial.begin(9600);
  Serial.println("DHT22 Library Loaded");
}

void loop(void)
{ 
  DHT22_ERROR_t errorCode;
  // minimum 2s warm-up after power-on, then read every 2 seconds.
  delay(2000);  
  errorCode = myDHT22.readData();

  switch(errorCode){
      case DHT_ERROR_NONE:                
             sprintf(buf, "{%hi.%01hi,%i.%01i}",myDHT22.getTemperatureCInt()/10,
               abs(myDHT22.getTemperatureCInt()%10),
               myDHT22.getHumidityInt()/10, myDHT22.getHumidityInt()%10);
             Serial.println(buf);
             break;
      case DHT_ERROR_CHECKSUM:      Serial.print("check sum error "); break;
      case DHT_BUS_HUNG:            Serial.println("BUS Hung "); break;
      case DHT_ERROR_NOT_PRESENT:   Serial.println("Not Present "); break;
      case DHT_ERROR_ACK_TOO_LONG:  Serial.println("ACK time out "); break;
      case DHT_ERROR_SYNC_TIMEOUT:  Serial.println("Sync Timeout "); break;
      case DHT_ERROR_DATA_TIMEOUT:  Serial.println("Data Timeout "); break;
      case DHT_ERROR_TOOQUICK:      Serial.println("Polled to quick "); break;
    }
  }
}

To download the compiled code, just open the Arduino IDE, create a new sketch, paste the code and verify it. Then plug the Arduino without the shield, and without any wires connected, and select your serial port in Tools->Serial Port. Then download the compiled code, and unplug the USB cable.


Test #1

Let's make a simple test, before going any further, to check the Arduino works properly. Connect the sensor but not the shield nor the XBee, so sensor's pin 2 goes straight to pin 7 in the Arduino board. Plug again the USB cable, and in the Arduino IDE go to Tools->Serie Monitor, and you should see the measures appearing on the screen:


2. XBee

In order for the antennas to be connected, it is neccessary to establish a ZigBee network between them. For that, Digi International software X-CTU is required (only works in Windows, for other OS see xbeeconfigure sketch). 

Also, it's recommended to use a XBee Explorer, so just by attaching a mini USB cable you will have direct access to the serial and programming pins on the XBee unit. Otherwise, you'll have to use the access through the Arduino board, but changing the jumpers in the shield to the USB position and removing the microcontroller, which is always a little bit risky.


Anyway, for our project we'll need this Explorer, as we intend to connect it to the Raspberry Pi USB port.

There are quite good blogs out there showing how to configure both antennas (like this or this), so I'm going to give just a short description of how I do it.

Coordinator XBee #1

First, with the XBee #1 in the Explorer, plugged to the USB port, open the X-CTU application and select the correct USB serial port from the list displayed in the PC-Settings tab.

Then, go to Modem Configuration tab, uncheck Always update firmware and click on Read button and wait a few seconds. A valid name should appear under Modem label. Otherwise, click on Download new versions button, and try again.

Once you've got a right modem (in my case XB24-ZB), on the function set list, select Zigbee Coordinator AT. See left picture below. This one should be afterwards plugged to the Raspberry Pi.

A few parameters must be set:
  • Networking, ID: Pan ID. The network ID, 0 to 0xFFFF. For instance, 1111
  • Addressing. NI: Node Identifier, for instance COORDINATOR
  • Addressing. DL: Destination Address Low: 0 
  • Serial Interfacing. BD Baud Rate, 9600

then click Write button, and these parameters will be stored in your XBee #1. Close X-CTU and unplug the Explorer.


Router XBee #2

Plug on the Explorer the second XBee, and start again X-CTU. Choose the serial port and read the modem parameters. Now select Zigbee Router AT and set these parameters:
  • Networking, ID: Pan ID. The network ID, the same as #1: 1111
  • Addressing. NI: Node Identifier, for instance ARDUINO
  • Addressing. DL: Destination Address Low: 0 
  • Serial Interfacing. BD Baud Rate, 9600
Check that the Operating Channel is the same for both (CH=19). Then click Write button, and these parameters will be stored in your XBee #2. See right picture above. Close X-CTU and plug this anntena on the Arduino shield.

Note: You can use also AT commands in the Terminal Tab, just by entering +++ and waiting for an OK response. Then you can get or set the usual parameters, with AT and the parameter code: ATID, ATNI, ATDL, an so on.

Though this configuration is pretty simple, it gives you the idea of how you could set a mesh of nodes around the same coordinator, in case you have several arduinos around your house, with their own XBee antenna.


 Source: http://www.rfwireless-world.com/Tutorials/Zigbee_tutorial.html

Test #2

So let's now check if the ZigBee network is working properly. Let's plug the shield with the XBee #2 on the Arduino board, check the RHT03 connections (its pin 2 now goes through pin 7 in the shield) and power on the Arduino. Then plug the XBee #1 via Explorer to the PC and start X-CTU, select serial port, read the modem and go to Terminal tab to see the readings that should appear:

Otherwise, please check carefully the previous steps. Note that instead of X-CTU you can use any hyperterminal like software in your OS.

3. Raspberry Pi

First of all, we need to set the Raspberry Pi. For that you can follow this guide, or this. Briefly, you need:
  • A Raspberry Pi model B (with 256 or 512 MB RAM)
  • A USB keyboard and USB mouse (optional)
  • A display with HDMI, a HDMI cable, or a display with DVI and a HDMI to DVI conversor
  • A power supply of 5 V and minimum 0.7 A, with micro USB connector (some mobile chargers will do).
  • And a SD card, 4 or 8 GB, not-generic, class 6 to 10 recommended.

In order to install Java Embedded, for now we must use soft-float Debian wheezy image. Download it from here here, extract it and write it to the SD with Win32DiskImager for Windows. For other OS please check here.

Once the SD card is ready, insert it in the socket below the Raspberry Pi, connect the display and the keyboard and power on. Then it should boot up, and enter in the raspi-config menu, where we are going to config a few things (look here for a further explanation):
  • expand-rootfs: Press ok to use the whole SD card space.
  • change_locale: from en_GB.UTF8 to es_ES.UTF8 in my case, select yours.
  • change_timezone: Select continent (Europe) and major city (Madrid, in my case).
  • memory_split: you can give only 32MB to video, leaving the rest for the ARM, as in this case we're developing a server. You can change this later on.
  • ssh: Press enable to allow ssh connections.
Select Finish and the Pi will reboot.

Network

Now let's setup the network. My advise is that you set a static IP address. For that (look here for further instructions), edit with root privileges this file:

sudo nano /etc/network/interfaces

And change dhcp for static, adding your IP and LAN data configuration. This is mine:

auto lo
iface lo inet loopback
iface eth0 inet static
address 192.168.0.39
netmask 255.255.255.0
gateway 192.168.0.1

Save (Ctrl+O) and exit (Ctrl+X). Now edit this other file:

sudo nano /etc/resolv.conf

and add your DNS nameservers. This is my data:

nameserver 192.168.0.1
nameserver 62.42.230.24
nameserver 62.42.63.52

Save and exit, reboot and plug in the ethernet cable. Now we're able to install software from the repository, like a VNC server, so we can access remotely to the Pi headless, without display, keyboard nor mouse:

sudo apt-get install tightvncserver

After it has been installed, type:

sudo /usr/bin/tightvncserver

When prompted, select a password for remote users. Allow it to start at boot time, editing the file: 

sudo nano /etc/rc.local

At the end type:

su -c "/usr/bin/tightvncserver -geometry 1280x1024" pi

Save, exit and reboot. Now from your favourite VNC client try to connect to the Pi, using its IP address, the port 5901, and the specified password for remote users.

Test #3

In order to read serial port communications install minicom:

sudo apt-get install minicom

Then plug in the XBee #1 via Explorer in the USB port of the Pi. Power on the Arduino, and start minicom:

minicom -b 9600 -o -D /dev/ttyUSB0

You should see the readings appearing on the screen:


To close it, press Ctrl+A+Z+X.

4. Java Embedded Suite 7.0

It was launched by Oracle at the end of September 2012. As you can read here,
  • Oracle Java SE Embedded 7 provides runtime for Java embedded applications
  • Java DB provides a database to store local content securely
  • Glassfish for Embedded Suite provides an application server for Web pages
  • Jersey RESTful Web Services Framework for hosting and accessing Web services.
with the main goal of optimization for embedded devices and server systems.

 
Installation

In your PC, download the distribution for Raspberry Pi (ARM v6 soft-float) from here and the samples from here. Now connect by ssh and go to directory /home/pi and make a new directory there, install. Then copy both files to /home/pi/install.

Now on your Pi, go to /home/pi/install and unzip the code bundle, which creates /home/pi/install/jes7.0/Unzip also the samples bundle, which creates /home/pi/install/jes7.0/samples/. Then delete the bundles:


unzip jes-7.0-ga-bin-b11-linux-arm-runtime-15_nov_2012
rm jes-7.0-ga-bin-b11-linux-arm-runtime-15_nov_2012
unzip jes-7.0-ga-b11-linux-samples-15_nov_2012.zip
rm jes-7.0-ga-b11-linux-samples-15_nov_2012.zip

Now with root privileges create /usr/java directory and move /home/pi/install/jes7.0 to /usr/java:

sudo mv jes7.0 ../../../usr/java

Finally, we need to add to PATH the route for Java, and add a JAVA_HOME variable. For that edit the file:

sudo nano /etc/bash.bashrc

And nearly at the end, add:

export PATH=/usr/java/jes7.0/jre/bin:$PATH
JAVA_HOME="/usr/java/jes7.0/jre"
export JAVA_HOME

Save and exit, and reboot. Login, and check if everything is fine by typing java -version:


You should try now all the samples from the Suite that come within the bundle, following this guide, going to /usr/java/jes7.0/samples/dist/run directory.

Test #4
 

The next step in our tests is check if we can read the serial port with Java Embedded. For that we'll make a small project to read the serial port. First of all, we need to install RXTXcomm library and test java embedded serial reading with xbee.jar.

sudo apt-get install librxtx-java

It will install /usr/share/java/RXTXcomm-2.2pre2.jar. Back on your PC, create a new project in your Java IDE, with the class listed below, add this jar (copy it by ssh from your Pi), compile and build the project, and send it to the Pi by ssh (both jars), to /home/pi/java, for instance.

public class EmbSerial {

    private CommPort m_commPort=null;
    private SerialPort m_serialPort=null;
    
    public void connect( String portName ) throws Exception {
        
        CommPortIdentifier portIdentifier = 
                           CommPortIdentifier.getPortIdentifier(portName);
        if(portIdentifier.isCurrentlyOwned()){
            System.out.println( "Error: Port is currently in use" );
        } else {
            int timeout = 2000;
            m_commPort = portIdentifier.open(this.getClass().getName(), timeout);
            if( m_commPort instanceof SerialPort ) {
                m_serialPort = (SerialPort)m_commPort;
                m_serialPort.setSerialPortParams(9600, SerialPort.DATABITS_8,
                                SerialPort.STOPBITS_1, SerialPort.PARITY_NONE );
                final InputStream in = m_serialPort.getInputStream();
                new Thread(){                    
                    @Override public void run() {
                        byte[] buffer=new byte[1024];
                        int len = -1;
                        try {
                            while((len = in.read(buffer))>-1) {
                                System.out.print(new String(buffer,0,len));
                            }
                        } catch( IOException e ) {
                            System.out.println("Error reading: " + e.getMessage());
                        }
                    }  
                }.start();
            } else {
                System.out.println( "Error: Not a serial port" );
            }
        }
    }
        
    public void disconnect(){
        if(m_serialPort!=null){
            m_serialPort.removeEventListener();
            m_serialPort.close();
        }
        if(m_commPort!=null){
            System.out.println("Port closed");
            m_commPort.close();            
        }
    }
    
    public static void main(String[] args) {        
        final EmbSerial serial=new EmbSerial();        
        try {
            serial.connect("/dev/ttyUSB0");
        } catch(Exception e) {
            System.out.println("Error connecting: " + e.getMessage());
            return;
        }
        
        Runtime.getRuntime().addShutdownHook(new Thread(new Runnable() {
            @Override public void run() {
                serial.disconnect();
            }
        }));
    }
}

Run it by:

java -Djava.library. path=/usr/lib/jni -jar EmbSerial.jar

You should get the readings on the terminal. Press Ctrl+C to finish.



Part I conclusion

Well, if you have followed closely the detailed procedures and performed successfully all the tests, congratulations!

Now you're ready for bigger adventures, so in the next part of this series we'll create the embedded server in the Raspberry Pi: 
  • Back-end task: it will repeatedly read the serial port to get the measures from the Arduino and store them in a database.
  • Web services: it will respond to web requests returning the current values measured.
  • RESTful web services: it will respond to REST requests returning lists in json format with the data measured between two dates.

And we will create the JavaFX based client application, that will mainly:
  • Connect to the server to get last measures and show them in a LED Matrix Panel control.
  • Connect to the server to get a list of measures between two dates, showing them in a chart. 
  • Show the status of the connection anytime.
This is a preview of this app:


Please, have a breath after this really long post and, if you're ready, continue reading Part II. In the meantime, I'd love to hear any comments from you.