0

I am trying to turn my bluetooth Hue bulb on/off and change brightness using my Raspberry Pi 4B. The bulb is on, and I have successfully connected to it using bluez. When I try to run 'char-write-req 0x0027 01' to turn it on, I get this message:

GLib-WARNING **: 22:53:34.807: Invalid file descriptor

I can see that the connection is successful, but whenever I try to write a value to it, I just get this message and it disconnects. Running bluetoothctl 5.50. I have seen the patch conversation here: https://www.spinics.net/lists/linux-bluetooth/msg67617.html. But I am not sure it applies and I also wouldn't even know how to apply it. Can someone please help me!

EDIT I ditched the gatttool and am using bluetoothctl to connect to the bulb and menu gatt to send commands to it.

I figured out that the characteristic for toggling the light on and off is 932c32bd-0002-47a2-835a-a8d455b859dd (For my Philips Hue A19). After connecting to the bulb, I was able to select this attribute and use 'write 01' to turn it on and 'write 00' to turn it off. The brightness characteristic is 932c32bd-0002-47a2-835a-a8d455b859dd. When I read, it outputs 'fe', which is HEX for 254. This is the highest brightness setting, which it was already set to. I can use 'write ' where value ranges from 1-254 to change the brightness.

Anvar
  • 1
  • 2
  • You say that you are using `bluetoothctl` tool but that doesn't have a `char-write-req` command. I think you might be using `gatttool` which was [deprecated](https://git.kernel.org/pub/scm/bluetooth/bluez.git/commit/?id=b1eb2c4cd057624312e0412f6c4be000f7fc3617) back in 2017. I would suggest you try with`bluetoothctl` – ukBaz Jan 29 '21 at 07:14
  • I need to write an on/off command to the light bulb and also a change brightness command. I am now trying to use the "acquire-write" command in the gatt menu of bluetoothctl. I have identified that UUID for turning the light on/off is 932c32bd-0000-47a2-835a-a8d455b859dd. It is listed as a service (not a characteristic) when I run list-attributes. So, when I do a "acquire-write" command, it said unable to acquire write: not a characteristic. I also cannot do a simple "read" – Anvar Jan 29 '21 at 12:13
  • Also, I just selected another attribute (932c32bd-0002-47a2-835a-a8d455b859dd) which is used to change the brightness of the bulb. It successfully connects, and when I do a read, it outputs: Device [mac address] ServicesResolved: no Device [mac address] connected: no and then it disconnects me. – Anvar Jan 29 '21 at 12:17
  • Putting output in the comments is not very helpful because of limited space and formatting. It is more helpful if you update the question with the actual transcript of the failing attempt. – ukBaz Jan 29 '21 at 13:30

2 Answers2

1

Using acquire-write in bluetoothctl is typically not the correct command. read and write are what you want.

After starting starting bluetoothctl I would expect the series of commands to be:

connect <Address of bulb>
menu gatt
select-attribute 932c32bd-0002-47a2-835a-a8d455b859dd
write 1
write 0

If you wanted to script this, then below is a Python3 script that I would expect to turn the bulb on then off.

from time import sleep
from pydbus import SystemBus

BLUEZ_SERVICE = 'org.bluez'
BLUEZ_DEV_IFACE = 'org.bluez.Device1'
BLUEZ_CHR_IFACE = 'org.bluez.GattCharacteristic1'


class Central:

    def __init__(self, address):
        self.bus = SystemBus()
        self.mngr = self.bus.get(BLUEZ_SERVICE, '/')
        self.dev_path = self._from_device_address(address)
        self.device = self.bus.get(BLUEZ_SERVICE, self.dev_path)
        self.chars = {}

    def _from_device_address(self, addr):
        """Look up D-Bus object path from device address"""
        mng_objs = self.mngr.GetManagedObjects()
        for path in mng_objs:
            dev_addr = mng_objs[path].get(BLUEZ_DEV_IFACE, {}).get('Address', '')
            if addr.casefold() == dev_addr.casefold():
                return path

    def _get_device_chars(self):
        mng_objs = self.mngr.GetManagedObjects()
        for path in mng_objs:
            chr_uuid = mng_objs[path].get(BLUEZ_CHR_IFACE, {}).get('UUID')
            if path.startswith(self.dev_path) and chr_uuid:
                self.chars[chr_uuid] = self.bus.get(BLUEZ_SERVICE, path)


    def connect(self):
        """
        Connect to device.
        Wait for GATT services to be resolved before returning
        """
        self.device.Connect()
        while not self.device.ServicesResolved:
            sleep(0.5)
        self._get_device_chars()

    def disconnect(self):
        """Disconnect from device"""
        self.device.Disconnect()

    def char_write(self, uuid, value):
        """Write value to given GATT characteristic UUID"""
        if uuid.casefold() in self.chars:
            self.chars[uuid.casefold()].WriteValue(value, {})
        else:
            raise KeyError(f'UUID {uuid} not found')

    def char_read(self, uuid):
        """Read value of given GATT characteristic UUID"""
        if uuid.casefold() in self.chars:
            return self.chars[uuid.casefold()].ReadValue({})
        else:
            raise KeyError(f'UUID {uuid} not found')


