返回文章列表

藍牙低功耗(BLE)技術 GATT 協定與 Python 實戰

本文探討藍牙低功耗 (BLE) 技術,特別著重於通用屬性組態檔案 (GATT) 的核心概念及其實際應用。文章首先介紹 BLE 與經典藍牙的差異,接著說明 GATT 的基本概念,包括特徵、屬性、描述器以及它們之間的層級結構。同時,文章也提供 Python 程式碼範例,示範如何掃描 BLE 裝置、Beacon

物聯網 嵌入式系統

藍牙低功耗(BLE)技術因其低功耗特性,已成為物聯網應用不可或缺的一環。相較於傳統藍牙,BLE 具有更低的功耗和更快的連線速度,使其適用於各種資源受限的裝置。BLE 的核心概念圍繞著通用屬性組態檔案(GATT),GATT 定義了 BLE 裝置之間如何交換資料,並透過服務和特徵的層級結構來組織資料。理解 GATT 的運作方式對於開發 BLE 應用至關重要。在實際應用中,開發者會使用各種程式語言和工具來與 BLE 裝置互動,Python 正是其中一種常用的語言,其豐富的函式庫和易於使用的特性,讓開發者能夠快速上手 BLE 開發。透過 Python,可以輕鬆地掃描 BLE 裝置、讀取 GATT 資料以及與 BLE 裝置進行通訊。此外,安全性在 BLE 應用中也扮演著重要的角色,開發者需要考慮如何保護 BLE 裝置免受未經授權的存取和攻擊。

BLE - 藍牙低功耗技術

由於物聯網(IoT)產業興起,越來越多低功耗裝置需要透過藍牙進行短距離資料交換而不消耗太多電力;為此而設計出來的是BLT Low Energy (BLE). BLE 配合低功耗設計適合健身追蹤器、醫療裝置和感測器等小型物聯網裝置應用場景。

BLE 與經典藍牙差異

BLE 與經典藍牙最大差異是其針對低功耗設計及更簡化快速配對所設計出來;雖然兩者底層硬體架構相似但是由於不同設計目的所以有些差異化:

  1. ATT (屬性協定) : BLE 配合低功耗特性而增加了一項Attribute Protocol來管理各項屬性特性。
  2. SM (安全管理協定) : BLE 配合快速配對需求增加安全管理機制確保配對過程中的資料安全性。
  3. GATT (通用屬性組態檔案) : BLE 新增GATT來定義屬性服務等規則來提升快速啟動與資料交換效率
graph TD;
    A[ATTP] --> B[Attribute Protocol];
    C[SM] --> D[Security Manager];
    E[GATT] --> F[Generic Attribute Profile];
次段落標題:此圖示

圖示說明BLT Low Energy架構及其各個主要組成部分及其關係:

  • ATTP 是主要負責管理解決資料存取規則;
  • SM 負責確保安全機制;
  • GATT 是負責管理屬性服務;

內容解密:

ATTP (Attribute Protocol)

ATT 屬性協定是在BELT Low Energy中新增的一項特殊功能 , 他負責管理解決資料存取規則 , 比如當我們第一次將手機與BLT Low Energy耳機連線時 , ATTP會幫助我們建立一些必要的屬性值;

SM (Security Manager)

BELT Low Energy 配合快速配對需求而增加了一項Security Manager , 他負責確保安全機制;比如我們常見到BELT Low Energy裝置有短暫間隔時間後自動斷開連線就是為了減少駭客破解攻擊時間.

GATT (Generic Attribute Profile)

GATT 主要目的是為了簡化BELT Low Energy裝置之間啟動連線與資料交換過程所建立的一套屬性規範規則; 比如常見紅外線體溫計每次測量完溫度後都會自動將資料推播到你手機裡就是利用GATT來完成這項工作. BLT Low Energy與經典藍牙相比有更高效且低延遲特點因此BLT Low Energy已經廣泛應用於智慧手錶或者IoT物聯網裝置以及醫療領域等場景

藍牙低功耗技術實戰與應用

