ESP32使用MicroPython设置低功耗蓝牙广播,通过Chrome Web蓝牙通信

NO.1
前置准备

电脑端Chrome浏览器在地址栏打开以下网址,修改配置

chrome://flags/

把以下4个属性开启

找不到的话可以在顶部搜索栏搜索关键字

Experimental Web Platform features

Bluetooth

此图片的alt属性为空;文件名为image-105-1024x536.png

NO.2
Web Bluetooth

Web Bluetooth文档

https://developer.mozilla.org/zh-CN/docs/Web/API/Bluetooth

注意以下几点:

  1. chrome版本需要>=53

  2. 需要部署到HTTPS的网页进行测试和使用

  3. 需要用户手势出发,也就是真实的鼠标点击之类的操作,才能出发蓝牙扫描和连接

体验网站Demo效果,需要对应的ESP32代码

https://bluetooth.dsx2020.com/

效果如图

ESP32会收到对应的测试字符串

此图片的alt属性为空;文件名为image-107-1024x556.png

网页代码

那其中的service_uuid和receive_uuid换成你自己的蓝牙广告ID就可以了

如果不确定,就继续参考ESP32蓝牙广播对应的代码

<html lang="en">
    <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>BL</title>
    </head>
    <body>
        <!-- 只有通过真实点击才能连接蓝牙 -->
        <div onclick="blList()">blue</div>
    </body>
    <script>
        // let uuid=
        // 定义连接蓝牙方法
        async function blList() {  
            navigator.bluetooth
                .requestDevice({
                    // 蓝牙名称前缀
                    filters: [{ name: "ESP32" }],
                    // 蓝牙uuid
                     optionalServices: ["ae25a5c1-4601-143c-12bb-8bc45a18749c"], 
                })
                .then(async (device) => {
                    console.log("Name: " + device.name, device);
                    // 连接设备
                    let server = await device.gatt.connect();
                    console.log(`server`, server);
                    // 获取蓝牙uuid相关内容
                    let service = await server.getPrimaryService("ae25a5c1-4601-143c-12bb-8bc45a18749c");
                    console.log(`service`, service);
                    // 获取可以读写字符流的服务
                    let characteristic = await service.getCharacteristic(
                        "ae25a5c2-4601-143c-12bb-8bc45a18749c"
                    );
                    // 写入字节(括号中的方法为把字符串转为字符流,传输给蓝牙)
                    characteristic.writeValue(
                        new Uint8Array(
                            new TextEncoder("utf-8").encode("str")
                        )
                    );
                    alert("已发送字符")
                })
                .catch(function (error) {
                    // 监听错误
                    console.log("Something went wrong. " + error);
                    alert(error)
                });
        }
        // blList();
</script>
</html>
NO.3
ESP32 Bluetooth

参考上一篇文章

MicroPython[ESP32]物联网开发-Bluetooth蓝牙通信-002

这里贴上完整的代码

# 引入依赖
import ubluetooth
# 实例化蓝牙
class BLE():
    def __init__(self, name):   
        # 蓝牙名称
        self.name = name
        # 创建蓝牙实例
        self.ble = ubluetooth.BLE()
        # 开启蓝牙
        self.ble.active(True)
        # 蓝牙事件回调
        # 参考文档
        # https://docs.micropython.org/en/latest/library/bluetooth.html?highlight=irq
        self.ble.irq(self.ble_irq)
        # 配置蓝牙UUID
        self.register()
        # 特征和描述符的默认最大大小为 20 个字节,修改允许为100个字节(蓝牙数据的发送和接收字节大小限制)
        self.ble.gatts_write(self.rx, bytes(100))
        # 蓝牙广播
        self.advertiser()
        print("已开启蓝牙广播")
        
    # 蓝牙连接成功后回调
    def connected(self):        
        print("connected")
    # 蓝牙断开连接后回调
    def disconnected(self):        
        print("disconnected")  

    # 蓝牙事件回调函数
    def ble_irq(self, event, data):
        #蓝牙已连接
        if event == 1:
            print("蓝牙已连接")
            # 连接后的执行函数
            self.connected()
        #蓝牙已断开连接
        elif event == 2:
            print("蓝牙已断开连接")
            # 断开连接后的执行函数
            self.advertiser()
            self.disconnected()
        #蓝牙已发送数据
        elif event == 3 :
            print("蓝牙已接收到数据")        
            # 读取二进制数据
            buffer = self.ble.gatts_read(self.rx)
            # 使用UTF-8格式把二进制数据转为字符串
            message = buffer.decode('UTF-8').strip()
            # 打印收到的字符数据
            print("message",message)    
            # 对指定的数据做处理并蓝牙返回数据        
            if message == 'test':
                print('test')
                ble.send('test')
            if message == 'str':
                print('str')
                ble.send('str')
    # 注册蓝牙UUID
    def register(self):        
        # 自定义UUID
        # 蓝牙服务UUID service_uuid(后续蓝牙建议连接会用到)
        NUS_UUID = 'AE25A5C1-4601-143C-12BB-8BC45A18749C'
        # 蓝牙接收特征UUId receive_uuid
        RX_UUID = 'AE25A5C2-4601-143C-12BB-8BC45A18749C'
        # 蓝牙发送特征UUId transmit_uuid
        TX_UUID = 'AE25A5C3-4601-143C-12BB-8BC45A18749C'
        # UUID组合(一个包含UUID和特征列表的二元元组)
        BLE_NUS = ubluetooth.UUID(NUS_UUID)
        BLE_RX = (ubluetooth.UUID(RX_UUID), ubluetooth.FLAG_WRITE)
        BLE_TX = (ubluetooth.UUID(TX_UUID), ubluetooth.FLAG_NOTIFY)
        BLE_UART = (BLE_NUS, (BLE_TX, BLE_RX,))
        SERVICES = (BLE_UART, )
        # 使用指定的服务配置外围设备
        # 文档地址:
        # https://docs.micropython.org/en/latest/library/bluetooth.html?highlight=irq#peripheral-role
        ((self.tx, self.rx,), ) = self.ble.gatts_register_services(SERVICES)
    # 发送数据
    def send(self, data):
        # 向连接的客户端发送通知请求
        # 文档地址:
        # https://docs.micropython.org/en/latest/library/bluetooth.html?highlight=irq#gatt-client
        self.ble.gatts_notify(0, self.tx, data + '\n')
    # 蓝牙广播配置
    def advertiser(self):
        name = bytes(self.name, 'UTF-8')
        # 以指定的时间间隔(以微秒为单位)开始广播
        # 文档地址
        # https://docs.micropython.org/en/latest/library/bluetooth.html?highlight=irq#broadcaster-role-advertiser
        self.ble.gap_advertise(100, bytearray('\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name)
        
# 创建一个名为ESP32的蓝牙广播
ble = BLE("ESP32")
NO.4
Tips

目前Web Bluetooth只支持安卓和Windows上的Chrome浏览器

不支持MacOS和Iphone上Chrome浏览器

使用安卓手机Chrome浏览器同样可以测试网页蓝牙通信,但是也要设置前置权限

手机权限

  1. 在系统设置中打开蓝牙

  2. 应用设置中允许开启或者关闭蓝牙

  3. 允许桌面快捷方式

  4. 允许锁屏显示

  5. 允许后台弹出界面

  6. 允许常驻通知

  7. 允许读写手机存储

因为网页蓝牙扫描和配对时,会以弹框的形式展示,所以需要一些显示和通知的应用权限,确保能展示蓝牙提示弹框

相比APP和微信小程序的蓝牙开发和调试,显然网页相对方便一些

可以用来测试简单的字符通信,测试蓝牙广播是否被正常扫描,以及特定字符的发送和接收逻辑处理等

本文的网页蓝牙UUID默认是固定的,后期有时间再改为动态输入

END.