► 前言:
在嵌入式 Linux(如 Yocto)的開發環境中,藍牙低功耗(BLE)的應用開發往往讓人感到頭痛。雖然 Linux 官方有強大的 BlueZ 協議棧,但直接操作 D-Bus 或使用 C 語言開發對於快速原型驗證來說門檻稍高。
本篇博文將帶大家在 SL1680 平台上,使用 Python 的 Bluezero 套件來開發 BLE Peripheral。Bluezero 是一個封裝 BlueZ D-Bus 介面的高階套件,能讓我們用更簡潔的 Python 程式碼實現 GATT 服務、廣播與掃描功能。
►環境準備:Yocto 與 Bluetoothctl
在開始撰寫程式之前,需要確保Synaptics SL1680的Yocto環境已經安裝必要的相依套件。
1. 修改 local.conf
請在 Yocto 的 local.conf 中加入以下軟體包:
IMAGE_INSTALL:append = " \
python3-pygobject
gobject-introspection
gobject-introspection-dev
cairo-dev
bluez5-開發
"
系統編譯重新bitbake image
$ bitbake astra-media
燒錄製作SL1680開發板,參考Synaptics 官方文件。
開發板啟動後記得安裝 bluezero 軟體包:
sh-5.1# pip install bluezero
2. 啟動藍牙硬體
Python 的 bluezero 套件依賴於系統底層的藍牙狀態。在執行 Python 程式之前,必須先使用 bluetoothctl 確保藍牙硬體已開啟。
請在終端中執行以下步驟:
sh-5.1# bluetoothctl
[bluetooth]# 開啟電源
[CHG] 控制器 XX:XX:XX:XXXX:XX 類別: 0x00080000
更改電源成功
[更改] 控制器 XX:XX:XX:XXXX:XX 已通電:是
[bluetooth]# 退出
►代碼:打造一個互動式 GATT 服務
接下來,將撰寫一段 Python 程式碼,此範例會建立一個 BLE 周邊設備,包含一個自訂的 Service(服務)和 Characteristic(特徵),支援讀取(Read)、寫入(Write)與通知(Notify)。
功能說明:當手機端輸入文字(例如:「好棒棒」)時,SL1680會接收到消息並回傳「已收到:好棒棒」給手機。
Python完整程式碼
Python
導入 struct
從 bluezero 匯入 async_tools
從 bluezero 匯入 adapter
從 bluezero 匯入 device
從 bluezero 匯入 peripheral
# 定義自訂的 UUID [引用: 70, 71]
CUSTOM_SERVICE_UUID = '1a8f3532-628b-4435-9774-a034a85b008d'
CUSTOM_INTERACTIVE_CHAR_UUID = 'c284b42c-29d9-4368-85ed-466d333464d2'
ble_peripheral = 無
last_message_from_phone = "還沒有消息。"
def on_connect(ble_device: device.Device):
print("已連接到 " + str(ble_device.address)) # [引用: 74, 75]
def on_disconnect(adapter_address, device_address):
print("已斷開與" + device_address + "的連接") # [引用: 76, 77]
定義自訂讀取回呼函式():
當手機讀取這個特徵時被呼叫
打印(f"手機正在讀取最後一條訊息: {last_message_from_phone}")
return last_message_from_phone.encode('utf-8') # [引用: 78-81]
def custom_write_callback(value, options):
當手機寫入自訂特徵時被呼叫,並透過通知返回訊息
全域變數 last_message_from_phone, ble_peripheral
# 將接收到的 bytes 解碼為字串
解碼訊息 = bytes(value).decode('utf-8')
last_message_from_phone = decoded_message
print(f"💻 收到手機訊息: '{decoded_message}'")
# 準備返回訊息
response_message = f"已收到: {decoded_message}".encode('utf-8')
嘗試:
通過 set_value 發送通知 (Notify)
ble_peripheral.set_value(response_message)
print(f"📱 已返回訊息至手機: '{response_message.decode('utf-8')}'")
except (KeyError, IndexError):
print("錯誤:找不到自訂特徵物件。") # [cite: 82-93]
定義自訂通知回呼函式(custom_notify_callback)(notifying, characteristic):
自訂通知的回呼函式
全域 ble_peripheral
If notifying:
ble_peripheral = characteristic
print("✅ 手機已訂閱自訂通知")
否則:
print("❌ 手機已取消訂閱自訂通知") # [cite: 94-101]
定義主要函式(adapter_address):
全球藍牙
# 初始化周邊設備 [cite: 104]
ble = peripheral.Peripheral(
適配器地址
local_name="選項回呼測試")
# 新增主要服務 [cite: 107]
ble.add_service(srv_id=1, uuid=CUSTOM_SERVICE_UUID, primary=True)
# 新增特徵 (Characteristic) [cite: 108]
ble.add_characteristic(
伺服器ID=1,角色ID=1,
uuid=CUSTOM_INTERACTIVE_CHAR_UUID,
值=[],通知=False,
設置標誌為可讀、可寫、可通知 [cite: 113]
flags=['讀取', '寫入', '通知'],
# 指定對應的回呼函式 [cite: 115-117]
read_callback=custom_read_callback,
write_callback=custom_write_callback,
notify_callback=custom_notify_callback
)
發布服務並啟動事件循環 [cite: 119-123]
print("📢 廣告服務中... 等待連線。")
ble.on_connect = on_connect
ble.on_disconnect = on_disconnect
ble.publish()
if __name__ == '__main__':
ble = 無
自動抓取第一個可用的藍牙適配器 [cite: 126]
dongle = list(adapter.Adapter.available())[0]
print(f"使用藍牙適配器: {dongle.address}")
main(dongle.address)
程式碼解析
- GATT 結構建立透過 add_service 建立服務,並透過 add_characteristic 建立特徵。
- srv_id 和 chr_id 是內部識別用的 ID。
- primary=True 表示這是主服務。
- 回呼函式 (Callbacks)Bluezero 的強大之處在於將複雜的事件處理簡化為 Python 函數:
- read_callback:當外部設備讀取資料時觸發。
- write_callback:當外部設備寫入數據時觸發,我們在此範例中將接收到的數據解碼並打印出來。
- notify_callback:處理訂閱狀態的變更。
- 廣播 (Advertising)最後調用 ble.publish(),這會啟動 BLE 廣播,讓手機可以掃描到名為 "Options Callback Test" 的設備。

