This is notes for anyone who is interacting with (in Australia at least) Clipsal-branded smart switches that operate over BLE. (They also come with a ZigBee certification document, but it seems like it was never enabled.)
They have a couple of interesting UUIDs (these are here for y'all searching for them):
-
Control service,
720a9080-9c7d-11e5-a7e3-0002a5d5c51b
- State characteristic (i.e., switch on/off),
720a9081-9c7d-11e5-a7e3-0002a5d5c51b
- Level characteristic (i.e., brightness),
720a9082-9c7d-11e5-a7e3-0002a5d5c51b
- State characteristic (i.e., switch on/off),
-
Command service,
720a7080-9c7d-11e5-a7e3-0002a5d5c51b
- Request characteristic,
720a7081-9c7d-11e5-a7e3-0002a5d5c51b
- Response characteristic,
720a7082-9c7d-11e5-a7e3-0002a5d5c51b
- Request characteristic,
For clarification, I have some CLP5010's which have on/off as well as brightness. I also have CLP5011's which I've yet to install (but are just switches, and do not have a level)—these seem more suitable for controlled loads or lights that cannot dim.
So, you can write 0x00 or 0x01 to the state characteristic to turn a switch on or off. You can also write to the level characteristic (as a 16-bit little-endian number, for some reason) which ranges from 0-10,000. (So the highest value will be 0x2710, written as "0x10 0x27" in LE).
The brightness isn't independent from the power state. If the light is off, brightness will be zero. For example: if you set the brightness to 600 on an off switch, the light will come on, and the opposite if you set brightness to zero. (Toggling on/off will restore the most recent brightness, or there's an option in their app to have it restore at a specific value always.)
Regardless, it seems as if these characteristics ONLY report the last state you wrote over BLE.
- You cannot read the latest value if a person physically toggled the switch.
- You can see the latest value if you're subscribed to the characteristic, but this requires holding a BLE connection open (not really ideal when you have lots of switches).
This is… strangely broken for real use if you're trying to include these switches in a home automation system.
You can read the current state of the light by having a BLE scanner run. The advertising data packet contains a "manufacturer specific" (i.e., 0xff) payload that announces on/off and level. Yes, this means sufficiently motivated neighbours could read the status of your lights—it's public. But they could probably tell if your windows are lit up anyway.
The packet has a bunch of stuff in it, but importantly:
data[5]
contains the current settings generation (it updates whenever a setting changes)data[6]
reports on/off state (the Clipsal app masks it with& 15
but no other data ever appears here)data[7]
has the brightness from 0-255 (it's really internally 0-10,000), you can/ 255.0 * 10000
to bring it in-range
I use these packets to update my code which eventually informs e.g., Google Assistant as to whether the lights are on.
(I find it really amusing that the Clipsal app does this discovery, but still makes you tap on a specific light to see whether it's currently on. It already knows and could show the statuses all at once!)
There's also a way to make arbitrary requests and wait for responses. This is how the app gets state and writes settings.
There's two types of requests: read and write. The app refers to using these as reading and writing "registers". The read command looks like:
Byte | Value | Notes |
---|---|---|
0 | 0xff | |
1 | 0xff | |
2 | 0x06 | Magic value |
3 | 0xff | |
4 | 0x43 | Magic value |
5-6 | register | The register to read, in 2-byte big-endian |
6-7 | length / 2 | The number of 2-byte values we expect in return (length is total bytes) |
The write is pretty similar, but contains more data:
Byte | Value | Notes |
---|---|---|
0 | 0xff | |
1 | 0xff | |
2 | length + 7 | The number of bytes to write, plus seven |
3 | 0xff | |
4 | 0x10 | Magic value |
5-6 | register | The register to write, in 2-byte big-endian |
6-7 | length / 2 | The number of 2-byte values we're reading (length is total bytes) |
8 | length | The total number of bytes being written |
9+ | your payload | The payload to write |
Length must always be even and seems to be minimum eight. If the payload you're writing is fewer bytes (many registers only take 2-byte BE values) then pad it on the right with zeros.
Once you've done a read or write request (well, you should do this before that) watch for notifications on the response characteristic. It has a bunch of values as a prefix, but the result tends to start at byte 8.
You can e.g., read the light's name by reading register 0x1002. If you happen to have access to the app's source code, you can find the descriptions of additional registers in a file called "ParametersMapCommon.xml".
Write a comment if you're interested in more or just want to say thanks.
Just wanted to say thanks for this, awesome work.
I had struggled with this as I’m pretty new to BLE, but this makes a bunch more sense now!