Home > Domotica > Plugwise Protocol Analysis, Part 1

Plugwise Protocol Analysis, Part 1

I ordered my Plugwise set two weeks ago, and it arrived a few days later. The hardware looks OK, through it is a bit expensive. Big disadvantage is that it’s windows only, through there are some people that have things running with their own software (both Linux and Windows). My goal is to get things up-and-running with Linux, but that means some reversing work. I did find two blogs about it, and that was a good starting point.

To get a quick start I remembered that the netbook I recently bought still has it’s windows partition (I use Linux on it), so I could install the ‘Source’ and check how it works.

Installation went OK and it discovered my circles (through I still had to type the circle-addresses myself). I only discovered  the buttons at the bottom  a few days later after wondering how to change settings, but the Plugwise window can be resized. Not many software developers think of somewhat smaller screens (1024*600 is not that big a resolution, but also not far from the old 1024*768 and the also quite popular 1366*768).

I have PlugWise devices with firmware v2.4 (as read from the PlugwiseData.mdb) and the ‘Source’  is v2.16

Analising the Protocol

From Hackstuces I got the idea to use portmon and capture the communication. I did forget to change the max line-length it stores in the log, so for my initial captures (where I configured the circles) some date is truncated. I concentrated my analysis of the protocol with the ‘data gathering’ part, for now.

Offcourse I also used the findings I found at Maartens blog, but it is not complete yet. That is why I’m writing this, documenting what I found and a way to find it again. For the data frame structure, see the Plugwise Unleased document and the blog posts.

Remember, all communication data is ASCII, and the messages where we are looking at are all HEX digits. There are also some other Ascii messages, but those seem to be informational only and contain no new data. It is probably to aid debugging, likely messages for the circle network. I’ll just ignore them for now.

Here are three mayor parts I see when looking at the traffic, after starting the ‘Source’.

  • Initialisation and clock-synchronisation with the Circle+
  • read real-time data from circles
  • read stored data from circles

I Striped out the Start and End (CrLf) sequence, and CRC16 from each message. According to this post in Domotica forum the ACK reply can be considered as a notification that the command is being processed (or rejected) and it gives the sequencenumber back for tracking what happens with it. In the dumps below, I omit this ACK reply, to save space.


This is a simple sequence, where the MAC of the Stick is found, and some synchronisation with the Circle+ takes place.

For my hardware here are the MAC addresses.

  • 000D6F0000B835CB (Stick)
  • 000D6F0000B1B64B (Circle+)

This is the sequence of commands and responses I found:

So to summarise the command/reply sequence:

  • (to stick) 000A/0011, (to circle+) 004E/0000 , then a reset (might be just a probe, to see if the network is connected)
  • (to stick) 000A/0011, 0023/0024, 0023/0024
  • (to circle+) 0023/0024, 0016/0000, (0008/0000), 0028/0000, 0029/003A, 004A/0000, 003E/003F (the position of the 0008/0000 sequence varies)
  • (to circle) 0023/0024, 003E/003F, 0012/0013

The 08 command contains no MAC, so is a bit strange. It returns the MAC of the Circle+, but before this command there was already communication directly to the Circle+ (probably using the Circle+ MAC from the ‘Source’ configuration). The 0016 command contains the current date-time.

There is a difference between reading the Circle+ and the other Circles, but both have Commands 0023 and 003E in common. Now the Circle+ is the coordinator node that has a Clock. That explains some differences, as command 0016 is a SET clock data and command 003E is a GET clock. Maarten already analysed this data. Note that the clock seems to be set to UTC, not local time. The 16-bit integer for Minutes  in the date part of the 0016 command is counted from midnight of the first day of the month.

Note that command 003E is only used in the first round of calling all the circles, so it is part of the initialisation/synchronisation.

The reply to the initialisation command (000A) gives the MAC-address of the Stick
w 000A
r 0011 0001 000D6F0000B835CB 01 01 440D6F0000B1B64B 3B44 FF

In the reply, the sequence number (0001) associated with the command, MAC address Stick (000D6F0000B835CB), 64-bit, two 8-bit fields that are either True (non zero) or False (zero), an Extended PAN ID (440D6F0000B1B64B) 64-bit, and the PAN ID (3B44) 16-bit, and another unknown 8-bit value (FF). The Extended PAN ID looks like the Circle+ MAC with the first byte changed to 44 instead of 00. The value of 44 is set when configuring the network, an changes when the network is destroyed and rebuild.

Using command 0024 more info is requested from the stick