► 結論
透過 Bluezero,我們在 SL1680 平台上僅用簡短的 Python 程式碼,就實現了一個功能完整的 BLE 雙向通訊服務。相比於撰寫 C 語言程式碼,這大幅降低了 IoT 應用的開發門檻。希望這篇教學能幫助大家快速上手 Linux 藍牙開發,期待下一篇部落格文章吧!
► 問與答
Q1: Bluezero 和 BlueZ 有什麼區別?
A: BlueZ 是 Linux 系統底層的藍牙協議棧;Bluezero 則是用 Python 封裝的高階套件,讓開發者不用直接處理複雜的 D-Bus,開發更簡單。
Q2: 為什麼在執行 Python 之前要先使用 bluetoothctl?
A: Python 程式依賴底層狀態,必須先透過 bluetoothctl 下達 power on 指令開啟藍牙硬體電源,程式才能運行。
Q3:Yocto 環境需要安裝什麼?
A: 除了 bluezero 本身,還需要在 local.conf 中加入 bluez5-dev、python3-pygobject 和 gobject-introspection-dev 等相依套件。
Q4: 程式碼中的 UUID 是用來做什麼的?
它是一個128位的唯一識別碼,用於定義並區分這是一種什麼樣的服務(Service)或特徵(Characteristic)。
Q5: 傳輸中文(如:好棒棒)要注意什麼?
A: BLE 底層傳輸的是 Bytes(十六進位數值),Python 接收後必須使用 .decode('utf-8') 解碼才能顯示正確的中文字串。
延伸資源
評論