ubluepy --- Bluetooth LE peripheral และ central

โมดูล ubluepy คือ API Bluetooth LE รุ่นเก่าที่จัดส่งมากับ MicroPython nRF port โดยมีแบบจำลองคร่าวๆ จากไลบรารี Python bluepy ของ Linux และทำงานโดยตรงบน Nordic SoftDevice --- ไม่มี back-end แบบพกพา ดังนั้นโมดูลนี้จึงใช้ได้เฉพาะบน Nordic targets (Arduino Nano 33 BLE Sense ในกลุ่มผลิตภัณฑ์ของ OpenMV) API bluetooth / aioble รุ่นใหม่กว่า ไม่ได้ เปิดใช้งานในบิลด์นี้ ดังนั้น ubluepy จึงเป็นวิธีเดียวในการขับเคลื่อนวิทยุในชิป

ชุดคุณสมบัติที่ใช้งานได้ขึ้นอยู่กับ SoftDevice ที่แฟลชโดย firmware:

  • s140 (Nano 33 BLE Sense) --- ทั้งบทบาท peripheral และ central (scanner) นี่คือสิ่งที่ OpenMV firmware จัดส่ง

  • s132 --- ทั้ง peripheral และ central

  • s110 --- เฉพาะ peripheral เท่านั้น โดย scanner / connect method ถูกคอมไพล์ออก

ตัวอย่าง Peripheral

โฆษณาในฐานะ Bluetooth LE peripheral พร้อมบริการ environmental sensing เดียวและแจ้งเตือน temperature characteristic ในทุกการเขียนไปยัง Client Characteristic Configuration Descriptor (CCCD):

from ubluepy import Service, Characteristic, UUID, Peripheral, constants
from machine import LED

notif_enabled = False

def event_handler(event_id, handle, data):
    global notif_enabled
    if event_id == constants.EVT_GAP_CONNECTED:
        LED("LED_GREEN").on()
    elif event_id == constants.EVT_GAP_DISCONNECTED:
        LED("LED_GREEN").off()
        periph.advertise(device_name="Nano 33", services=[svc])
    elif event_id == constants.EVT_GATTS_WRITE:
        notif_enabled = bool(data[0])

svc = Service(UUID("181A"))            # Environmental Sensing
char = Characteristic(UUID("2A6E"),
                      props=Characteristic.PROP_NOTIFY | Characteristic.PROP_READ,
                      attrs=Characteristic.ATTR_CCCD)
svc.addCharacteristic(char)

periph = Peripheral()
periph.addService(svc)
periph.setConnectionHandler(event_handler)
periph.advertise(device_name="Nano 33", services=[svc])

ตัวอย่าง Central

สแกนหาอุปกรณ์โฆษณาที่อยู่ใกล้เคียงเป็นเวลา 100 ms และถอดรหัสข้อมูลโฆษณาของ ScanEntry แต่ละรายการ:

from ubluepy import Scanner, constants

s = Scanner()
for entry in s.scan(100):
    print(entry.addr(), entry.rssi(), "dBm")
    for ad_type, name, value in entry.getScanData():
        print(" ", ad_type, name, bytes(value))

เนื้อหาของโมดูล

คลาส

class ubluepy.UUID(value)

สร้าง Bluetooth UUID ขนาด 16 บิตหรือ 128 บิต

value

หนึ่งในรายการต่อไปนี้:

  • int --- UUID ตัวเลข 16 บิต (UUID(0x180A))

  • สตริง "0xXXXX" 6 ตัวอักษร --- UUID 16 บิต เช่น UUID("0x181A")

  • สตริง "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx" 36 ตัวอักษร --- UUID 128 บิตแบบเต็ม โดยส่วนที่เฉพาะเจาะจงของ vendor จะถูกลงทะเบียนกับ SoftDevice เมื่อสร้าง

  • อินสแตนซ์ UUID อื่น --- ทำการคัดลอก

