Smart lights for home controlled by a Linux laptop
As we’ve learned in the previous article, I’ve purchased smart lights for home and trying to control them in different ways. The smart lights for home support Bluetooth (specifically Bluetooth Low Energy device) and they come with a bundled app that you can use to control them.
In the previous article I used nRF Connect app to connect to the lights and read and write Bluetooth attributes and successfully switched the light on and off. I was therefore able to control the brightness, the light temperature (from warm yellow to cold white light) and set a timer to turn the lights on and off at a predetermined time.
As in the previous article, I want to set a goal.
My goal is to control the lights using my Linux laptop.
I imagine there are some utilities that I can learn and use.
First some basics.
Bluetooth vs WiFi vs others
The market is flooded with different products that can be controlled remotely. They use different standards to connect to a central hub. Apart from the wired switches, lights, sensors, and other devices, there are only a handful of protocols that companies use.
WiFi
Out of these three, WiFi is the one known to most people. For instance, having your smart lights for home or light switch work with WiFi means that a device has a WiFi chip and connects to a wireless router you use to connect your other devices and computers. The device is assigned an IP and it can be accessed like any other device on the network. Compared to Bluetooth it offers a longer range and higher bandwidth. The drawback is relatively high power consumption and until recently, a higher price for the chips.
Bluetooth
Bluetooth is also a well-known protocol. You use it each time you connect your phone to your computer or your wireless headphones to your phone. It uses the same frequency range as WiFi (802.11b/g/n).
The protocol was developed to complement WiFi but was meant for smaller and less capable devices and for symmetrical communication (when using WiFi there is usually much more data coming in than going out).
While having smaller energy requirements than WiFi, Bluetooth devices still require more energy and are not appropriate for devices that should have extended (months or years) autonomy.
BLE (Bluetooth Low Energy also known as BTLE) is a newer standard designed with low energy requirements in mind. The idea behind BLE is that for most IoT applications builders can trade bandwidth and range for low energy consumption. BLE was developed separately but rolled into Bluetooth 4.0 in 2009 so it is supported by most newer phones, tablets, etc.
There are several other protocols such as ZigBee, Z-wave, ANT for short-range communication and wearable devices and LoRa, GPRS, LTE for long-range communication. Bluetooth and WiFi are also the only protocols that your computer directly supports. All other protocols will require additional hardware.
Linux and Bluetooth with smart lights
Now to the next step. If we can control the smart light for home by reading and writing attributes of the light, we can also automate this. Let’s see if there is something that we can use on Linux.
After a quick search, I found that Linux distributions include a bluez libraries that connects to the underlying hardware. Actually, bluez is a an official Linux Bluetooth protocol stack which means it includes everything from modules, libraries to tools we can use to interact with the devices. Bluez also included bluetoothctl utility which seemed like a promising start. It is using I’m using a Debian distribution for this sample, but I also tested the tools in CentOS 8 virtual machine, so it should be widely supported.
Bluetoothctl opens in interactive mode and you can quickly scan, pair and connect to bluetooth devices. Let’s have a look.
$ bluetoothctl
Agent registered
[bluetooth]#
If the utility starts correctly, it says “Agent registered” which means that utility found the bluetooth hardware and is ready to use it.
Scanning for Bluetooth smart lights for home
Now let’s see what’s around us. Run the scan…
[bluetooth]# scan on
Discovery started
[CHG] Controller DC:XX:XX:XX:XX:34 Discovering: yes
[NEW] Device 45:XX:XX:XX:XX:70 45-74-CA-26-68-70
[NEW] Device 65:XX:XX:XX:XX:FE 65-27-DA-83-EB-FE
[NEW] Device 61:XX:XX:XX:XX:3C 61-66-A4-68-E0-3C
[CHG] Device 38:XX:XX:XX:XX:18 RSSI: -80
[CHG] Device 38:XX:XX:XX:XX:18 ManufacturerData Key: 0x3118
[CHG] Device 38:XX:XX:XX:XX:18 ManufacturerData Value:
1b d7 81 38 d2 ...8.
[NEW] Device C8:XX:XX:XX:XX:E8 EON Smart Box
[bluetooth]#
Note that Xs in the MAC addresses are there to obscure the actual MAC. Don’t expect Xs in a hexadecimal notation.
As you can see, there are three devices near me. Lamp-WC is the one that I’m looking for. Now list all of the devices and connect to the smart lights for home.
[bluetooth]# devices
Device 38:XX:XX:XX:XX:18 Lamp-WC
Device DB:XX:XX:XX:XX:B1 Mito volo
Device 7C:XX:XX:XX:XX:07 P3
[bluetooth]# connect 38:XX:XX:XX:XX:18
Attempting to connect to 38:XX:XX:XX:XX:18
[CHG] Device 38:XX:XX:XX:XX:18 Connected: yes
Connection successful
[NEW] Primary Service
/org/bluez/hci0/dev_38_XX_XX_XX_XX_18/service000c
00001801-0000-1000-8000-00805f9b34fb
Generic Attribute Profile
[NEW] Characteristic
/org/bluez/hci0/dev_38_XX_XX_XX_XX_18/service000c/char000d
00002a05-0000-1000-8000-00805f9b34fb
Service Changed
[NEW] Descriptor
/org/bluez/hci0/dev_38_XX_XX_XX_XX_18/service000c/char000d/desc000f
00002902-0000-1000-8000-00805f9b34fb
Client ...
Connect and authenticate
I managed to connect to the lights. The utility outputs the information on all of the services, characteristics and descriptors.
In my previous article on using Android to control Bluetooth devices the nRF Connect app displayed all this information very clearly. I can use this app to find the characteristics that I need.
Now, let’s search for password and authenticate. GUID of password is 00002901-0000-1000-8000-00805f9b34fb. I can search for this in our output:
[NEW] Characteristic
/org/bluez/hci0/dev_38_81_D7_1B_31_18/service0023/char003c
0000ffba-0000-1000-8000-00805f9b34fb
Unknown
[NEW] Descriptor
/org/bluez/hci0/dev_38_81_D7_1B_31_18/service0023/char003c/desc003e
00002901-0000-1000-8000-00805f9b34fb
Characteristic User Description
VoilĂ . Found it. Now select the attribute or characteristic that we want to change. After that, we’ll try to send the PIN that we defined in the previous article.
[Lamp-WC]# menu gatt
Menu gatt:
Available commands:
...
...
help Display help about this program
export Print evironment variables
[Lamp-WC]# select-attribute 0000ffba-0000-1000-8000-00805f9b34fb
[Lamp-WC:/service0023/char003c]#
If you look at prompt, it says Lamp-WC:/service0023/char003c. This means, that we’re connected to the smart lights for home and that our characteristic is selected. Now, let’s send the PIN.
[Lamp-WC:/service0023/char003c]# write 0x30313233
This is where I got stuck. I tried different approaches to write a simple string of “0123” in hex but I haven’t had any success.
Workaround for writing attributes
After a frustrating evening, I decided it was time to rethink the approach. I decided against browsing the source code of the tool and instead opted for an alternative tool.
Enter gatttool. This tool is also part of the bluez package but was primarily created to interact with attributes of the device and subscribe to changes of the attribute. This means that you get notified when the value of an attribute changes.
Let’s see how it works.
root@centos8 centos]# gatttool -I
[ ][LE]> connect 38:XX:XX:XX:XX:18
Attempting to connect to 38:XX:XX:XX:XX:18
Error: connect error: Connection timed out (110)
[38:XX:XX:XX:XX:18][LE]> connect 38:XX:XX:XX:XX:18
Attempting to connect to 38:XX:XX:XX:XX:18
Connection successful
[38:XX:XX:XX:XX:18][LE]> help
help Show this help
....
mtu <value> Exchange MTU for GATT/ATT
And it works. We managed to connect to the smart lights for home and call for help. Now let’s have a look around.
[38:XX:XX:XX:XX:18][LE]> primary
attr handle: 0x0001, end grp handle: 0x000b uuid: 00001800-0000-1000-8000-00805f9b34fb
attr handle: 0x000c, end grp handle: 0x000f uuid: 00001801-0000-1000-8000-00805f9b34fb
attr handle: 0x0010, end grp handle: 0x0022 uuid: 0000180a-0000-1000-8000-00805f9b34fb
attr handle: 0x0023, end grp handle: 0xffff uuid: 0000ffb0-0000-1000-8000-00805f9b34fb
[38:XX:XX:XX:XX:18][LE]> char-desc
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-80 ...
...
... 002901-0000-1000-8000-00805f9b34fb
[38:XX:XX:XX:XX:18][LE]> char-read-hnd 0x001e
Characteristic value/descriptor: 50 61 75 6c 6d 61 6e 6e 20 4c 69 63 68 74 20 47 6d 62 48 00 00 00 00 00 00 00 00 00 00 00 00
Calling primary displays a list of characteristics that we can use to identify the device and check the capabilities. I have a head start and I can search for the manufacturer name UUID that I already identified in the previous article on using Android to control Bluetooth devices.
The string of hexadecimal numbers translates to an ASCII string of “Paulmann Licht GmbH”. We found the right attribute, now let’s authenticate with the device.
Authentication with smart lights for home using gatttool
Recall, that we’re looking for a characteristic with the name password and want to write the PIN to the associated attribute.
[38:XX:XX:XX:XX:18][LE]> char-desc
handle: 0x0001, uuid: 00002800-0000-1000-8000-00805f9b34fb
handle: 0x0002, uuid: 00002803-0000-1000-80 ...
...
handle: 0x003b, uuid: 00002901-0000-1000-8000-00805f9b34fb
handle: 0x003c, uuid: 00002803-0000-1000-8000-00805f9b34fb
handle: 0x003d, uuid: 0000ffba-0000-1000-8000-00805f9b34fb
handle: 0x003e, uuid: 00002901-0000-1000-8000-00805f9b34fb
[38:XX:XX:XX:XX:18][LE]> char-write-req 0x003d 30313233
Characteristic value was written successfully
We listed all the characteristics again and found the UUID corresponding to the password attribute. For instance, you can see here that each attribute also has a “handle”, a shorthand to access the attribute.
Our handle is 0x003d and we use that handle to write “30313233”. This is actually a set of hexadecimal numbers that we can write as 0x30 0x31 0x32 0x33 but gatttool also supports a shorthand to simplify our life.
The response says that the write was successful so we can assume that authentication was a success. Let’s try to play with the lights:
> [38:XX:XX:XX:XX:18][LE]> char-write-req 0x0031 00
Characteristic value was written successfully
[38:XX:XX:XX:XX:18][LE]> char-write-req 0x0031 01
Characteristic value was written successfully
[38:XX:XX:XX:XX:18][LE]> char-write-req 0x0034 20
Characteristic value was written successfully
[38:XX:XX:XX:XX:18][LE]> char-read-hnd 0x003c
Characteristic value/descriptor: 08 3d 00 ba ff
I see the lights turning on and off and dimming. So it works.
With the first two command we write 0x00 and 0x01 consequtively to turn the lights off and on again. The third command is a command to dim the lights to about a third (dimmer in this lights has a range of 0 to 100 and 0x20 = 32 in decimal).
Conclusion
In the previous article I set out to connect to the smart lights for home using nRF Connect app and turn them on and off and in this article I used bluez library and bluetoothctl and gatttool utilities to do the same from a Debian and CentOS Linux laptop.
In addition, I tested how scanning works, learned about MAC addresses and successfully connected to the phone reading and writing attributes.
Now I’m able to control the lights from my laptop and in my next article, I’ll use Python to write a program. After that, I’ll make a library that I can use whenever I want to work on home automation.
No Comments