A while ago, while browsing through a local Maplin store, I found a cheap wireless electricity power meter that is possible to connect to a PC via USB cable. Since I was planning to experiment with the electricity power monitoring for one of my commercial projects anyway, I decide to buy it and find out how to establish a communication with it from a custom piece of software and possibly even present the data on a website with a real time update. The Wireless electricity monitor was, and I believe still is, available for £14.99 from Maplin under code N94KQ This is what you get in the box:
The installation was very simple. The main measurement unit with the transmitter gets clamped on the live phase wire coming to your house. If you have three phase distribution you can buy extra two clamps and connect them to the transmitter. The meter can handle them 🙂 This is how I placed the transmitter next to my main power meter.
Communication with the electricity monitor
After installing the meter at home I realized the provided software for getting data from the unit was only for Widows and pretty rough to say the least. I didn't have any intention to use it anyway but I was quite surprised the manufacture didn't put more effort in it.
To find out how the host computer talks to the meter was quite simple. Plugging the USB cable to my linux machine and running dmesg command quickly revealed what I was dealing with.
[337148.094624] usb 6-1: new full-speed USB device number 4 using uhci_hcd [337148.257064] pl2303 6-1:1.0: pl2303 converter detected [337148.269252] usb 6-1: pl2303 converter now attached to ttyUSB1
As one would expect the USB cable is a simple RS232 to USB bridge with the very common PL2303 chip. The USB cable is attached to the unit with RJ45 connector with quite large USB connector on the other side. I believe the RS232->USB converter is built in the USB connector itself so the data on the RJ45 should be the raw RS232 but I haven't investigated that.
Second step was to find out the communication protocol. I didn't want to do any reverse engineering of the protocol so it tried to find what controller was used in the meter and obtain the protocol from the manufacturer. The product is re-branded for Maplin and to find the manufacturer was not possible. Inside the unit is R5F2L38ACDFP microcontroller but that also didn't help.
The fastest approach appeared to be to analyse the data between the unit and the software that came with it. After and hour with a serial port sniffing tool I managed to extract a startup sequence, and two other sequences that need to be sent to the unit to make it to return data with the current power consumption. This is how they look in the python.
START_CMD=[0xAA, 0x00, 0x00, 0xAD] READ1_CMD=[0xAA, 0x01, 0x00, 0xAD] READ2_CMD=[0xAA, 0x02, 0x00, 0xAD]
So far so good, I can initialize the unit and make it to return a long byte sequence with the power usage information like this.
How do I know? Well, I recorded several output sequences, each for different power consumption which I controlled by turning on/off my el. kettle 🙂 For each case I wrote down the power usage displayed on the LCD screen of the unit. Then it was just a matter of identifying what bytes changed and determining how they are formatted. The power in Watts is stored in the bytes 69 and 70 in the sequence. This is how to read it in python.
power = data + data * 256
To read the power is very simple.
- Open the serial port.
- Write the initialization sequence to the port.
- Write the READ1_CMD and READ2_CMD sequences.
- Read the data from the serial line and decode the power.
The last two steps can be repeated infinitely Here is a python code to does exactly that. The only dependency is on the pySerial module
import sys import time from serial import * START_CMD=[0xAA, 0x00, 0x00, 0xAD] READ1_CMD=[0xAA, 0x01, 0x00, 0xAD] READ2_CMD=[0xAA, 0x02, 0x00, 0xAD] def write_cmd(device, cmd): device.write(to_bytes(cmd)) def read_data(device): data= while True: b = device.read() # Read all available bytes if len(b) == 0: break data.append(b) return data def exec_cmd(device, cmd): write_cmd(device, cmd) # The power meeter needs some time to deal with the command time.sleep(0.2) return read_data(device) # Extract the current power consumption in Watts from the data # returned by the power meter def decode_power(data): power = 0 data_len = len(data) if (data_len > 70): power = ord(data) * 256 + ord(data) return power # Returns current power in watts def read_power(device): data = exec_cmd(device, READ1_CMD) data = exec_cmd(device, READ2_CMD) return decode_power(data) def run(uart_port, period_sec=4): # Open the serial line device = serial_for_url(uart_port, timeout=1) # Initialize the device data = exec_cmd(device, START_CMD) print "Startup response: ", print data # Keep reading the power consumption infinitely while True: power = read_power(device) #print str(power) + " Watts ", # Sometimes the power meter returns 0 Watts. This can happen if # the power meter itself fails to read data from the main unit over the RF link. if power == 0: print " Ignoring *********************************" continue # Pause for 'period' seconds time.sleep(period_sec) device.close() if __name__=="__main__": uart_port = "/dev/ttyUSB0" run(uart_port)
The complete code including the dependencies can be downloaded from http://code.google.com/p/electroncastle/source/checkout
Given the simplicity one can use any off the shelf hardware with the USB host port and some basic computation capabilities for example the recently very famous Raspberry PI. If the data on the RJ45 is really RS232 then one could use even more basic micro controllers to read the data.
Next time I will show how to setup very simple real time visualization of the power consumption in a web page.