ความยาวอื่นๆ จะ raise ValueError("Invalid UUID string length")

binVal() int

คืนค่า 16 บิตต่ำของ UUID เป็น int สำหรับ UUID 128 บิต จะคืนค่าเฉพาะฟิลด์ 16 บิตที่ฝังอยู่ภายใน vendor-specific UUID (ค่า 128 บิตแบบเต็มสามารถเข้าถึงได้เฉพาะผ่าน vendor-specific index ของ SoftDevice)

class ubluepy.Service(uuid: UUID, type: int = Service.PRIMARY)

กำหนดบริการ GATT ที่จะลงทะเบียนกับ SoftDevice เมื่อเพิ่มไปยัง Peripheral

uuid

อินสแตนซ์ UUID การส่งออบเจ็กต์ที่ไม่ใช่ UUID จะ raise ValueError

type

เป็น Service.PRIMARY (ค่าเริ่มต้น) หรือ Service.SECONDARY ค่าอื่นๆ จะ raise ValueError

uuid() UUID

คืนค่าอินสแตนซ์ UUID ของบริการ

addCharacteristic(characteristic: Characteristic) None

ลงทะเบียน Characteristic กับบริการ โดย GATT handle ของ characteristic จะถูกกำหนดระหว่างการเรียกนี้

getCharacteristic(uuid: UUID) Characteristic | None

ค้นหา Characteristic ที่เพิ่มไว้ก่อนหน้านี้ด้วย UUID คืนค่าอินสแตนซ์ characteristic หรือ None หากไม่พบรายการที่ตรงกัน

getCharacteristics() list

คืนค่ารายการ characteristic ทั้งหมดที่เพิ่มไปยังบริการ

PRIMARY: int

ค่าคงที่ประเภทบริการสำหรับ primary service (1)

SECONDARY: int

ค่าคงที่ประเภทบริการสำหรับ secondary service (2)

class ubluepy.Characteristic(uuid: UUID, *, props: int = PROP_READ | PROP_WRITE, attrs: int = 0)

กำหนด GATT characteristic โดยเพิ่มไปยัง Service ด้วย Service.addCharacteristic() ก่อนที่ Peripheral พาเรนต์จะเริ่มโฆษณา

uuid

อินสแตนซ์ UUID

props (keyword-only)

Bitmask ของค่า Characteristic.PROP_* หนึ่งรายการหรือมากกว่าที่อธิบายว่า characteristic รองรับการดำเนินการใดบ้าง

attrs (keyword-only)

Bitmask ของ GATT attribute เพิ่มเติม ใช้ Characteristic.ATTR_CCCD เพื่อแนบ Client Characteristic Configuration Descriptor --- จำเป็นสำหรับการทำให้ characteristic PROP_NOTIFY / PROP_INDICATE ทำงาน

uuid() UUID

คืนค่าอินสแตนซ์ UUID ของ characteristic

properties() int

คืนค่า bitmask props ที่กำหนดไว้เมื่อสร้าง

read() bytearray

เฉพาะบทบาท Central เท่านั้น อ่านค่าของ characteristic จาก peer ที่เชื่อมต่อ คืนค่า bytearray พร้อมค่าล่าสุด บน peripheral นี้เป็น no-op และคืนค่า None

write(data, *, with_response: bool = False) None

เขียนค่าไปยัง characteristic

  • บน peripheral หาก PROP_NOTIFY ถูกตั้งค่าใน properties ของ characteristic ค่าจะถูกส่งเป็น GATT notification ไปยัง central ที่เชื่อมต่อ มิฉะนั้นค่า attribute ในเครื่องจะถูกอัปเดต

  • บน central ค่าจะถูกเขียนไปยัง peer ระยะไกล ตั้งค่า with_response=True เพื่อออก write request และรอการยืนยันจาก peer แทนที่จะเป็น write command