w 0023 000D6F0000B835CB
r 0024 0002 000D6F0000B835CB 00000000 00000000 00 80 6539-0700-8510 4CCEC22A 00

This request is weird, maybe a probe if a Circle+ is connected
w 004E 000D6F0000B1B64B
r 0000 0003 00F4 000D6F0000B1B64B

Now, for some unknown reason, Initialisation restarts here (does that every time)
w 000A
r 0011 0004 000D6F0000B835CB 01 01 440D6F0000B1B64B 3B44 FF

The following two (identical) commands go to [000D6F0000B835CB], the Stick, detected in the previous command
w 0023 000D6F0000B835CB
r 0024 0005 000D6F0000B835CB 00000000 00000000 00 80 6539-0700-8510 4CCEC22A 00
w 0023 000D6F0000B835CB
r 0024 0006 000D6F0000B835CB 00000000 00000000 00 80 6539-0700-8510 4CCEC22A 00

So to summarise the command/reply sequence:
(to stick) 000A/0011, (to circle+) 004E/0000 , then a reset
(to stick) 000A/0011, 0023/0024, 0023/0024

First time data-scan from circles is different for Circle+ and normal Circles. I omit the capture, just the commands.

Circle+ 0023/0024, 0016/0000, (0008/0000), 0028/0000, 0029/003A, 004A/0000, 003E/003F

Circle+ 003E reply 003F 000D 000D6F0000B1B64B 12 1B 2A 06 01 45 7A

Circle   0023/0024, 003E/003F, 0012/0013

Circle  003E reply 003F 0012 000D6F0000AF4C47 12 1B 28 06 01 45 7A

Both give about the same reply, a different sequence number, almost identical time stamp, an identical  unknowns.

Noticed that several commands return a 0000-reply. Those replies have the same structure, reply code 0000, 16-bit sequence value, another 16-bit value (probably bit-fields, some kind of status, it seems) and a 64-bit MAC address.

Read real-time data from circles

All Circles are read with 0023/0024 and 0012/0013 command/reply pairs. The handling of the Circle+ is not different from others, after the initialisation sequence completed. The Source (awefull name)  keeps asking for data, so it can display real-time data.

w 0023 000D6F0000B1B64B
r 0024 0056 000D6F0000B1B64B 0B048013 00044480 01 85 6539-0700-7324 4CCEBFA1 01
w 0012 000D6F0000B1B64B
r 0013 0058 000D6F0000B1B64B 002F0175 00010AA7 00000000 0004
w 0023 000D6F0000B1B967
r 0024 005A 000D6F0000B1B967 0B048014 00044470 01 85 6539-0701-4023 4CCEC0C2 02
w 0012 000D6F0000B1B967
r 0013 005B 000D6F0000B1B967 00070038 00002E14 00000000 0004

Read stored data from circles

Al Circles are read with command/reply 0048/0049. It takes more than one command to read one circle.

W 0048 000D6F0000B1A240 00044460
R 0049 0051 000D6F0000B1A240 0B047F80 00000A87 0B047FBC 00000ACF 0B047FF8 00000AAC FFFFFFFF FFFFFFFF 00044460
W 0048 000D6F0000B1A240 00044440
R 0049 0052 000D6F0000B1A240 0B047E90 00000A9B 0B047ECC 00000AD4 0B047F08 00000B0B 0B047F44 00000B0E 00044440
W 0048 000D6F0000B1A240 00044420
R 0049 0053 000D6F0000B1A240 0B047DA0 00000A8C 0B047DDC 00000A98 0B047E18 00000A6D 0B047E54 00000A71 00044420

W 0048 000D6F0000B1B5B6 00044480
W 0048 000D6F0000B1B5B6 00044460
R 0049 0055 000D6F0000B1B5B6 0B047F44 000021AA 0B047F80 000020F1 0B047FBC 0000216D 0B047FF8 0000213E 00044460
W 0048 000D6F0000B1B5B6 00044440
R 0049 0057 000D6F0000B1B5B6 0B047E54 00036708 0B047E90 00035291 0B047ECC 00000DD3 0B047F08 00002199 00044440
W 0048 000D6F0000B1B5B6 00044420
R 0049 0059 000D6F0000B1B5B6 0B047D64 000349C5 0B047DA0 0003538A 0B047DDC 0003541F 0B047E18 000355A4 00044420

I have not attempted to decode the 0049 replies. From the data structure I assume that 8 values ( 32 bit each) are returned, probably in pairs belonging together. I also assume the parameter in the 0048 command and the matching one in the 0049 reply (for example “00044420“) is some sort of buffer-code.  I did read about a buffer address mentioned in the explanation of the device info command, but not this command structure.

