Martin's corner on the web

Capture, decode and log to emoncms RFM12B packets on Raspberry Pi

With the RF12Demo sketch running on a TinySensor permanently hooked to my Raspberry Pi, my next step was to be able to capture the RFM12B packets that are being sent by various remote sensors in my home. Using the minicom terminal program on the Pi allows me to even send data packets with whatever content I want to other nodes from the serial console.

So what we have on the serial console when the RF12Demo sketch is running is a series of numbers whenever a packet is received. The meaning of these numbers depends on the data structure that the remote sensor is sending, here is a good post by JCW describing that.

I decided to do the capturing, decoding and posting to emoncms with PHP, not an optimal solution, but I am familiar with it. I’d rather do this with a perl script, but I need some more self-educating to do. The PHP script uses the PHP serial library available here to do its job. I have found that the library works good for receiving and not so good with sending data. The TinySensor works just fine with the minicom terminal program, but I can’t make it send data with the PHP serial library yet.. So my solution will be just to read from the RFM12b, decode and post to emoncms for the moment.

The code for that is pretty much trivial, we scan the serial port for incomming messages. The first byte of the message identifies the sending node, so we can expect what the rest of the bytes mean knowing who is sending them. Using the pack/unpack PHP functions we put back a data structure based on the incoming bytes and make a HTTP get to emoncms with the values extracted from the incomming message.

To have the script run in the background as a deamon, I use “sudo nohup php serial.php &”. To stop it, you must find the processID with “ps -A” and “kill” it.

The PHP code is available on github here

Here is a screenshot of it running

As a to-do remains that I re-write the gateway script in PERL and make it bi-directional i.e. the Pi will send the current time to remote nodes upon receiving a data packet from them.

This setup makes a complete in-house monitoring system, including storing the data.

6 thoughts on “Capture, decode and log to emoncms RFM12B packets on Raspberry Pi

  1. Troels

    Hi Martin,

    Thanks for the php-parser, which I’m happily using (with attiny84+ds18b20 as nodes). Unfortunately I can’t seem to get negative values through the parser with correct output.

    Can you help me out?

    1. admin Post author

      Hi,
      you need to modify the pack() format characters, I now have “v” which stands for unsigned short (always 16 bit, little endian byte order) and a “f” for the float values. Try “s” or “i” to see how it works out.

      so in the row where you unpack the values, replace the “v” before the variable name with “s” or “i”:

      $array = unpack(“CnodeID/vTemp1/vVoltage/vTemp2”, $bin_str);

      read more here:
      http://php.net/manual/en/function.pack.php

      1. Troels

        Thanks, “s” did the job!

        “i” gave me this error:
        OK 2 146 9 200 10 198 247
        PHP Warning: unpack(): Type i: not enough input, need 4, have 2

        Although I can’t figure out how “198 247” becomes -21.06C..

        1. admin Post author

          You need to post the data structure you want to transmit and the full unpack string so I can take a look. I am reading too quickly :o)

          Your second question is quite simple, 198 in decimal is 0xC6 in hex, 247 is 0xF7, so 0xF7C6 is -2106 in decimal. The temperatures are normally sent with value multiplied by 100 so that the transmission can fit in 2 bytes. Divide -2106 to 100 and you get -21.06

          Read the decoding post by JCW, he has some nice explanation as well.

  2. Troels

    BTW – I also had to do some minor changes to your parser. It could probably be prettified a bit:

    $serial->deviceClose();
    if ($theResult ==”) echo “.”; // write “.” until data comes in
    //raw packet data
    $binarydata = “”; // clear binarydata cache
    $valores=explode( ” “, $theResult ); // explode as array
    if($valores[0]==”OK”) { // continue if val0 = OK
    echo($theResult);
    $que = ltrim($theResult,”OK “); // remove “OK” from line
    //echo $que; // print result without “OK”

    $valores2=explode( ” “, $que ); // explode as array
    for ( $i=0; $i<count( $valores2 ) ; $i++) {
    $binarydata.= str_pad(dechex( $valores2[$i] ),2,'0',STR_PAD_LEFT) ;
    }
    $bin_str = pack("H*" , $binarydata);

  3. Pingback: RaspberryPi+TinySensor as EmonBase | Martin's corner on the web