data คือออบเจ็กต์ buffer-protocol ใดๆ (bytes, bytearray, memoryview)

PROP_BROADCAST: int

Characteristic สามารถกระจายค่าของตน (0x01)

PROP_READ: int

Characteristic รองรับการอ่าน (0x02)

PROP_WRITE_WO_RESP: int

Characteristic รองรับการเขียนโดยไม่มีการตอบสนอง (0x04)

PROP_WRITE: int

Characteristic รองรับการเขียนพร้อมการตอบสนอง (0x08)

PROP_NOTIFY: int

Characteristic สามารถส่ง notification ไปยัง central ที่สมัครรับข้อมูล (0x10)

PROP_INDICATE: int

Characteristic สามารถส่ง indication (notification ที่ยืนยัน) ไปยัง central ที่สมัครรับข้อมูล (0x20)

PROP_AUTH_SIGNED_WR: int

Characteristic รองรับ authenticated signed write (0x40)

ATTR_CCCD: int

เพิ่ม Client Characteristic Configuration Descriptor ไปยัง characteristic (0x01) จำเป็นสำหรับ client ในการสมัครรับ notification/indication

class ubluepy.Descriptor(uuid: UUID)

คลาส stub สำหรับแสดง GATT descriptor การนำไปใช้งานปัจจุบันเก็บเฉพาะ UUID และไม่เปิดเผย method ใดๆ --- มีไว้เพื่อความเข้ากันได้ในอนาคตกับการแก้ไขโมดูลในอนาคต

class ubluepy.Peripheral

อุปกรณ์ Bluetooth LE ในเครื่อง คลาสเดียวกันนี้ใช้สำหรับทั้งบทบาท peripheral และ central โดยบทบาทจะถูกเลือกตามวิธีการที่คุณเรียก (advertise() เลือก peripheral, connect() เลือก central)

addService(service: Service) None

ลงทะเบียน Service (และ characteristic ที่เพิ่มไว้ก่อนหน้าทั้งหมด) กับ GATT server ในเครื่อง

getServices() list

คืนค่ารายการบริการที่ลงทะเบียนกับ Peripheral นี้ในปัจจุบัน

advertise(*, device_name: str | None = None, services: list | None = None, data: bytes | None = None, connectable: bool = True) None

เริ่มโฆษณาในบทบาท peripheral

device_name

ชื่อในเครื่องแบบสมบูรณ์ที่โฆษณาใน GAP payload

services

รายการของอินสแตนซ์ Service ที่จะโฆษณา UUID ของแต่ละบริการจะถูกรวมในโฆษณา

data

raw advertisement payload ที่ไม่บังคับ (bytes / bytearray) ที่ต่อท้าย header ที่สร้างอัตโนมัติ ใช้สำหรับ payload เฉพาะ vendor หรือ beacon เช่น Eddystone

connectable

เมื่อเป็น True (ค่าเริ่มต้น) โฆษณาเป็นอุปกรณ์ที่เชื่อมต่อได้และลงทะเบียน GAP / GATTS event handler เพื่อให้ callback setConnectionHandler() ที่กำหนดค่าไว้ทำงานเมื่อเชื่อมต่อ ตัดการเชื่อมต่อ และ CCCD write เมื่อเป็น False โฆษณาเป็น beacon --- ไม่มี handler แนบอยู่และอุปกรณ์ไม่สามารถเชื่อมต่อได้

advertise_stop() None

หยุดการโฆษณาที่กำลังดำเนินอยู่

setConnectionHandler(func) None

ลงทะเบียน callback ที่ถูกเรียกใช้กับ GAP และ GATTS event โดย callback จะถูกเรียกในรูปแบบ func(event_id, conn_handle, data) โดย event_id เป็นหนึ่งในค่า constants.EVT_GAP_CONNECTED, constants.EVT_GAP_DISCONNECTED หรือ constants.EVT_GATTS_WRITE, conn_handle คือ SoftDevice connection handle (หรือ attribute handle สำหรับ GATTS write) และ data คือ raw event payload เป็น bytearray (หรือ None สำหรับ connect / disconnect)

