Reads the electricy meter status information sent over IrDA, specifically the Elster A100C. Can also use this DIY hardware instead of IrDA.


With the ever rising cost of electricy I became interested in knowing what the money is being spent on, is it that computer running 24x7? Is it the electric oven? Maybe the fridge freezer? Some of these can be measured at one moment to give an accurate long term average, others will always vary from day to day, so although they could all be estimated it is better to get the true figure of power consumption over the medium term.

Which is where this little program steps in. The Elster A100C, and probably many others - though not necessarily in the same format, continuously outputs its status using invisable infrared pulses. Specifically, every second it outputs 110 bytes containing, amongst other things, the total amount of energy consumed in WattHours. This is 1000 times more resolution than displayed on the lcd - it is WattHours not just KiloWattHours.

The program

The program rdmeter.c is the culmination of the data gathering and comparison process. This program reads irda serial data from electric meter, in my case an Elster A100C and displays per line:
1. current system time in UNIX time.
2. WattHours used.
3. Two unknown but surely meaningful bytes. Does anybody know?
3. An estimate of the Watts (ie. energy per second) consumed since the WHs counter changed.

This program can be compiled with the line:
gcc -Wall rdmeter.c -o rdmeter
and then run with the line:
./rdmeter /dev/ttyS1 "Elster A100C" 2> /dev/null
where the /dev/ttyS1 is the second serial port, in my case, the built in IrDA adapter in the laptop. The string "Elster A100C" helps rdmeter locate a known position in the data stream, from this it can work out the beginning and the end of each data frame.

Get it wrong and rdmeter will be unable to find the frame, and will instead print out raw hex of the first 256 bytes of irda stream and then quit, leaving you to find the make/model name in the hex and use it as the correct option to rdmeter.

It is assumed that the make and model fields are always in the same part of the data frame relative to the checksum and WHours counters. You will know that assumption is wrong if the unit counter don't match what you see on your meter.

The 2> /dev/null throws away all mentions of checksum failure, which is probably what you want when it working. I see maybe 1 checksum failure per minute, with the laptop in a cupboard with the plastic near the ir sensor leaning against the eletricity meter by the ir sender.

Data format

This data format is derived from what I see from my A100C over the course of a few days monitoring. It is incomplete. Data is sent at 2400 baud, 110 bytes per frame including a 1 byte checksum. The data is sent once every second, regardless of anything listening, so it is physically irda but seems to lack any of the irda layers - also there is no 9600 baud component, which I beleive is a required part of irda negotiation.

Each 110 byte frame includes:
1. The make and model of the electric meter.
2. The serial number of the electric meter.
3. The number of units used, in WattHours i.e., 1000 times the resolution of the usual kWattHours displayed on the lcd screen.
4. The total electric meter runtime, or something like it, in hours.
5. Some other counter that increments every hour.
6. Two unknown bytes loosely related to power consumption, but not.
7. Checksum of the frame, which is the sum of all previous 109 bytes mod 256.

It is not known how consistent this format is across electric meters. If it works for you, I'll happily add it to the list.

Taking each section in turn, with the checksum as the last byte of the frame at position 110 bytes:

The make and model (and submodel) field is ASCII and occupies bytes 5 to 25, with a NULL at byte 26.

The serial number field is ASCII and occupies bytes 37 to 46, though byte 47 is 0x01, and byte 48 is NULL.

The number of units is encoded using the decimal only part of hexadecimal numbers, and occupies bytes 50 to 54. For example, say the hexadecimal numbers are: 0x00, 0x06, 0x94, 0x37, 0x51, the meter reading is 6943751 WattHours, or dropping the last three digits, 6943 KWattHours. Byte 49 is 0x02, which I assume to mean it relates to something else.

Unit runtime is (according to the meter datasheet) recorded and available to query, though I don't know how. Bytes 88 and 104 increment every hour, both increment in the same frame and both are different values. Byte 104 overflows at 0x99 to 0x00 and byte 103 increments. This uses the same decimal part of hexadecmial encoding as used by the WHs fields. Byte 88 overflows at 0x99 to 0x00 and byte 87 increments. Byte 86 is 0x01 and byte 85 is 0x35. Knowing this meter has been installed for less than two years suggests byte 85 is for something else and so bytes 86 to 88 record runtime hours. Byte 102 is 0xC3 which suggests if byte 103 overflows, it doesn't increment byte 102.

The two unknown bytes (80 and 81) are annoying in that they seem to relate to real quanites, continously varying and following a pattern that definately relates to changes in energy consumption. But, I cannot find what they refer to. Plotting byte 80, byte 81 and energy consumption based on the WattHours counter, shows no pattern. Byte 80 is generally 228 or slightly less, or it is 100, or maybe slightly less. The closer to one of these two it is, the more commonly it appears. Byte 81 is only ever one of 4 values, 0x00, 0x20, 0x40 or 0x60, and can sometimes change one time frame before an otherwise seemingly synchronised change to byte 80. My first thoughts were that byte 80 was a fixed point number and byte 81 was a multiplier or power, but there was no visible correlation. rdmeter prints these two values in the hope they might one day prove useful.

The checksum field is the last byte in the frame (according to me, but it is the only way that makes sense). Summing all bytes from 1 to 109 and masking off all but the lower 8 bits should equal this byte. Anything else indicates a transmission error somewhere in that frame. As frames are sent every second and the values produced are absolute measurements, it is best to skip errored framed.

Besides these fields, there are many bytes that have a non-zero value but did not change over the time they were being recorded. Only official documentation or infinite time will show what they are used for. For example, byte 3 is 0x68(104), which is close enough to 110 to hint that it is the frame size minus a constant. Using the same reasoning, byte 1 is 0x01 and byte 2 is 0x00, and using the above decimal in hexadecmial this would mean 100.


Initial testing was done with minicom, to find the correct baud rate, and then hexdump -C. I'm sure there was a hex dump option in minicom, but I couldn't find it. It was only with the hexdump that the repetitive frames and the mix of ascii with decimal only hexadecimal became clear. Using hexdump also meant hours of data could be collected and then parsed looking for differences.

This is the point that it become much more clear. Starting a new line with every complete mention of "Elster A100C" and then only printing byte positions when they changed made it possible to see only the handful of changes out of the 110 bytes of possible changes.

All this processing was done with multiple awk scripts, each reformatting the data stream originally from hexdump into something more suitable, largely by adding, removing and then adding linefeeds, making the hex codes line up on a frame boundary that could then be viewed with less -S. More awk then printed fields that had changed twice since the start of execution, twice because its nothing to something to something else, and only the last change means anything.

More awk and gnuplot was used to confirm the numbers were meaningful (or meaningless), and produce pretty graphs that clearly showed the two fridge/freezers, the base line of the 24x7 computer and misc, the electric oven, nighttime lights and the short large peak of the kettle.

The initial scripts can be found here.


1. Find a source of the docs that specify the actual data format.
2. Add something on reading IrDA at 2400 baud without using an IrDA port - done here.


Written by greg on 14/04/2009, : r.gregory at liv ac uk. Would welcome any comments.