想像一下,清晨,你戴上智慧手環出門慢跑,手環上的心率感測器忠實地記錄著每一次心跳,並即時同步到手機 App 中,繪製出漂亮的運動曲線。跑累了,你輕點手環,切換了手機正在播放的下一首歌曲。回到家,站上體重計,幾秒鐘後,體重、體脂率等數據便自動出現在手機的健康管理 App 裡。
這些看似「理所當然」的智慧生活場景,背後都有一個共同的隱形魔法師在默默工作。你有沒有想過,手環是如何告訴手機「我的心率是 85」?手機又是如何命令手環「播放下一首歌」的?
答案,就藏在我們既熟悉又陌生的「藍牙 (Bluetooth)」技術裡。
不過,傳統的藍牙(現在稱為經典藍牙)雖然適合用在無線耳機這種需要持續傳輸大量數據的場景,但它有個致命的缺點——耗電。如果你的智慧手環每小時都要充電,那它一點也不「智慧」。
為了解決這個問題,低功耗藍牙 (Bluetooth Low Energy, BLE) 應運而生。它專為物聯網 (IoT) 裝置設計,具備以下幾個關鍵特點:
極致省電:裝置可以用一顆小小的鈕扣電池就運作數月甚至數年。
快速連接:能在幾毫秒內完成連接並傳輸數據,完成後立刻休眠。
專注小數據:非常適合傳輸感測器讀值、開關指令等少量、非持續性的資訊。
正是這些特點,讓 BLE 成為了智慧穿戴、健康醫療、智慧家居等領域的熱門技術。
好,我們知道了手環和手機是透過 BLE 在溝通。但它們具體是怎麼「對話」的呢?手機是如何精準地知道要從手環的哪個「地方」去讀取心率,而不是讀到電量或步數?
這就是我們今天要認識的主角——GATT (Generic Attribute Profile) 協議。
但在我們認識GATT之前,還有一個關鍵問題:當數以萬計的 BLE 裝置都可能提供「電池服務」時,手機要如何確保它連上的是「藍牙技術聯盟 (SIG) 」定義的那個標準電池服務,而不是某個廠商自己亂取的名字?
這個問題的答案就是 UUID (Universally Unique Identifier)。
UUID 就是服務 (Service) 和特徵 (Characteristic) 的「身分證號碼」。它是一串獨一無二的編碼,確保了無論裝置的名稱是什麼,我們都能透過這個「身分證號碼」精準地找到我們要的功能。
UUID 分為兩種:
標準 UUID:由藍牙聯盟官方定義,用來表示通用的功能。它們通常是較短的 16 位元碼,例如 0x180F
代表「電池服務」,0x2A37
代表「心率測量」。
自定義 UUID:由開發者自行產生,用於特定產品的獨有功能。它們是一串很長的 128 位元碼,例如 12345678-1234-1234-1234-1234567890AB
。
好了,有了「身分證號碼」的概念後,我們再回頭看 GATT 的結構,一切就豁然開朗了。
以下是 GATT 核心概念的基本定義:
服務 (Service): 功能的集合。將其想像成一個物件或一個模組。例如,一個「心率服務」包含了所有與心率相關的功能 。
特徵 (Characteristic): 實際的資料點或控制點。這是 GATT 層級結構中最重要的部分,是您應用程式直接互動的對象。例如,「心率測量值」就是「心率服務」下的一個特徵 。
屬性 (Properties): 定義了特徵的可操作權限。這是您專案動態 UI 的邏輯基礎。當您取得一個特徵物件後,可以透過其 properties 屬性查詢它是否支援讀取 (read)、寫入 (write)、通知 (notify) 等操作 。例如,一個感測器數值特徵的屬性可能是
read 和 notify,而一個控制 LED 的特徵屬性可能是 write。
描述符 (Descriptor): 提供關於特徵的元數據(metadata),例如人類可讀的描述或數值的單位。。
裝置 (Device)
└── 服務 (Service) - e.g., 心率服務 (UUID: 0x180D)
└── 特徵 (Characteristic) - e.g., 心率測量值 (UUID: 0x2A37)
├── 值 (Value): e.g., [0x00, 0x4E] (原始位元組) <--- 代表 78 bpm
└── 屬性 (Properties): [Read, Notify]
單看這些定義,可能會讓人感到眼花撩亂,想要打退堂鼓,我們可以換個方式來了解GATT
你可以把 GATT 想像成是一份公開的「服務菜單」或「API 文件」。每個 BLE 裝置都會提供這樣一份菜單,上面清清楚楚地寫著每個菜色的「品名」與「點餐編號 (UUID)」:
「我能提供哪些服務 (Services)?」 (例如:品名是「心率服務」,點餐編號 UUID 是 0x180D
)
「每項服務底下有哪些特徵 (Characteristics)?」 (例如:「心率服務」底下有「心率測量值」這道菜,它的點餐編號 UUID 是 0x2A37
)
「這道菜可以怎麼『吃』?」(例如:「心率測量值」的屬性 (Properties) 是可以被讀取 (Read)
和訂閱通知 (Notify)
)
試想一下,今天當你到了一間陌生的餐廳在位子上坐好之後,通常你的第一個動作會是甚麼,我想大多人的做的第一件事不外乎就是拿起桌上的菜單或是看看店內牆上有沒有價目表之類的告示,同樣的場景也能應用在我們的裝置上。
當我們的手機(或瀏覽器)連上 BLE 裝置時,第一件事就是去讀取這份 GATT 菜單。讀懂了菜單,我們就知道如何與這個裝置互動,從而實現前面提到的那些智慧應用。
好的,今天的內容就先到這邊了,本來今天想一股作氣得將架設虛擬 BLE 裝置的部分也寫完,但是為了能夠簡單的理解GATT基礎概念,花了比想像中還多的篇幅,於是我決定把實作部分移到明天再來進行。
文章的最後,感謝能看到這裡你,在這邊祝你早安、午安、晚安,我們明天見。