During some point in time (say T element of N) my colleague – Joost – was explain his home-automation efforts he was progressing using tech from KNX. He introduced me to a certain piece of software (OpenHab), he had come across. So reading into this (Java based) project (and all it’s marvelous plugins and apps in particular), it entangled my into it’s grip. (Yes,they support IOS and Android)
Caught by the idea of doing something similar (on the cheap), I started reading into the ways this software work. Although I’m not a particular fan regarding OSGI, I got in deep.
Wanting to utilize my bulk buy (3 pieces) of TI’s launchpad for something more useful than driving digital leds (WS2811, are very cool btw!), I started digging into it.
As a proper brogrammer is opted to do, I looked around for the quickest way to get going with these babies. Not that the TI is a very complex processor, its 16bits, has a couple of timers and so forth. But it is main selling-point is being particularly energy efficient. It’s functionally wise a trimmed down Atmega cpu (being it a different architecture and bus-width all asside), its a hobby-bob cpu, little flash and ram. However semmingly simple as these cpus may be, radios and all there registers are more of a challenge.
So after reading some nice stuff about Energia (a spinoff from the Arduino (Atmel Atmega cpus) IDE) and the NRF24L01+ radios, I was very pleased to find that some clever dude wrote a nice noob-proof library to utilize these radios on the Energia platform. For those not known to Arduino’s, Processing and other MumboJumbo, its basically an abstraction layer to hide away registers, timers and creepy stuff, making prototyping very fast (at the expense of not being able to harness all features in the most efficient way) (like energy saving in LPM4-mode, however for this project more than adequate, and very pleasent to work with! For example: one can address a PWM (pulse-width-modulation) with two lines of setup (and analogWrite(uint8_t value, pin-number). Instead of setting-up counter(s), top levels and the proper registers to do all …. sjit.
Anyway, utilizing Energia, the libraries which are included in the core, and the library for the radio (did I mention it was very cheep at $12 for 10 pieces), I can control the radios, which are quite fast by the way, a theoretical speed of 2.0 Mbit/s :). So more then plenty of throughput to do some simple stuff, like few values. One the nice thing of these radio’s is is there relatively ease of use, each message is send to a receiver, which should be listing on a mutual known address, the payload per package is 32bytes, and checksumming, acknowledging and re-transmission is – in certain modes – handled by the transceiver itself, so less stuff for me to implement 🙂
After some messing about with my soldering iron, one of my nodes looks like this:
For those eager to know the parts:
- Resitor(s) 470 and 1M ohm
- AMS1117 3.3 volt regulator
- 3x TIP122 NPN Transistor (or equivalent)
- 3x 4.7K Resitor
- Prototype (double-sided) PCB
TBC: ~ $5
My ‘server’ node (which is basically the same, only no additional components like leds, and high-power(is) Transistors, just the launchpad, and the radio (will be in a future version a dedicated pcb with a $2 usb -> LVTTL converter
Ofcourse this hardware is completely useless without firmware/software, so via these two github repositories, you can find the code for both the hardware and the OpenHAB configuration:
- The OpenHab configfiles, rules etc.
- The Hardware schema’s (may not be fully up2date) and the software for the uC’s
Don’t forget to download the library needed for the NRF24L01+ ( by Spirilis, kudo’s !)
For those intersting to certain problems I faced:
for one, the OpenHab project utilized the eXtend framework (which is a dialect of java which compiles to ‘human-readable’ javacode ,so not bytecode). However, to make it more friendly for non-programmers, the basic rule-engine syntax is quite different from what (at least this) java developer is used to.
As i’m not too keen on wasting bytes to work around String literals instead of chars to send data to uC’s (e.g. String a = “200” <> unsigned char x = 200). This was rather ignoring to make work,
Eventually i settled for something like:
val Number scale = Math::floor( percent.floatValue * 1.27).intValue
sendCommand(Msp, "LEDC1" + BRIGHTNESS_PACKET + String::format("%c", scale) +"\n")
What basically happens:, you get a value between 0-100, this is an int. However, this value once multiplied with a scalar 1.27, get a value of 127 (decimal), as I couldn’t find a way to proper make a hex-value of it, this 127, decimal get send using a char, and is received by the uC as 255, magic (and ugly)
One of the other impracticalities is that OpenHab (to my knowledge), doesn’t provide a mechanism to write functions. This make it easy for a novice, but ugly in terms of write massive amounts of boilerplate code, and we all know where Java excels…. Yep, boilerplate code!
Anyway, should you have some tips, feel free to let me know, It shouldn’t be to hard to find my contact details
to be continued (oh and the gitcode is updated regularly.. )
Update: 12 July 2013
After some fellow (Fuzail) asking for more information ( always nice to hear back from like-minded people 🙂 ), I wrote (perhaps a bit unstructured) some more details regarding the communication in general (between openahab and the micro controller and between the nodes.
The communication (overview):
The communication is quite straight forward:
Every node sends an update (if needed of course) towards the ‘server’. For now i had a point-point setup where we depends on the addressing of the nrf24L01+, so the server has a fixed address, every node ‘pings’ the server at boot and regular intervals.
When the ‘package’ arrives (so the payload of the package (not the confuse with the package that goes over the air)), we do a rudimentary check regarding the contents of the payload( which is at most 32bytes (as this is a hard limit inside the nrf24L01(+) modules.
After this check, we simply forward the package on the to the serial port, and handle it on the pc/raspbery/whatever..
At openhab, we use the Serial binding to receive the package. what basically happens, as it is an stream of data, we append the receiving data into a string (which should never exceed 32 bytes ;). After we encounter a fixed limit (e.g. \n), we now that the package has been received properly. So we start to process this line of text.
Using the rules of openhab, we then toggle switches based on these packages.
The communication between nodes:
As mentioned previously, we utilized a point-to-point approach in terms of communication between server and client (so termal- sensor to server). However, although this unicast way of communication works rather nice in small spaces, and the very neat and simple library which enables us to do so, this does less in big areas, where there are more walls, of slimly larger distances to cover.
Therefore i’m currently working on a mesh-network setup. This multicast way of communicating, enables each node to act as a repeater. The leaves in the network (e.g. a battery powered node), will ideally consume as little as possible to prolong battery span. Therefore, we’ll configure those to not forward packages to other nodes.
So the idea is to make a simple (non-route-table-driven), protocol which forwards every package exactly once (if it is not destined for ourselves). To do so, we will configure every node on the same seinding-receiving address, and give them a unique id of say 2 bytes (which enables us to use 2^16 nodes in a network. which should be enough (for my house at least)). Every node will keep a package counter in memory. When a node sends a package, he requests a new counter value (which is the increment of the last one), end sends out a package. When another node receives this package. He will check if the package is already seen (by checking the local counter against the package number). If we’ve seen it, we will discard it, if not, we well either process it, if it is ours, or otherwise, resend it. In both cases we will set the local counter to the value inside the package.
This naive approach will quickly fill the air with plenty of packages. every package will be send repeated at least once by every node in the network, except for the server, and the sending node.
So if we were the repp this in a formula, f(N) = 1* (N -2) | where N denotes the number of nodes and F represents the number of package-resend.
This may seem not that much, but if we would like to use openhab tighter with boblightd to make every RGB node in the network act as a giant ambilight house, we well run into problems, as we want to update these nodes attest 20/s.
Therefore in the long(er) term, i’ll have to make some kind of routing scheme onto of the rudimentary communications to reduce the retransmission of packages and re-introduces a form of acknowledging successful packages.