setNotificationHandler(func) None

ลงทะเบียน callback สำหรับ notification event ที่ได้รับในบทบาท central

withDelegate(delegate: DefaultDelegate) None

แนบอินสแตนซ์ DefaultDelegate เพื่อรับ GATT event ที่ถอดรหัสแล้ว

disconnect() None

ยกเลิกการเชื่อมต่อที่ใช้งานอยู่ (ปัจจุบันเป็น no-op stub ในบิลด์นี้)

connect(addr, *, addr_type: int = constants.ADDR_TYPE_PUBLIC) None

เฉพาะบทบาท Central เท่านั้น เชื่อมต่อกับ peer ที่มีที่อยู่ที่กำหนดและค้นพบ primary service และ characteristic ของมันแบบ synchronous บล็อกจนกว่าการเชื่อมต่อจะสร้างขึ้นและการค้นพบเสร็จสมบูรณ์ โดยบริการที่ค้นพบจะใช้ได้ผ่าน getServices()

addr

ที่อยู่ peer เป็นสตริง "xx:xx:xx:xx:xx:xx" 17 ตัวอักษร (เช่น ที่นำมาจาก ScanEntry.addr())

addr_type (keyword-only)

เป็น constants.ADDR_TYPE_PUBLIC (ค่าเริ่มต้น) หรือ constants.ADDR_TYPE_RANDOM_STATIC

class ubluepy.Scanner

GAP observer สำหรับค้นพบอุปกรณ์โฆษณาที่อยู่ใกล้เคียง ใช้ได้เฉพาะเมื่อ firmware สร้างกับ SoftDevice ที่มีการรองรับ central (s132 / s140)

scan(timeout: int) list

รันการสแกนแบบ passive เป็นเวลา timeout มิลลิวินาทีและคืนค่ารายการของอินสแตนซ์ ScanEntry --- หนึ่งรายการต่อรายงานโฆษณาที่ได้รับระหว่างช่วงเวลานั้น

class ubluepy.ScanEntry

รายงานโฆษณาเดียวที่จับได้โดย Scanner.scan() โดยอินสแตนซ์จะถูกส่งคืนจาก scanner --- ไม่มี constructor สาธารณะ

addr() str

คืนค่าที่อยู่ peer เป็นสตริง "xx:xx:xx:xx:xx:xx" 17 ตัวอักษร

addr_type() int

คืนค่าประเภทที่อยู่ peer (constants.ADDR_TYPE_PUBLIC หรือ constants.ADDR_TYPE_RANDOM_STATIC)

rssi() int

คืนค่าตัวบ่งชี้ความแรงสัญญาณเป็น dBm

getScanData() list

ถอดรหัส advertisement payload เป็นรายการของ tuple (ad_type, description, value) โดย ad_type คือ byte ประเภท AD แบบตัวเลข (ดู constants.ad_types), description คือชื่อของค่าคงที่ที่ตรงกันเป็นสตริง (หรือ None หากประเภทไม่รู้จัก) และ value คือ AD record body เป็น bytearray

class ubluepy.DefaultDelegate

คลาสพื้นฐานสำหรับออบเจ็กต์ที่ส่งไปยัง Peripheral.withDelegate() โดย subclass และ override handleConnection() / handleNotification() เพื่อตอบสนองต่อ GATT event

handleConnection() None

ถูกเรียกเมื่อเกิด GAP connect / disconnect event การนำไปใช้งานเริ่มต้นเป็นค่าว่าง

handleNotification() None

ถูกเรียกเมื่อได้รับ GATT notification ขาเข้า การนำไปใช้งานเริ่มต้นเป็นค่าว่าง

ค่าคงที่