藍牙低功耗技術(Bluetooth Low Energy, BLE)已成為現代物聯網(IoT)應用中的重要組成部分。本文將探討BLE技術的核心概念、實作步驟以及實務應用,並提供具體的程式碼範例,幫助讀者全面理解BLE技術的運作原理與實作細節。

BLE 技術概述

BLE是一種專為低功耗裝置設計的無線通訊協定,廣泛應用於可穿戴裝置、智慧家居和醫療裝置等領域。BLE通訊分為兩個主要角色:啟動器(Initiator)和伺服器(Responder)。啟動器負責發起連線,而伺服器則提供相應的服務。這些角色由通用存取組態檔案(Generic Access Profile, GAP)和通用屬性組態檔案(Generic Attribute Profile, GATT)來定義。

BLE 協定層級

BLE協定堆積疊結構如下圖所示:

graph TD;
    A[應用層] --> B[GATT/GAP];
    B --> C[L2CAP];
    C --> D[HCI];
    D --> E[RF層];

此圖示展示了BLE協定從應用層到RF層的完整結構。每一層都有其特定的功能和責任,確保資料能夠安全且高效地傳輸。

BLE 的安裝與環境組態

在開始BLE開發之前,需要先安裝必要的Python模組和依賴函式庫。以下是在Debian或Ubuntu系統上進行安裝的步驟:

sudo apt-get install libbluetooth-dev
sudo apt-get install libboost-dev libboost-thread libboost-python-dev
pip3 install PyBluez
pip3 install gattlib
pip3 install PyOBEX

這些命令分別安裝了藍牙開發函式庫、Boost函式庫以及Python模組。完成這些安裝後,就可以開始撰寫BLE相關的Python程式碼了。

藍牙經典裝置掃描

首先,我們來看看如何使用Python掃描周邊的藍牙經典裝置。以下是一個簡單的Python範例:

#!/usr/bin/env python3

import bluetooth as bt

for addr, name in bt.discover_devices(lookup_names=True):
    print(f"{addr} {name}")

內容解密:

這段程式碼使用了PyBluez函式庫來掃描周邊的藍牙裝置。discover_devices函式傳回一個包含硬體地址和裝置名稱的元組列表。引數lookup_names=True表示會尋找並顯示裝置名稱。如果不設定這個引數,則只會傳回裝置地址。

BLE 裝置掃描

接下來,我們來看看如何使用Python掃描BLE廣告包。BLE廣告包是小型資料包,每20毫秒到10.24秒傳送一次,預設不超過31位元組。廣告包包含傳送裝置的資訊以及它是否可連線等細節。

以下是一個掃描BLE廣告包的Python範例:

#!/usr/bin/env python3

from bluetooth.ble import DiscoveryService

service = DiscoveryService()
devices = service.discover(2)

for addr, name in devices.items():
    print(f"Found {name} ({addr})")

內容解密:

這段程式碼使用了DiscoveryService類別來掃描BLE廣告包。discover方法接受一個超時引數(以秒為單位),傳回一個包含BLE裝置地址和名稱的字典。程式碼會遍歷這個字典並列印預出每個發現的裝置。

GAP 與 GATT 組態檔案

GAP定義了BLE通訊中的角色,包括外圍裝置、中央裝置、廣播裝置和觀察者等。外圍裝置會傳送廣告包並可被連線,而中央裝置則會掃描並連線到外圍裝置。

以下是一個掃描周邊Beacon裝置並顯示其資料的Python範例:

#!/usr/bin/env python3

from bluetooth.ble import BeaconService

service = BeaconService()
devices = service.scan(10)

for addr, data in devices.items():
    print(f"{addr} (UUID {data[0]} Major {data[1]} Minor {data[2]} Power {data[3]} RSSI {data[4]})")

內容解密:

這段程式碼使用了BeaconService類別來掃描周邊Beacon裝置。scan方法接受一個超時引數(以秒為單位),傳回一個包含Beacon地址和資料的字典。程式碼會遍歷這個字典並列印預出每個Beacon裝置的UUID、Major、Minor、Power和RSSI等資訊。

