Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Devices that do not include a service UUID in advertising data cannot be detected on macOS 12.0 to 12.2 unless running in app created by py2app #720

Closed
dlech opened this issue Jan 5, 2022 · 6 comments · Fixed by #753
Labels
Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend

Comments

@dlech
Copy link
Collaborator

dlech commented Jan 5, 2022

  • bleak version: 0.14.0
  • Python version: all
  • Operating System: macOS 12.x

Description

This is basically the same issue as #635. That issue was closed because there is now a workaround available in Bleak v0.14.0 that works in most cases. However, there is one case that doesn't have an acceptable workaround. If a device does not include a service UUID in the advertising data, then the advertising data from that device cannot be received in Bleak.

Call to action

This is a regression from previous versions of macOS. Please everyone report this issue to Apple using the Feedback Assistant app. If enough people report it, hopefully they will prioritize fixing it.

Workaround

This isn't great, but it is possible to convert your Python script to an app using py2app to work around the issue. Here is an example setup.py that can be uses as a starting point:

from setuptools import setup

setup(
    app=["my_script.py"],
    setup_requires=["py2app"],
    options=dict(
        py2app=dict(
            plist=dict(
                NSBluetoothAlwaysUsageDescription="This app uses Bluetooth.",
            ),
        ),
    ),
)

Then run python setup.py py2app to build the .app.

If your script does not have a graphical user interface, you can run it with:

open -n -W --stdin $TTY --stdout $TTY --stderr $TTY dist/my_script.app

See man open for more info.

Control C doesn't work to stop the program, but you can secondary-click on the icon that is created in the dock and force quit if needed.

@dlech dlech added the Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend label Jan 5, 2022
@hbldh
Copy link
Owner

hbldh commented Jan 5, 2022

Very good to keep an issue alive for this.

@dlech dlech changed the title Devices that do not include a service UUID in advertising data cannot be detected on macOS 12 Devices that do not include a service UUID in advertising data cannot be detected on macOS 12 unless running in app created by py2app Jan 10, 2022
@dlech
Copy link
Collaborator Author

dlech commented Jan 10, 2022

I did a deep dive into the logs in Console.app (enabled debug and info messages and filtered on bluetoothd and python/my_script processes) over the weekend and I think I have a pretty good understanding of the issue at this point. Following the advice of @arthurbiancarelli in #635 (comment), I was able to successfully get things to work (scanning without specifying service uuids) when running Bleak in an app built with py2app. I also found a workaround so that you don't have to create a graphical user interface (I updated the first comment in this issue with the workaround).

My theory is that Apple is bringing macOS closer inline with iOS. So the comments in the CoreBluetooth docs about foreground and background scanning now apply to macOS as well.

In order for your Python script to be considered a foreground app, it has to be a .app with an icon in the dock (doesn't necessarily have to have a visible window) and the app has to have a valid signature (done automatically by py2app).

The reason scripts that are run in a terminal window fail is because the Python Framework includes a Python.app. The bluetoothd daemon sees that the process running your script is the Python.app but the foreground app is the Terminal.app, so it considers your Python script as a background app and therefore background scanning rules apply.

The reason Python includes a Python.app is so that it can launch programs that use graphical user interfaces. So you might think if you just open a window (i.e. import turtle; turtle.showturtle()), then your app should be the foreground app and all is good. However, this is where the second rule comes in. Bluetoothd sees that your script isn't part of the Python.app bundle and therefore considers it not properly signed and so you don't get foreground app treatment.

Finally, the NSBluetoothAlwaysUsageDescription key in info.plist is unrelated to the foreground/background scanning issue. If your app has already been given permission to use Bluetooth in System Prefereneces, then NSBluetoothAlwaysUsageDescription doesn't have any effect. However, if your app has not been given permission, then having NSBluetoothAlwaysUsageDescription in your info.plist will prevent a crash from SIGABRT when your application is run.

dlech added a commit that referenced this issue Jan 10, 2022
If bleak is running in a .app (e.g. created with py2app), then scanning
in macOS 12 works as it did in previous versions, so we don't need to
log the error. We can determine this by checking the bundle id since
Python itself is a .app and has a bundle id.

Related: #720
@pauloesteban
Copy link

Hi everyone,

Anyone tried a similar workaround with PyInstaller?

Cheers

@kdewald
Copy link

kdewald commented Jan 24, 2022

@dlech have you have any updates on your research on this topic?

I've been able to reproduce it with a very minimalist console application on XCode (https://github.com/kdewald/MontereyBluetoothError). My theory is that there is some problem between the TCC and the Bluetooth subsystems on Monterey, as looking at the logs shows that certain authorization steps do not happen when running console applications, even though they have Bluetooth authorization.

@dlech
Copy link
Collaborator Author

dlech commented Jan 25, 2022

I haven't done any further research. Reiterating what I have already said, the NSBluetoothAlwaysUsageDescription (I assume this is what you mean when you say "they have Bluetooth authorization") only prevents the app from crashing with SIGABRT. It is completely independent of the "no scan results" problem. The "no scan results" problem has only to do with the ability of the process to be considered the "foreground" app which consists of having an icon in the dock and being properly signed.

@dlech dlech changed the title Devices that do not include a service UUID in advertising data cannot be detected on macOS 12 unless running in app created by py2app Devices that do not include a service UUID in advertising data cannot be detected on macOS 12.0 to 12.2 unless running in app created by py2app Jan 30, 2022
@dlech
Copy link
Collaborator Author

dlech commented Jan 30, 2022

Good news! It looks like Apple has fixed the issue in macOS 12.3 Beta (21E5196i).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Backend: Core Bluetooth Issues and PRs relating to the Core Bluetooth backend
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants