The uWasp project has been on hold for a while as I have been working on another project. I'm calling this a Wireless Reticulation Controller. In fact, I have plans for an entire wireless home automation platform but this just the first real step.
Figure 1 – Reticulation Controller
This is a 4 station domestic reticulation controller which I designed and built. It runs on 24V AC from a plug pack. It has no buttons or display – at least for now. It receives commands via a custom protocol over UHF. The controller utilises the ultra cheap 433MHz radio modules that are available everywhere. I got mine from Little Bird Electronics. More on the RF side of things a bit later on.
The controller simply plugs into an outdoor power socket and any reticulation solenoids terminate on the terminal block. Once powered up, the controller runs a schedule which is uploaded via the RF link. Manual Override is also supported over RF. Any station can be switched on independently and also in any combination – though I need to disable that as I don't want to see too much current draw on the plug pack. The controller receives it's clock over RF, so no battery backup is required. A simple Ping exchange is implemented too. I'm currently seeing a 300ms round trip which is not too bad considering I haven't optimised anything yet. The packet loss can also be measured by the ping facility as a bonus and this help to position the UHF Access Point (more on that later) as multi-path fading is an issue as far as I can tell.
The heart of the controller is a ATMega328p (same as Arduino Uno etc). The firmware is (in my humble opinion) properly designed for extensibility and maintainability. I'm using a simple Task abstraction and a few different libraries for queues and other primitives. AES128 encryption is in place but not activated. I don't plan to activate crypto for my reticulation system. Sure, someone can drive by and turn on my sprinklers – an effective water pressure denial-of-service attack is possible if i'm in the shower at the time. The individual would have to be nearby since the range on the RF modules is not that great... I digress.
UHF Access Point
Figure 2 – UHF Access Point (UAP)
Figure 2 above is the UHF Access Point (UAP) I created to communicate with the controller (and other devices to come later). It connects to my server over a USB-to-RS232 cable from SparkFun. Eventually I want to connect this to a Raspberry Pi to make a nice self contained UAP. I have a headless server at home which is simply a VM host for a number of different VMs – one of which runs my Reticulation Web Application. The Web App talks via UDP multicast (using the fine LCM library) to an RFGateway application which talks to the board above. I'm using socat to move data between the USB port on the VM host and the RF Gateway application which runs inside the guest VM.
Web and RF Gateway Applications
I used the project as an excuse to learn a few new frameworks. The Web Application is written in Sencha's ExtJS 4.1 framework heavily using their new MVC features.
Figure 3 – The Simple Controller
I wrote an administrative interface for the system which can be extended to support different types of devices. Currently it allows for Retic Systems to be defined and the schedule defined too.
Figure 4 – Administrative Web Application
The goal was to build a system that could be evolved toward an entire home automation platform. Another really important goal was to pick an RF technology that was super low-cost – partly because I was really curious as to whether it could be done and partly because I want to have a lot of devices in the network. For example, I might want to put sensors on every window lock or my garage door, or water sensors in the lawn and gardens. I also wanted to allow for hard-wired devices (such as a house Alarm).
Reticulation Controller Architecture
The architecture of the Reticulation Controller is based around a couple of principles:
- Subsystems should be decoupled to the implementation to be changed easily.
- Collaborators should be “injected” using IoC techniques.
- Portability should be maintained in order to allow easy unit testing on a Macbook or a Linux PC.
I imposed a number of design constraints at the hardware level that influence the architecture including:
- The target device is 8-bit AVR with at least 32KB Flash and 1KB SRAM.
- The language would be C++ with no RTTI used.
- The RF interface would be cost optimised.
Low-coupling and high-cohesion is 101 stuff as far as Software Engineering is concerned but you do need to be careful when all you have is 32KB of flash to work with. I wanted to try and structure things well and decided that I would pull back from ideals as space came under pressure. This turned out to be a great choice because I'm only using 50% of flash currently and because I've retained good structure, adding features has been very quick. That said there is lot's of room for improvement and I think I trim off 1-2KB without losing the plot.
I wanted to be able to easily swap out sub-systems to support ease of system evolution, testability and re-usability. I defined or utilised a number of interfaces (using pure virtual classes in C++) such as Task, Handler and Message. Queues are used to communicate Messages between Tasks in system. For example, once a valid ManualControlMessage is decoded by the RFTask, this POCO (Plain Old C++ Object) is placed in the CommandQueue for the CommandPostTask to process. The CommandPostTask pulls the message from the Queue, and using a simple dispatcher feeds it to the appropriate Handler. The figure below shows some of the classes/interfaces in the system.
Figure 5 – Important classes
Most classes within the system heavily rely on Dependency Injection (or IoC). I love this pattern because it let's me unit test components easily. I swap out dependencies during unit testing for mocks that let me capture and assert the correctness of certain behavioural interactions.
Portability was important too. I wanted to be able to develop on my Macbook Air or my Linux PC. I wanted to be able to use tools like Valgrind and CGDB. So, I picked a nice easy subset of C++ and no RTTI (I don't think that is supported on AVR-GCC anyway). The build system is an SConstruct-based contraption. That was new for me as I'm used to Make, Ant, Ivy, Maven and MSBuild/TFS. I like it and I'd definitely use it again.
Reticulation Web Application
The Web Application is a typical n-Tier setup which is written in Java. I decided (after scraping the DJango application) that it was time to have a look at the Play! Framework that i'd heard so much about. I downloaded Play! 2.0 and started reading the tutorials. It took me a long time (probably more than 8 hours) to integrate Maven and Play! together. It was an absolute nightmare but I got it working. You might ask why, after all Play! includes a build system. I didn't want to lose the power of Maven and I wanted the ability to work in Eclipse. The work flow ended up being something like this:
- Make sure everything compiles in Eclispe
- Run a Maven install from the command line
- Run a Play (well SBT) command to pull dependencies from Maven
- Run the Play Server
- Attach debugger from Eclipse
In the end I got sick of this workflow and ported the solution to Jetty. It took only 30 minutes and now I have massive amounts of flexibility back. Please don't read too much into this. Play! Is not design for my type of application. I just wanted to highlight that you do some flexibility in order to maintain a Maven build system. Perhaps these issues have been resolved recently...
The rest of the application is typical. I have a Service (Business Logic Layer) which exposes the functionality of the server. As per defacto-standard Fowler layering, all database transactions (my Unit of Work) are bracketed within the Service Layer. I'm using Hibernate for the Data Access Layer and SQL-Lite at the moment.
The various server side components communicate cross-process via UDP multicast. I'm using the LCM library to make this easy.
In another post I might describe the communications protocol and how it allows (well tries to allow) reliable communication over this type of radio network. I might also explain how I made the PCBs on my Zen Toolworks CNC.