Getting rid of dependence on external utilities #675
Replies: 11 comments 15 replies
-
Hi @Magalex2x14 Magalex2x14, welcome back! The way I have programmed it now is running some command line commands via the subprocess package.
I have limited time to look into this, but feel free to make a better proposal. I’m going to move to a new house, so can’t spend much time coming months. |
Beta Was this translation helpful? Give feedback.
-
Yes, that could help probably. It’s a difficult error, and I still can’t find out why some people have these errors. It certainly seems related to the Bluetooth adapter, not running properly. Let’s just collect info in this topic and we will see how far we get. |
Beta Was this translation helpful? Give feedback.
-
I tried the 2nd code, I copies the code into the BLE monitor folder and added the following code in for interface in interface_list:
hci = BluetoothHCI(device_id=interface, auto_start=False)
hci_info = hci.get_device_info()
_LOGGER.error(hci_info) It finds the HCI info nicely.
The fist MAC looks a bit weird, with one 0 in the first byte of the MAC, but that's probably not a big issue to solve (should be But after that, it won't find my HCI adapter anymore.
Not sure if that is related to the following requirement:
Something to figure out tomorrow... |
Beta Was this translation helpful? Give feedback.
-
A small investigation into the bank: Examining the result of executing the A short googling gave the code for this command: ogf 0x04, ocf 0x0009 Successful attempt with hcitool: root@mini2x14:/home/aleksey# hcitool -i hci1 cmd 0x04 0x0009
< HCI Command: ogf 0x04, ocf 0x0009, plen 0
> HCI Event: 0x0e plen 10
01 09 10 00 11 71 DA 7D 1A 00 Relevant event in btmon output:
In addition, there are no commands similar to HCIGETDEVINFO, HCIUP, HCIDOWN in the supported lists. There are no such commands here either - HCI commands. Reset is present, yes.
In general, on the one hand, it s a success (we can get a mac address and reset the interface), on the other, even more questions... We need to check if the "Event loop stopped before future completed" error always occurs when trying to start a new scan period (I'm pretty sure it is): self._event_loop.run_until_complete(btctrl[hci].send_scan_request(self._active)) It seems to me that it never appeared in the cycle self._event_loop.run_forever() that is, during the actual collection of packets. Thus, it turns out that the event leading to the problem with starting a new scan occurs in the previous period. And since previous period is not interrupted, we have a chance to catch the corresponding event. It is possible to make a separate parser for them. At the initial stage, for example, we can log all events other than the LE Meta Event (0x3e), and in the future, upon the occurrence of certain events (such as Hardware error (0x10) or others identified as a result of collecting user statistics), we can set special flag and decide to reset the interface or user notification immediately after the end of the current period. |
Beta Was this translation helpful? Give feedback.
-
@Ernst79 I seem to have found the root of the problem with Event loop stopped before future completed. I made a small program with the BLEmonitor and HCIdump classes (slightly modified to run outside of HA): print("Init")
blemonitor = BLEmonitor(None)
print("blemonitor.start()")
blemonitor.start()
time.sleep(10)
print("blemonitor.restart()")
blemonitor.restart()
time.sleep(10)
print("blemonitor.stop()")
blemonitor.stop() It turned out that the error always occurs when the scan is restarted (blemonitor.restart()), and does not occur at the start of the first period. Also, after blemonitor.stop() the program does not exit (the HCIdump thread hangs). As far as I understand, the problem lies in the fact that when event loop must be stopped to restart scanning at the end of the period the attempt to send a scan request has not yet completed, because aioblescan is still pending initialization, because there is no response from the interface about the supported commands and features (aioblescan needs to know whether it is asking for a legacy scan or an extended one): There is no choice - we need to check the initialization status of aioblescan. Catching an error in this case is not enough, since there is a negative effect in the form of a feature and a thread stuck. I think ideally the timeout should be implemented in aioblescan. |
Beta Was this translation helpful? Give feedback.
-
Working example using BlueZ DBus API (bluetooth daemon should be running): import dbus
bus = dbus.SystemBus()
manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.freedesktop.DBus.ObjectManager")
managed_objects = manager.GetManagedObjects()
for path, iface in managed_objects.items():
if ("hci" in path and "org.bluez.Adapter1" in iface and "org.freedesktop.DBus.Properties" in iface):
hci_props = dbus.Interface(bus.get_object("org.bluez", path), "org.freedesktop.DBus.Properties")
print(hci_props.Get("org.bluez.Adapter1", "Address"))
print(hci_props.Get("org.bluez.Adapter1", "Powered"))
if hci_props.Get("org.bluez.Adapter1", "Address") == "00:1A:7D:DA:71:11":
hci_props.Set("org.bluez.Adapter1", "Powered", True)
print(hci_props.Get("org.bluez.Adapter1", "Powered")) However, the python-dbus library fails to install in the official HassOS image. Found in my bookmarks excellent exhaustive materials from @ukBaz - one and two. As a result, I settled on pydbus, although it has not been updated for a long time, and many consider it abandonware. So, here is working example for pydbus: from pydbus import SystemBus
BUS_NAME = 'org.bluez'
OBJ_MANAGER = 'org.freedesktop.DBus.ObjectManager'
bus = SystemBus()
btadaptermac = "00:1A:7D:DA:71:11"
bluez = bus.get(BUS_NAME, '/')
manager = bluez[OBJ_MANAGER]
managed_objects = manager.GetManagedObjects()
for path, iface in managed_objects.items():
if "hci" in path:
print(path)
adapter = bus.get(BUS_NAME, path)
print(f'{adapter.AddressType} address: {adapter.Address}, powered = {adapter.Powered}')
if adapter.Address == btadaptermac:
# change to False to power off
adapter.Powered = True
print(f'{adapter.AddressType} address: {adapter.Address}, powered = {adapter.Powered}') |
Beta Was this translation helpful? Give feedback.
-
@Ernst79 Do you remember what for rfkill was added to the reset procedure? Were there situations when bluetooth was blocked? |
Beta Was this translation helpful? Give feedback.
-
I’m not sure there actually were situations where rfkill was needed, we have to check #295 for that. |
Beta Was this translation helpful? Give feedback.
-
That's sounds ok. I found a small bug, on my main machine, after the update to 7.5.0. Didn't had time yet to look into it. It continues to run, so not a big issue right away.
|
Beta Was this translation helpful? Give feedback.
-
Houston, we have a problem! I don’t know how I checked the installation of the pydbus module on Homeassistant OS, but it is not work for me now either:
Crap! Apparently, I messed up something (maybe I only checked on my HA core installation on Debian)... In general, the new_bt_helpers branch contains untested code using pydbus (and rfkill using pyric).
Perhaps I'll move towards point number 2. P.S. more observations: the HA Supervisor uses DBus, but the search over Core code does not give any results... |
Beta Was this translation helpful? Give feedback.
-
The next step after #703 I'm thinking of disabling all adapter functions except for LE at the start of integration. I see this as an option similar to restarting the interface. But later. |
Beta Was this translation helpful? Give feedback.
-
Discussion in continuation of the topic raised here, and to accumulate knowledge about the methods of solving this issue.
As far as I understand, at the moment we use external utilities to solve the following tasks:
At leisure, I decided to delve a little into this topic, and came across:
there are many useful links to sources of technical details inside the comments of the both sources.
The second code solves the problem of resetting the interface (and allows you to control the success of the operation), but I'm not sure about the first one, since it uses system calls, which may not be the right way (given the possible inclusion of integration in the official home-assistant repository). I see two alternatives - to use the Bluez DBus API to make requests to the bluetooth daemon, or using the second code to iterate over interface numbers in series until the first one is encountered, which will return an erroneous message in response to a hci_dev_info request :)
Beta Was this translation helpful? Give feedback.
All reactions