attribute constants ของโมดูลเป็น namespace ที่ประกอบด้วยตัวระบุ GAP/GATT event, ค่าประเภทที่อยู่ และ namespace ย่อย ad_types

ubluepy.constants: type

คอนเทนเนอร์ที่เปิดเผยค่าคงที่ด้านล่าง

constants.EVT_GAP_CONNECTED: int

Peripheral connection handler event_id สำหรับ GAP connect (16)

constants.EVT_GAP_DISCONNECTED: int

Peripheral connection handler event_id สำหรับ GAP disconnect (17)

constants.EVT_GATTS_WRITE: int

Peripheral connection handler event_id สำหรับการเขียนไปยัง GATT attribute ในเครื่อง รวมถึงการเขียนไปยัง CCCD ที่เปิด/ปิด notification (80)

constants.UUID_CCCD: int

Bluetooth UUID มาตรฐานสำหรับ Client Characteristic Configuration Descriptor (0x2902)

constants.ADDR_TYPE_PUBLIC: int

Public Bluetooth Device Address (0)

constants.ADDR_TYPE_RANDOM_STATIC: int

Static random Bluetooth Device Address (1)

constants.ad_types: type

Namespace ของค่าคงที่ประเภท AD ของข้อมูลการโฆษณาจาก Bluetooth Core Specification Supplement โดยแต่ละชื่อแมปกับประเภท AD 1 byte ที่สอดคล้องกัน:

ชื่อ

ค่า

AD_TYPE_FLAGS

0x01

AD_TYPE_16BIT_SERVICE_UUID_MORE_AVAILABLE

0x02

AD_TYPE_16BIT_SERVICE_UUID_COMPLETE

0x03

AD_TYPE_32BIT_SERVICE_UUID_MORE_AVAILABLE

0x04

AD_TYPE_32BIT_SERVICE_UUID_COMPLETE

0x05

AD_TYPE_128BIT_SERVICE_UUID_MORE_AVAILABLE

0x06

AD_TYPE_128BIT_SERVICE_UUID_COMPLETE

0x07

AD_TYPE_SHORT_LOCAL_NAME

0x08

AD_TYPE_COMPLETE_LOCAL_NAME

0x09

AD_TYPE_TX_POWER_LEVEL

0x0A

AD_TYPE_CLASS_OF_DEVICE

0x0D

AD_TYPE_SIMPLE_PAIRING_HASH_C

0x0E

AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R

0x0F

AD_TYPE_SECURITY_MANAGER_TK_VALUE

0x10

AD_TYPE_SECURITY_MANAGER_OOB_FLAGS

0x11

AD_TYPE_SLAVE_CONNECTION_INTERVAL_RANGE

0x12

AD_TYPE_SOLICITED_SERVICE_UUIDS_16BIT

0x14

AD_TYPE_SOLICITED_SERVICE_UUIDS_128BIT

0x15

AD_TYPE_SERVICE_DATA

0x16

AD_TYPE_PUBLIC_TARGET_ADDRESS

0x17

AD_TYPE_RANDOM_TARGET_ADDRESS

0x18

AD_TYPE_APPEARANCE

0x19

AD_TYPE_ADVERTISING_INTERVAL

0x1A

AD_TYPE_LE_BLUETOOTH_DEVICE_ADDRESS

0x1B

AD_TYPE_LE_ROLE

0x1C

AD_TYPE_SIMPLE_PAIRING_HASH_C256

0x1D

AD_TYPE_SIMPLE_PAIRING_RANDOMIZER_R256

0x1E

AD_TYPE_SERVICE_DATA_32BIT_UUID

0x20

AD_TYPE_SERVICE_DATA_128BIT_UUID

0x21

AD_TYPE_URI

0x24

AD_TYPE_3D_INFORMATION_DATA

0x3D

AD_TYPE_MANUFACTURER_SPECIFIC_DATA

0xFF