Jumping Jack Flash

It’s a gas, gas, gas…

OK, so the title’s rubbish.  I’m open to suggestions for a better one which includes the word ‘gas’ or ‘meter’.  Except the Beatles song ‘From me to you’, of course, because that would be a dreadful pun.  And so to the point, which is that this blog post talks about using Gadgeteer kit to periodically read a gas meter, and send the data to a server for further use.

The gas bills for my house are, frankly, enormous.  Not so unusual for a twenty-five bedroom mansion, of course, but I don’t live in one of those.  And I’m not downsizing for anybody.  I’d like to know when the gas is being used, so that I can optimise the times that the central heating is on, but that means reading the meter regularly.  I could simply go to the cupboard under the stairs and look, but where’s the fun in that?  It’s clearly a much better option to build some electronic gadget which will do it for me, and in doing so raise my electricity usage.

It’s important to be clear about one thing.  Gas (and electricity) suppliers do not like you attaching devices to their meters.  For one thing, they always suspect foul play and that you are trying to slow down or reverse the meter.  For another, it’s dangerous.  Gas is explosive, and you really don’t want even the slightest possibility of an electrical spark in its vicinity.  Some gas meters come equipped with built in contacts which pulse a switch after every unit of gas is used, but wiring up to them is not a good idea (and may well be illegal, for all I know) unless the equipment you are connecting is specially designed.  So I don’t do that.

My approach to reading the meter is completely non-contact.  Using the Gadgeteer camera, a photo is taken at regular intervals, and sent to a server for processing.  Yes, it’s ridiculous technological overkill, but it is safe and legal.  There are some technical hurdles to overcome, of course.  Firstly, my gas meter is in a distinctly insalubrious cupboard under the stairs (at least that whiny Potter boy has moved out now), and it’s dark.  This means that lighting is required as well as the camera.  Secondly, the image has to leave the Gadgeteer system and get to a server, but oddly enough I don’t have a network point in the under-stair cupboard, so wireless data transmission is required.  WiFi would be the obvious way to do this, but I don’t have a Gadgeteer WiFi board, so I’m using XBee instead.

The hardware

For this project, I’m using five Gadgeteer elements: the Sytech Nano main board, the Sytech Serial Camera, a GHI dual power supply board, the GHI 7 LED board and a Sytech XBee module.  In addition, a couple of white LEDs and a couple of 180 Ohm resistors are needed.  Oh, and a 5V power supply.

P1020223P1020277P1020640P1020212

In the absence of a 3D printer to print housings for the stuff, I’m also using some cheap plywood, glue and cable ties to hold everything together.  If you have been following my previous blog posts (and why wouldn’t you?), the only unfamiliar component will be the XBee board.  The board itself is little more than a simple carrier for the XBee module, which is a self-contained low power IEEE802.15.4 wireless networking node.  The poorly-mounted capacitor you see sticking out of the side of the board is my addition, about which I will comment later.  XBee modules can operate in a variety of modes, including mesh networking, which is undoubtedly cool but not supported by the older nodes I possess, and broadcast or point-to-point communication.  For my purposes, the node at the meter reader end is simply going to broadcast its data to anything that will listen.  I’ve then got a second XBee node on a USB carrier plugged in to a proper computer to receive the data.  In the Gadgeteer world, the XBee device appears as a serial port – you send data to it, and it gets broadcast.  Incoming data can be read as you would any other serial stream.  You can effectively forget that it’s a radio transceiver, and just use it as a serial cable.

So, to the Visual Studio project.  The usual setup applies; here is a picture of the design surface once the components are added:

GasMeterReader_01

You’ll notice that the XBee component doesn’t look too good.  That’s because the manufacturer hasn’t fully implemented the component.  The driver works, though, and that’s the main thing.

The code is a  simple timer-based loop.  It initialises the camera (and waits for it to be ready) then starts a timer.  The timer ticks every so often, and keep track of when the last picture was taken.  When enough time has passed, it takes a new picture, gets the data as a byte array and sends it out over the XBee serial port, adding a small header so that the receiver knows it’s a new picture, and a byte count so that the receiver knows what to expect. A byte count is a good idea, because radio transmission is liable to interference, and data can go missing or get corrupted.  Some form of reliable data transfer, with checksums and acknowledgements would be better, but that’s too much like hard work to implement.  When I get hold of a WiFi Gadgeteer board, I’ll use TCP and not worry about it.  While the system is waiting to take a picture, it periodically flashes the red LED on the LED7R board, and while it is getting the data from the camera, it animates the other 6 green LEDs, to show progress.  there is no other display or means of showing debugging info on this project, so it’s useful to have some reassurance that it is still running.  The code is below:

 

using System;
using System.Collections;
using System.Threading;
using Microsoft.SPOT;
using Microsoft.SPOT.Presentation;
using Microsoft.SPOT.Presentation.Controls;
using Microsoft.SPOT.Presentation.Media;
using Microsoft.SPOT.Touch;
using Microsoft.SPOT.Hardware;

using Gadgeteer.Networking;
using GT = Gadgeteer;
using GTM = Gadgeteer.Modules;
using Gadgeteer.Modules.Sytech;
using Gadgeteer.Interfaces;
using GHIElectronics.NETMF.IO;
using GHIElectronics.NETMF.System;
using Gadgeteer.Modules.GHIElectronics;

namespace GasMeterReader
{
    public partial class Program
    {
        Gadgeteer.Modules.Sytech.XBee xbee;
        GT.Timer pictureTimer = new GT.Timer(1000);
        bool isProcessing = true;
        Serial xbeePort;
        int timeBetweenPictures = 20;// seconds
        int timeTillNextPicture = 10;