GATT則定義瞭如何組織和傳輸資料,包括服務、特徵和特性值等概念。這些概念使得BLE裝置能夠高效地傳輸資料並進行互動。

安全性考量

由於許多BLE裝置缺乏足夠的計算能力來進行加密,因此通常會使用硬編碼PIN或隨機生成PIN來進行配對。此外,許多BLE裝置還支援鑰匙儲存(bonding),這意味著配對過的裝置會儲存鑰匙以供後續通訊使用。

加密與PIN配對

大多數BLE裝置為簡化使用過程,選擇硬編碼PIN如「0000」或「1234」,而非預期能夠輸入PIN以完成配對流程,當遇到需要輸入PIN進行配對需求時,可能會預期產生隨機PIN進行配對。 此外,Ble也提供專門設計可生成隨機PIN提供更高安全性之選項。

鑰匙儲存與持續連線

Ble技術也提供鑰匙儲存功能( bonding )其目的是讓已經配對過之Ble裝置可在後續連線時自動使用儲存之鑰匙重新建立安全連線且避免重複輸入PIN進行手動重新配對。 一些應用場景如智慧家庭環境中之多處BLe裝置互聯之間即會普遍需求此功能。

Bluetooth 低功耗(BLE)與 GATT 協定概述

Bluetooth 低功耗(BLE)技術已成為物聯網(IoT)中的重要組成部分,其高效能及低功耗特性使其在各種應用場景中大放異彩。在 BLE 中,通訊協定的核心之一是通用屬性組態檔案(Generic Attribute Profile,GATT)。GATT 為 BLE 裝置提供了一個標準化的方式來交換資料,並且可以應用於各種不同的服務和特徵。本文將探討 GATT 的基本概念及其實際應用。

GATT 的基本概念

GATT 建立在屬性通訊協定(Attribute Protocol, ATT)之上,主要用於讀取和寫入值,但它實作這些操作的方式是透過一個服務和特徵的層級結構。GATT 不僅能夠讀寫資料,還能傳送命令、通知及指示。通知和指示包裝是用來告知新資料或更新資料的。

特徵與屬性

在 GATT 中,特徵是一個包含屬性定義(資料)的清單,並且選擇性地包含描述器以描述這些特徵。每個屬性都有一個值及其相關的元資料來描述它。這些元資料包括:

  • Handle:唯一識別伺服器上的屬性(16 位元 ID)。
  • Type:指定屬性代表的內容(16、32 或 128 位元 UUID,其意義如表 9.1所示)。
  • Permissions:讀取或寫入該屬性的許可權。

特徵的層級結構

GATT 的特徵與屬性之間存在著複雜的層級結構。這些結構包含了服務、特徵、描述器和資料,而它們全都是屬性。此圖示展示了這些結構的概覽。

@startuml
skinparam defaultFontName "Microsoft JhengHei"
skinparam backgroundColor #FEFEFE
skinparam componentStyle rectangle

title GATT 服務與特徵層級結構

package "GATT 架構" {
    rectangle "Profile\n(配置文件)" as profile {
        rectangle "Service 1\n(主要服務)" as service1 {
            rectangle "Characteristic A\n(特徵)" as char1 {
                [Value\n(值)] as value1
                [Descriptor 1\n(描述符)] as desc1
                [Descriptor 2\n(描述符)] as desc2
            }

            rectangle "Characteristic B\n(特徵)" as char2 {
                [Value\n(值)] as value2
                [Descriptor\n(描述符)] as desc3
            }
        }

        rectangle "Service 2\n(次要服務)" as service2 {
            rectangle "Characteristic C\n(特徵)" as char3 {
                [Value\n(值)] as value3
            }
        }
    }
}

component "屬性定義" as attr {
    [Handle\n(句柄)] as handle
    [UUID\n(類型)] as uuid
    [Permissions\n(權限)] as perm
}

actor "BLE 中央設備\n(手機/電腦)" as central
actor "BLE 外圍設備\n(感測器)" as peripheral