[later] I think the pairs of data is a power-value followed by a timestamp. The timestamp has the same structure as the date-word of the 0016 command. This means that  value 0B 04 7DA0 could mean Year 2011, Month April,  From the start of the month 32160 minutes, this is 536 hour, which is 22 days and 8 hour. Somewhere during the 23rd of april (yesterday), when the data was captured. So that is most likely.

[days later] The structure of this reply is explained in the plugwise unleased documents, and indeed 4 pairs of data, each pair represents one hour of accummulated power usage.


In the previous two sections, different data is retrieved. While analizing the log-captures, I noticed that both processes run at the same time. So a 0023 command starts and before de 0024 reply is received a 0048 command is send. Then the 0024 reply arrives followed with the 0049 reply. in between I also see the ACK replies. It is likely that the next command is not send before the ACK is received, but I am not sure if that is the case. Might be that usually the ACK is generated by the NC in the circle+, and has less delay as data-replies, so arrives shortly after the command is send. I assume that data-reply first needs to get back from a circle to the NC before it is transmitted to the stick.

It is not possible match a command directly with an ACK, but the ACK has the same sequence-number as the data-reply, which arrives later, and can be matched with a command. I suggest to  not wait for results from a command, just process what arrives. For error correction, wait for the first (fast) ACK reply and store the sequence number and associate that with the command (evaluate the value too for error processing). E.g. 00C1 is an OK response, but I did see this type of message used for other things (like responding with 00E1 instead of the expected reply), that could considered as some kind of timeout in the Zigbee network.

A forum post mentions that 00C2 and 00C3 are error-return codes from the ZigBee stack and that the command and it is not accepted.

Categories: Domotica Tags: ,
  1. titioft
    28 July 2011 at 23:11

    Good work…

    For the 0x49 reply here is the content of the data:
    $results is the string I receive in my xpl-plugwise module.

    position 18 length 6 : you can read the short device MAC address
    position 24 length 8 : hour of 1st buffer (abshour format)
    position 32 length 8 : Usage in pulses of 1st hour
    position 40 length 8 : hour of 2nd buffer (abshour format)
    position 48 length 8 : Usage in pulses of 2nd hour
    position 56 length 8 : hour of 3rd buffer (abshour format)
    position 64 length 8 : Usage in pulses of 3rd hour
    position 72 length 8 : hour of 4th buffer (abshour format)
    position 80 length 8 : Usage in pulses of 4th hour
    position 88 length 8 : Address of the current buffer

    A 0x49 is a reply to 0x48 (sic).

    The $packet is what I send to the stick
    $packet = “0048” . “000D6F0000” . uc($circle) . uc($msg->lastlog);
    Where $circle is the short MAC address
    and $msg->lastlog is the log address requested

    My sub in perl to return the time in local time zone in readable format
    sub plughr2time
    my $result=$_[0];
    my $year=2000+hex2int(substr($result,0,2));
    my $month=sprintf(“%02d”,hex2int(substr($result,2,2)));
    my $plughr=hex2int(substr($result,4,4));
    my $day=int($plughr/1440);
    my $hour=int(($plughr-$day*1440)/60);
    my $minutes=$plughr-$day*1440-$hour*60;
    printf(“Result: $result \nYear:%04d Month:%02d Day:%02d Hour:%02d Minute:%02d \n”,$year,$month,$day,$hour,$minutes);
    return sprintf(“%04d%02d%02d%02d%02d”,$year,$month,$day,$hour,$minutes);

  2. Xaho
    14 September 2011 at 11:16

    I seem to have run into a little problem…
    When I send a message to retrieve the buffer with logaddress I retrieved earlier with the device information request all I get is a response filled with FFFFFFFF’s…
    Any idea what I’m doing wrong?
    I’d love to hear suggestions 🙂

    Message sent: 0023000D6F0000992A8BD6EC
    Received message: 0024012B000D6F0000992A8B0B094B48000443C001856539070140224CCEC0C202B557
    Message sent: 0048000D6F0000992A8B000443C047A9

    • Xaho
      14 September 2011 at 14:43

      Solved my problem 🙂

      The logaddress I received by asking device information was the address of the current hour.
      By reducing the value by 32 decimal (or 0x20) I suddenly got the results I was hoping for.
      Information about the previous four hours of power usage! 😀

  1. 24 March 2012 at 10:26

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s