You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Python脚本终端运行正常,crontab执行时触发BLE蓝牙相关错误

问题:macOS下crontab执行BLE控制脚本提示蓝牙已关闭

我编写了一段使用bleak和asyncio控制BLE蓝牙设备的Python脚本,在PyCharm或终端手动运行时完全正常,但通过crontab定时执行时抛出错误,提示蓝牙设备已关闭。运行环境为macOS。

脚本内容

#!/usr/bin/python
from bleak import BleakClient
import asyncio
import time  # 原脚本遗漏此导入,需补充

address = "DFB18A2C-6BAB-439E-AF05-485FB4259B75"
MODEL_NBR_UUID = "99FA0002-338A-1024-8A49-009C0215F78A"

async def main(address):
    async with BleakClient(address) as client:
        for i in range(3):
            await client.write_gatt_char(MODEL_NBR_UUID, bytes.fromhex("0800"))
            time.sleep(0.5)  # 建议替换为await asyncio.sleep(0.5),避免阻塞事件循环

asyncio.run(main(address))

报错信息

Traceback (most recent call last):
  File "/Users/emileberhard/PycharmProjects/BedMove/main.py", line 19, in <module>
    asyncio.run(main(address))
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/runners.py", line 44, in run
    return loop.run_until_complete(main)
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/asyncio/base_events.py", line 642, in run_until_complete
    return future.result()
  File "/Users/emileberhard/PycharmProjects/BedMove/main.py", line 13, in main
    async with BleakClient(address) as client:
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/bleak/backends/client.py", line 61, in __aenter__
    await self.connect()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/bleak/backends/corebluetooth/client.py", line 78, in connect
    device = await BleakScannerCoreBluetooth.find_device_by_address(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/bleak/backends/scanner.py", line 220, in find_device_by_address
    return await cls.find_device_by_filter(
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/bleak/backends/scanner.py", line 249, in find_device_by_filter
    async with cls(detection_callback=apply_filter, **kwargs):
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/bleak/backends/corebluetooth/scanner.py", line 44, in __init__
    self._manager = CentralManagerDelegate.alloc().init()
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/bleak/backends/corebluetooth/CentralManagerDelegate.py", line 88, in init
    raise BleakError("Bluetooth device is turned off")
bleak.exc.BleakError: Bluetooth device is turned off
Exception ignored in: <CentralManagerDelegate objective-c instance 0x0>
Traceback (most recent call last):
  File "/Library/Frameworks/Python.framework/Versions/3.9/lib/python3.9/site-packages/bleak/backends/corebluetooth/CentralManagerDelegate.py", line 102, in __del__
IndexError: NSRangeException - Cannot remove an observer <CentralManagerDelegate 0x7fd036fbe0b0> for the key path "isScanning" from <CBCentralManager 0x600000aab100> because it is not registered as an observer.
Exception ignored in: <function CentralManagerDelegate.__del__ at 0x7fd01863cca0>

解决方案

核心原因

macOS的crontab运行在无用户会话的后台环境,无法访问CoreBluetooth服务——该服务需要绑定到活跃的用户GUI会话才能正常工作,因此crontab执行时会被判定为蓝牙未开启。

替代方案:使用launchd定时执行

launchd是macOS原生的任务管理工具,支持在用户会话上下文运行任务,能正常访问蓝牙服务。

  1. 创建launchd配置文件
    在~/Library/LaunchAgents/目录下新建com.yourname.bedmove.plist文件,内容如下(根据实际路径修改):
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>Label</key>
    <string>com.yourname.bedmove</string>
    <key>ProgramArguments</key>
    <array>
        <string>/Library/Frameworks/Python.framework/Versions/3.9/bin/python3</string>
        <string>/Users/emileberhard/PycharmProjects/BedMove/main.py</string>
    </array>
    <key>StartInterval</key>
    <integer>300</integer> <!-- 执行间隔,单位秒,这里是5分钟 -->
    <key>RunAtLoad</key>
    <true/> <!-- 登录时立即执行一次 -->
    <key>StandardOutPath</key>
    <string>/Users/emileberhard/PycharmProjects/BedMove/logs/out.log</string>
    <key>StandardErrorPath</key>
    <string>/Users/emileberhard/PycharmProjects/BedMove/logs/error.log</string>
</dict>
</plist>
  1. 准备日志目录
    创建日志目录,避免权限问题:
mkdir -p /Users/emileberhard/PycharmProjects/BedMove/logs
  1. 加载并启动任务
# 加载配置
launchctl load ~/Library/LaunchAgents/com.yourname.bedmove.plist
# 启动任务
launchctl start com.yourname.bedmove
# 查看任务状态
launchctl list | grep com.yourname.bedmove

脚本优化

原脚本中在async函数里使用time.sleep(0.5)会阻塞asyncio事件循环,建议替换为:

await asyncio.sleep(0.5)

同时补充遗漏的import time(如果保留原sleep的话),或者直接移除import time改用asyncio的sleep。


内容的提问来源于stack exchange,提问作者emileber

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.26 02:03:13