device_address = '11:22:33:44:55:66'
light_state = '932c32bd-0002-47a2-835a-a8d455b859dd'


dev = Central(device_address )
dev.connect()
dev.char_write(light_state , [1])
sleep(5)
dev.char_write(light_state , [0])
print(dev.char_read(light_state ))
dev.disconnect()

As I don't have a bulb the above is untested. But should be a good outline of what is required.

ukBaz
  • 6,985
  • 2
  • 8
  • 31
  • using write 1 or write 0 just outputs "Attempting to write /org/bluez/hci0/dev_E3_65_06_B2_68_B4/service0023/char0026" and then shows: [CHG] Device E3:65:06:B2:68:B4 ServicesResolved: no [CHG] Device E3:65:06:B2:68:B4 Connected: no Also, I tried running your code and it doesn't recognized "pydbus" even after I installed it. Running on raspberry pi btw. – Anvar Jan 29 '21 at 14:26
  • Hmm? That looks like it is a service. I thought `*0002*` was a character. We need to see a list of characteristics as they are what we will read and write to. – ukBaz Jan 29 '21 at 14:31
  • Made the edit. 0002 is a characteristic, yes. But one forum I found online stated that specific characteristic is for changing the brightness, so I do not know what the write format is to select a specific brightness. That form also stated that the attribute 932c32bd-0000-47a2-835a-a8d455b859dd (notice the *0000*) was for toggling the light on and off. However, this is listed as a primary service. So I'm a little confused here. Also, I really appreciate all the help! – Anvar Jan 29 '21 at 14:46
  • I've seen in some implementations that they are using the `b8843add-0003-4aa1-8794-c3f462030bda` characteristic for brightness. A value between 0 - 255. However I have no way of knowing if that is correct for your bulb. On some devices you can read the value and that will give you a clue to the format. – ukBaz Jan 29 '21 at 16:08
  • Honestly I don't think it's the attribute I'm selecting. Either attribute should output a value when I read or write. Reading the b8843add-0003-4aa1-8794-c3f462030bda characteristic says org.bluez.Error.NotPermitted. And then when I write to it, it attempts to write and then disconnects just as before. If it is a permission issue, idk how to resolve that. But could it also be that I am not using a bluetooth adapter for the raspberry pi? The bulb I have is Philips Hue A19. – Anvar Jan 29 '21 at 17:05
  • Try using something like [nRF Connect](https://www.nordicsemi.com/Software-and-tools/Development-Tools/nRF-Connect-for-mobile) on a mobile to explore the characteristics. That has more information on flags and permissions on the characteristics. – ukBaz Jan 29 '21 at 17:10
  • 1
    Found the following post which suggests the bulb can only be paired/bonded with one phone/client at a time: https://www.raspberrypi.org/forums/viewtopic.php?p=1783033&sid=d1fa9a37822cf9ab97cd6b76a3be7a81#p1783033 Could this be your issue? – ukBaz Jan 29 '21 at 17:29
  • That's a great point. I ended up resetting the hue bulb from my phone and reconnecting to my raspi to the new MAC address it created. I was able to pair it successfully. This time, when I try to read or write, it attempts to do it but the message now says "Failed to write: org.bluez.Error.Failed". Do you have a discord where we can discuss this further? – Anvar Jan 29 '21 at 17:56
0

It worked for me after I reset the Bulb with the bluetooth app to factory settings. The bulb appears to be able to be paired/bonded to a single device only. If other devices try to communicate with the bulb, the connection is lost, as @ukBaz mentioned in his comment.

Olloxan
  • 21
  • 5