一、蓝牙简介
蓝牙是一种无线通讯技术,可实现固定设备、移动设备之间的数据交换。一般将蓝牙3.0之间的BR/EDR蓝牙称为传统蓝牙,而将蓝牙4.0规范下的LE蓝牙称为低功耗蓝牙。目前,蓝牙技术已经应用到各个领域,并已经成为接入物联网的主要技术。如今,借助于ESP32平台,MicroPython中也能够使用蓝牙BLE协议进行通信。这对MicroPython平台而言,自然丰富了其生态,增强了其技能,反过来讲,蓝牙BLE能够在MicroPython中得以集成,借助Python语言的易用性,亦将大大降低其入门门槛。
二、miropython有关蓝牙的实现方法
在miropython官网中,提供蓝牙接口模块为bluetooth,下面简单介绍一下本次实验用到的一些方法。
网址:http://docs.micropython.org/en/v1.18/library/bluetooth.html
1)BLE.active([active, ]/)
可选地更改BLE无线电的活动状态,并返回当前状态。在此类上使用任何其他方法之前,必须使无线电处于活动状态。
2)BLE.config(*, param=value, ...)
获取或设置 BLE 接口的配置值。要获取一个值,参数名称应该作为字符串引用,并且一次只查询一个参数。要设置值,请使用关键字语法,一次可以设置一个或多个参数。
3)BLE.irq(handler, /)
为来自 BLE 堆栈的事件注册回调。如下官方给出的事件处理程序(部分截图):
4)BLE.gap_advertise(interval_us, adv_data=Non,*,resp_data=None,...)
以指定的时间间隔(以微秒为单位)开始广播。此间隔将向下舍入到最接近的 625us。要停止广播,请将interval_us设置为None。
adv_data和resp_data可以是实现缓冲协议的任何类型(例如bytes, bytearray, str)。adv_data包含在所有广播中,resp_data发送以回复主动扫描。
注意:如果adv_data(或resp_data)是None,那么传递给先前调用的数据gap_advertise将被重新使用。这允许广播公司仅使用gap_advertise(interval_us). 要清除广告有效载荷,请传递一个空的bytes,即b''。
5)BLE.gatts_register_services(services_definition, /)
用指定的服务配置服务器,替换任何现有的服务。services_definition是一个服务列表,其中每个服务是一个包含一个UUID和一个特征列表的双元素元组。每个特征都是两个或三个元素的元组,包含一个UUID、一个标志值和可选的描述符列表。每个描述符都是一个包含UUID和标志值的双元素元组。这些标志是下面定义的标志的位或组合。这些设置了特征(或描述符)的行为以及安全和隐私需求。返回值是一个元组列表(每个服务一个元素)(每个元素是一个值句柄)。按照定义的顺序,特征和描述符句柄被平展到同一个元组中。
以下官方示例注册了两个服务(Heart Rate, and Nordic UART):
HR_UUID = bluetooth.UUID(0x180D) HR_CHAR = (bluetooth.UUID(0x2A37), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) HR_SERVICE = (HR_UUID, (HR_CHAR,),) UART_UUID = bluetooth.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E') UART_TX = (bluetooth.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_READ | bluetooth.FLAG_NOTIFY,) UART_RX = (bluetooth.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E'), bluetooth.FLAG_WRITE,) UART_SERVICE = (UART_UUID, (UART_TX, UART_RX,),) SERVICES = (HR_SERVICE, UART_SERVICE,) ( (hr,), (tx, rx,), ) = bt.gatts_register_services(SERVICES)
6)BLE.gatts_read(value_handle, /)
读取此句柄(已由gatts_write或远程客户端写入)的本地值。
7)BLE.gatts_notify(conn_handle, value_handle, data=None, /)
向已连接的客户端发送通知请求。
如果data不是None,那么该值将作为通知的一部分发送给客户端。本地值不会被修改。否则,如果data为None,则将发送当前本地值(与gatts_write设置的一样)。注意:无论客户端对该特性的订阅状态如何,通知都将被发送。
8)bluetooth.UUID(value, /)
使用指定的值创建一个UUID实例。取值为:
16位整数,例如0 x2908
128位的UUID字符串,例如:'6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
三、我的实验代码
from machine import Pin from machine import Timer from time import sleep_ms import bluetooth BLE_MSG = "" class ESP32_BLE(): def __init__(self, name): self.led = Pin(22, Pin.OUT) self.timer1 = Timer(0) #创建定时器0对象 self.name = name self.ble = bluetooth.BLE() #创建蓝牙对象 self.ble.active(True) #启动蓝牙 self.ble.config(gap_name=name) #给蓝牙设置一个名字 self.disconnected() self.ble.irq(self.ble_irq) #蓝牙中断函数 self.register() self.advertiser() def connected(self): self.led.value(0) #点亮LED指示灯 self.timer1.deinit() #取消定时器 def disconnected(self): #100ms调用一次 mode循环计时 lambda匿名函数 self.timer1.init(period=100, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value())) def ble_irq(self, event, data): global BLE_MSG #替换外部的同名变量 if event == 1: #_IRQ_CENTRAL_CONNECT 手机链接了此设备 self.connected() elif event == 2: #_IRQ_CENTRAL_DISCONNECT 手机断开此设备 self.advertiser() #向外发送信号,广播 self.disconnected() elif event == 3: #_IRQ_GATTS_WRITE 手机发送了数据 buffer = self.ble.gatts_read(self.rx) BLE_MSG = buffer.decode('UTF-8').strip() def register(self): service_uuid = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E' reader_uuid = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E' sender_uuid = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E' #创建一个元组 services = ( ( bluetooth.UUID(service_uuid), #服务ID,可以定义多个服务 ( (bluetooth.UUID(sender_uuid), bluetooth.FLAG_NOTIFY), #服务具体类型 (bluetooth.UUID(reader_uuid), bluetooth.FLAG_WRITE), #服务具体类型 ) ), ) ((self.tx, self.rx,), ) = self.ble.gatts_register_services(services) def send(self, data): self.ble.gatts_notify(0, self.tx, data + '\n') def advertiser(self): name = bytes(self.name, 'UTF-8') adv_data = bytearray('\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name self.ble.gap_advertise(100, adv_data) #100us发布一次广告 print(adv_data) print("\r\n") def buttons_irq(pin): led.value(not led.value()) print('LED is ON.' if led.value() else 'LED is OFF') ble.send('LED is ON.' if led.value() else 'LED is OFF') if __name__ == "__main__": ble = ESP32_BLE("ESP32BLE") but = Pin(0, Pin.IN) but.irq(trigger=Pin.IRQ_FALLING, handler=buttons_irq) led = Pin(22, Pin.OUT) while True: if BLE_MSG == 'read_LED': led.value(not led.value()) print(BLE_MSG) BLE_MSG = "" print('LED is ON.' if led.value() else 'LED is OFF') ble.send('LED is ON.' if led.value() else 'LED is OFF') sleep_ms(100)
程序代码思路:蓝牙在未连接时,指示灯不断闪烁,当蓝牙被连接时,指示灯由闪烁变为常亮。当用户用手机APP发送“read_LED”时,指示灯翻转,并打印出接收到的消息。用户可通过手机APP设置提醒功能。ESP32可通过中断控制指示灯亮灭并提醒手机用户。
四、手机调试APP
IOS用户可下载LightBlue
安卓用户可下载BLE调试宝