central --> profile : 連接
profile --> service1 : 發現服務
service1 --> char1 : 讀取特徵
char1 --> value1 : 獲取數據
value1 ..> attr : 屬性定義

peripheral ..> service2 : 提供服務

note right of attr
  每個屬性都有:
  - Handle: 16位ID
  - UUID: 類型標識
  - Permissions: 訪問權限
end note

note left of char1
  特徵包含:
  - 值(Value)
  - 描述符(Descriptor)
  - 屬性(Properties)
end note

note bottom of service1
  服務是特徵的容器
  用於組織相關功能
end note

@enduml

此圖示展示了服務如何包含特徵,特徵又如何包含描述器和資料。每個部分都由屬性定義來描述。

GATT UUID 在廣告包中的應用

在廣告包中,GATT UUID 用於識別服務,這些 UUID 長度為 16 位元,因為空間有限無法使用 32 或 128 位元 UUID。所有這些 16 位元 ID 都是由 Bluetooth SIG 指派的,稱為公開 GAT 服務。以下是一些常見的 GATT 型態 UUID:

| UUID | 說明 | |



|





| | 0x2800 | 主要服務 | | 0x2801 | 次要服務 | | 0x2802 | 包含 | | 0x2803 | 特徵宣告 | | 0x2900 | 特徵擴充套件屬性 |

編寫 Python 工具來列出 BLE 裝置的 GATT 服務

接下來,我們將編寫一個小型 Python 工具來列出 BLE 裝置所提供的所有主要 GATT 服務。這個工具將使用 gattlib 模組中的 GATTRequester 類別。

#!/usr/bin/env python3

from gattlib import GATTRequester
import sys

if len(sys.argv) < 2:
    print("Usage: " + sys.argv[0] + " <addr>")
    sys.exit(0)

req = GATTRequester(sys.argv[1], True)

for service in req.discover_primary():
    print(service)

內容解密:

此段程式碼使用了 gattlib 模組中的 GATTRequester 類別。該類別的建構函式需要兩個引數:第一個是要連線的藍牙地址,第二個布林值表示是否自動連線到該裝置。

程式碼首先檢查命令列引數是否提供了藍牙地址。如果沒有提供地址,則顯示使用方法並離開程式。

接著,建立了一個 GATTRequester 物件並傳入藍牙地址和自動連線標誌。然後呼叫 discover_primary() 函式來發現該裝置所提供的所有主要服務並列印出來。

常見的 GATT 型態 UUID 說明

以下是一些常見的 GATT 型態 UUID 與其說明:

| UUID | 說明 | |



|







| | 0x1800 | 泛用存取 | | 0x1801 | 泛用屬性 | | 0x1802 | 呼叫警告 | | 0x1803 | 連結丟失 | | 0x1804 | 輸送功率 | | … | … |

GATT 型態與實際應用

在實際應用中,GATT 型態可以用來表示各種裝置和服務。例如,當我們需要一個手機與智慧型手錶之間進行通訊時,我們可以使用「電池服務」和「心跳率服務」來進行資料交換。

電池服務範例

UUID: 0x180F
說明: 電池服務

此服務可以提供裝置電池狀態及充電情況等資訊。

其他相關技術:SDP-Browser

除了 GATT 外,還有一種稱為服務發現協定(Service Discovery Protocol, SDP)的技術,它可以用來查詢傳統藍牙裝置所提供的服務。SDP 在查詢時會傳回該服務所在的頻道、使用的協定、服務名稱及簡短描述等資訊。

SDP-Browser Python 編碼範例

以下是使用 Python 查詢 SDP 的範例程式碼:

#!/usr/bin/env python3

import bluetooth as bt
import sys

if len(sys.argv) < 2:
    print("Usage: " + sys.argv[0] + " <addr>")
    sys.exit(0)

內容解密:

此段程式碼首先匯入必要的模組並檢查命令列引數是否提供了藍牙地址。如果沒有提供地址,則顯示使用方法並離開程式。