Remote sensors and mobile access: a simple exercise (part 2)

Following from a previous post, in this part I will highlight the coding section of the exercise aiming to a very simple goal: enable mobile access to a remote sensor reading.

With reference to the architectural schema, I will focus on the left-hand side:

Architectural schema to address the exercise’s goal: “enable mobile access to a remote sensor reading”.

In this case I opted to make use of the Spring framework, to follow a structured approach while being able to deploy everything inside a plain Tomcat server; I will reserve my JavaEE 6 for a different exercise, this time I really wanted to play around with Spring.

So overall the dependencies from a Java perspective are:

  • XBee API
  • RXTX – this is for serial communication over USB, enabled by the FTDI chip / breakout board on which the XBee coordinator is mounted on (detailed in the previous post)
  • Spring
  • CXF RS – this is for making use of REST webservices
  • JUnit, logging, etc.

In turn the POM, as I like to Maven stuff, looks like this:

Screen Shot 2012-12-02 at 15.05.36

Then I developed the REST webservice which will buffer all the readings from the XBee; when the webservice is consumed, the call will de-spool all the buffered readings from the buffer and place it on the webservice response.

I’m going to describe this webservice in two steps. First, is the webservice class declaration along with the constructor code, extract:

@Service("xbeeService")
@Path("/xbee")
public class XBeeService implements PacketListener {

	private XBee xbee;
	private Queue queue = new ConcurrentLinkedQueue();

	public XBeeService() throws XBeeException {
		xbee = new XBee();
		try {
			xbee.open("/dev/tty.usbserial-A4004CwJ", 9600);
			xbee.addPacketListener(this);
		} catch (Exception e) {
			// TODO no xbee
		}
	}

	@Override
	public void processResponse(XBeeResponse arg0) {
		queue.offer(arg0);
	}
  • It is a Spring’s Service, line 18.
  • It is also a CXF REST webservice available on the “xbee” URL path, line 19; more on this later.
  • It implements the PacketListener interface, meaning I can setup this class to be a subscriber and notified every time it’s incoming a packet from the Coordinator XBee, line 20.
  • Every time a packet is incoming will be placed on an internal buffer, line 35.
  • The buffer is actually a Queue of XBeeResponse packets, and implemented with a proper java.util.concurrent class in order to support concurrency (as from one side the XBeeResponse will need to be buffered every time they are incoming from the XBee Coordinator, meanwhile the webservice call will need to consume the same XBeeResponse packets from the buffer), line 23.
  • The constructor on line 25 make sure all the stuff are properly initialized at Spring container start. Because as mentioned earlier, this is a Spring Service class.

So now that the webservice class has all the code in order to be properly initialized and listen for XBeeResponse and place them on the buffer, it’s time to implement the code for the webservice call, extract:

	@GET
	@Produces("text/plain")
	public String getReading() {
		if (!xbee.isConnected()) {
			return "<p>No xbee connected.</p>";
		}
		StringBuffer sb = new StringBuffer();
		XBeeResponse response;
		while ((response = queue.poll()) != null) {
			try {
				ZNetRxIoSampleResponse ioSample = (ZNetRxIoSampleResponse) response;
				sb.append("<p>Sample from " + ioSample.getRemoteAddress64());
				if (ioSample.containsAnalog()) {
					sb.append(" - 10-bit temp reading (pin 19) is " + ioSample.getAnalog1()+"</p>");
				}
			} catch (ClassCastException e) {
				// TODO not an IO Sample
			}
		}
		return sb.toString();
	}

So this method will be invoked every time I submit a HTTP GET request at the “xbee/” URL:

  • It will check for the Xbee to be properly initialized, otherwise a simple dummy message is returned, line 43.
  • Otherwise, for every XBeeResponse packet de-spooled/consumed from the internal buffer, line 48, a simple string of the reading in English language is returned.
  • You can notice every line of message, being the former or latter case, is decorated by the HTML p tags.

So it’s now the turn of the web.xml descriptor, which role is to kick-start the Spring container and the CXF stuff, extract:

<web-app>
  <display-name>Archetype Created Web Application</display-name>
  <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>WEB-INF/beans.xml</param-value>
    </context-param>
    <listener>
        <listener-class>
            org.springframework.web.context.ContextLoaderListener
        </listener-class>
    </listener>
    <servlet>
        <servlet-name>CXFServlet</servlet-name>
        <display-name>CXF Servlet</display-name>
        <servlet-class>
            org.apache.cxf.transport.servlet.CXFServlet
        </servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>CXFServlet</servlet-name>
        <url-pattern>/ws/*</url-pattern>
    </servlet-mapping>

Then it’s the turn of the Spring beans.xml file for the actual Spring components, extract:

    <import resource="classpath:META-INF/cxf/cxf.xml"/>

    <context:component-scan base-package="net.tarilabs.test"/>
    
    <jaxrs:server id="restContainer" address="/">
        <jaxrs:serviceBeans>
            <ref bean="ciaoService"/>
            <ref bean="xbeeService"/>
        </jaxrs:serviceBeans>
    </jaxrs:server>

Which will scan the package “net.tarilabs.test” (line 12) where I got the @Service annotated class for the webservice, which will be a proper Spring bean in the container, which I later bind to the jaxrs:server (line 17).

Now that the server backend is fully implemented, it’s now turn for some HTML.

I incorporate my favorites: Twitter Bootstrap templates, and jQuery. Then in the html page I just place the following div container:

      <div class="well logarea" id="thelogarea">
      <p>mocking</p>
      </div>

Meaning it will be rendered as a Twitter Bootstrap well, containing a default p paragraph line, but it’s also a CSS logarea which I defined as:

.logarea {
  min-height: 300px;
  max-height: 300px;
  overflow-y:auto;
}

in order to have some pre-defined height dimensions.

Now, it’s time for some jQuery magic: from the user’s browser, will poll the REST webservice to obtain new content to place inside the mentioned div:

function doUpdate() {
	  $.ajax({type: "GET", url : "./ws/xbee",
	          success: function (data) {
	             if (data.length > 0)
	             {
	                $("#thelogarea").append("<p>"+data+"</p>");
	                var divx = document.getElementById("thelogarea");
	                divx.scrollTop = divx.scrollHeight;
	             }
	             setTimeout("doUpdate()", 2000);
	           }});
	}
	                                          
$(document).ready(function(){
	setTimeout("doUpdate()", 2000);
});

Specifically, consume the REST webservice via ajax call and on success, append the response of the webservice call inside the div (this is the reason why the webservice replies with html p line statements) and then programmatically move the div scrollbar all the way down to the bottom of it – simulating the trail command in Linux.

Time to deploy it on Tomcat and experience all the components working nicely all together:
Overview of the implementation modules and component which perform the goal: mobile access to a remote sensor reading.

Why do I blog this

This is the conclusion of this exercise; I reached my goal, enable mobile access to a remote sensor reading, by making use of some simple electronics and XBee modules, while for the coding part I leveraged the xbee-api with Spring and CXF REST webservices, along HTML5 and jQuery to access the data via mobile access.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s