        void ProgramStarted()
        {
            xbee = new XBee(5);
            xbee.Configure(115200, GT.Interfaces.Serial.SerialParity.None, 
                GT.Interfaces.Serial.SerialStopBits.One, 8, false);

            camera.CameraReady += new SerialCamera.CameraEnabledEventHandler(camera_CameraReady);
            camera.CameraPictureReady += new SerialCamera.CameraEventHandler(camera_CameraPictureReady);
            camera.OnPictureProgess += new GTM.Sytech.Camera.PictureProgressDel(camera_OnPictureProgess);
            camera.EnableCamera();

            xbeePort = xbee.GetPort;
            if (!xbeePort.IsOpen)
                xbeePort.Open();
            xbeePort.WriteLine("Program starting");

            pictureTimer.Tick += new GT.Timer.TickEventHandler(pictureTimer_Tick);
            isProcessing = true;
            pictureTimer.Start();
        }

        void pictureTimer_Tick(GT.Timer timer)
        {
            if (isProcessing) return;
            timeTillNextPicture = timeTillNextPicture-1;
            if (timeTillNextPicture == 0)
            {
                timeTillNextPicture = timeBetweenPictures;
                isProcessing = true;
                SetLedPercent(100);
                pictureTimer.Stop();
                camera.TakePicture();
            }
            else
                PulseRedLed();
        }

        void PulseRedLed()
        {
            lED7R.TurnLightOn(7);
            Thread.Sleep(200);
            lED7R.TurnLightOff(7);
        }

        void SetLedPercent(int percent)
        {
            for (int led = 1; led < 7; led++)
            {
                if (percent < (led * 16))
                    lED7R.TurnLightOff(led);
                else
                    lED7R.TurnLightOn(led);
            }
        }



        void camera_OnPictureProgess(object sender, GTM.Sytech.Camera.ProgressEventArg arg)
        {
            int percent = (arg.blockReceived * 100) / arg.Blocks;
            SetLedPercent(percent);
        }

        void camera_CameraReady(SerialCamera sender, GTM.Sytech.CameraProtocol.ImageSize resolution)
        {
            camera.Resolution = GTM.Sytech.CameraProtocol.ImageSize.svga;
            isProcessing = false;
        }

        void camera_CameraPictureReady(SerialCamera sender, GTM.Sytech.Camera.ImageEventArg CameraImage)
        {
            byte[] outputBuffer = CameraImage.GetImageDataBuffer();
            Debug.Print("CameraImage.GetImageDataBuffer()");

            xbeePort.WriteLine("BITMAP");

            UInt32 crcValue = Utility.ComputeCRC(outputBuffer, 0, -1, 0);
            byte[] header = new byte[4];
            header[0] = (byte)(outputBuffer.Length & 0xFF);
            header[1] = (byte)((outputBuffer.Length >> 8) & 0xFF);
            header[2] = (byte)((outputBuffer.Length >> 16) & 0xFF);
            header[3] = (byte)((outputBuffer.Length >> 24) & 0xFF);
            xbeePort.Write(header);
            xbeePort.Write(outputBuffer, 0, outputBuffer.Length);
            byte[] crc = new byte[4];
            crc[0] = (byte)(crcValue & 0xFF);
            crc[1] = (byte)((crcValue >> 8) & 0xFF);
            crc[2] = (byte)((crcValue >> 16) & 0xFF);
            crc[3] = (byte)((crcValue >> 24) & 0xFF);
            xbeePort.Write(crc);
            xbeePort.WriteLine("END");
            xbeePort.Flush();
            pictureTimer.Start();
            isProcessing = false;
        }

    }
}

And that’s it.  The receiver is a WPF application, and is not very complex  – it listens for the start of the bitmap message, reads the byte stream into an array and then creates an image from it (the data is already in jpg format).  It’s then easy to display that in an Image control.  My next task is to do some processing on the image to isolate the numbers, and store the actual meter reading in a database.  I haven’t done that yet.  I’d like to do it in the Gadgeteer device itself, but I’m not convinced that its practical.  At least the speed of processing is not an issue, because the meter does not need to be monitored every second!

Here’s what the finished article looks like.  Note the craftsmanship on the woodwork and the elegant use of hot-melt glue.  I’m particularly proud of the bright orange cable ties used to hold everything because I’m too cheap to buy a bag of 3mm screws and nuts.  Note that the 7-LED rosette was not mounted when I took these photos.

P1020643

P1020641

Front view (as seen by gas meter)

P1020644

Back view (note external power supply cable and wiring going to illumination LEDs)

And here it is in place, all alone in the dark:

P1020652

As soon as I get the recognition part of the receiver software working properly, I’ll post an update – and they you’ll be able to follow a live feed of my gas consumption.  I bet you can’t wait.

4 thoughts on “Jumping Jack Flash

    • I wasn’t aware of project hawaii. It looks interesting, though. My current plan is to do the OCR on the Nano board itself, because the image is highly constrained – there is a nice black rectangle containing four white characters (and two smaller ones containing red numbers), each of which can only be one of ten numbers. This simplifies the issue enormously. The image processing will still be very slow, but that hardly matters because the meter doesn’t change that quickly (though quicker than I would like, otherwise I wouldn’t be doing the project). I’ve not quite finished the OCR yet, but I’ll post it when I do.

  1. Hi Peter,

    Cool work.

    How many frames per second do you think you can transmitte with it?

    Thanks,

    Sean

    • it’s not really in the ‘frames per second’ league. I’m sending one frame every thirty seconds at the moment (though the actual data transfer takes only a few seconds). When I’ve finished doing the OCR inside the device, it will probably be nearer one frame a minute. That’s good enough for my purposes, but you wouldn’t want to try and film a humming bird with it :-)

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>