micropython ble 低功耗蓝牙 配网 成熟方案

本文介绍了一个基于Micropython的BLEConfig库,用于简化蓝牙低功耗设备的配置过程,包括SSID、密码接收以及与微信小程序的配网。作者提到该库是原创作品,反映了对国内微控制器生态系统中原创资源匮乏的观察。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

首先自吹自擂一波,这个思路是开始是我想出来的,用在了我自己的VFD时钟上,后来传给伟大的walkline群主,群主是认真的人,认真的做了架构和小程序,大家想用就用
原仓库地址

懒人福音,新建ble_config.py

"""
Copyright © 2023 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/micropython_ble_config
被灵性的jd3096所启发而作(这句是我不要脸自己添加的)
"""
__version__ = '0.1.1'
__version_info__ = (0, 1, 1)
print('module ble_config version:', __version__)


import struct
import ubluetooth as bt
from micropython import const


IRQ_CENTRAL_CONNECT       = const(1)
IRQ_CENTRAL_DISCONNECT = const(2)
IRQ_GATTS_WRITE           = const(3)

AD_TYPE_FLAGS                         = const(0x01)
AD_TYPE_COMPLETE_LOCAL_NAME             = const(0x09)
AD_TYPE_16BIT_SERVICE_UUID_COMPLETE     = const(0x03)
AD_TYPE_32BIT_SERVICE_UUID_COMPLETE     = const(0x05)
AD_TYPE_128BIT_SERVICE_UUID_COMPLETE = const(0x07)
AD_TYPE_APPEARANCE                     = const(0x19)

UART_UUID  = bt.UUID('6E400001-B5A3-F393-E0A9-E50E24DCCA9E')
RX_UUID    = bt.UUID('6E400002-B5A3-F393-E0A9-E50E24DCCA9E')
TX_UUID    = bt.UUID('6E400003-B5A3-F393-E0A9-E50E24DCCA9E')
LOCAL_NAME = 'ble-config'

SSID_PREFIX        = b'ssid_'
PASSWORD_PREFIX    = b'pswd_'


class BLEConfig(object):
    def __init__(self, rx_received_cb=None):
        self.__ble = bt.BLE()
        self.__rx_received_cb = rx_received_cb
        self.__conn_handle = None

        self.ssid = ''
        self.password = ''

        self.__ble.active(False)
        self.__ble.active(True)
        print('ble activated')

        self.__ble.config(gap_name=LOCAL_NAME)
        self.__ble.irq(self.__irq)

        self.__adv_payload = self.__advertising_payload(services=(UART_UUID,))
        self.__resp_payload = self.__advertising_payload(name=LOCAL_NAME)

        self.__register_services()
        self.__advertise()

    def __register_services(self):
        UART_SERVICE = (
            UART_UUID, 
            (
                (TX_UUID, bt.FLAG_NOTIFY,),
                (RX_UUID, bt.FLAG_WRITE,),
            ),
        )

        (
            (
                self.__tx_handle,
                self.__rx_handle,
            ),
        ) = self.__ble.gatts_register_services((UART_SERVICE,))

    def __advertise(self, interval_us=500000):
        self.__ble.gap_advertise(None)
        self.__ble.gap_advertise(interval_us, adv_data=self.__adv_payload, resp_data=self.__resp_payload)
        print('advertising...')

    def __irq(self, event, data):
        if event == IRQ_CENTRAL_CONNECT:
            self.__conn_handle, _, addr, = data
            print(f'[{self.__decode_mac(addr)}] connected, handle: {self.__conn_handle}')

            self.__ble.gap_advertise(None)
        elif event == IRQ_CENTRAL_DISCONNECT:
            self.__conn_handle, _, addr, = data
            print(f'[{self.__decode_mac(addr)}] disconnected, handle: {self.__conn_handle}')

            self.__conn_handle = None

            if not self.success():
                self.__advertise()
        elif event == IRQ_GATTS_WRITE:
            conn_handle, value_handle = data

            if conn_handle == self.__conn_handle and value_handle == self.__rx_handle:
                data = bytes(self.__ble.gatts_read(self.__rx_handle))

                if data.startswith(SSID_PREFIX):
                    self.ssid = data[len(SSID_PREFIX):].decode('utf-8')
                elif data.startswith(PASSWORD_PREFIX):
                    self.password = data[len(PASSWORD_PREFIX):].decode('utf-8')

                if self.__rx_received_cb:
                    self.__rx_received_cb(data)

    def __decode_mac(self, addr):
        if isinstance(addr, memoryview):
            addr = bytes(addr)

        assert isinstance(addr, bytes) and len(addr) == 6, ValueError('mac address value error')
        return ':'.join(['%02X' % byte for byte in addr])

    # https://github.com/micropython/micropython/blob/master/examples/bluetooth/ble_advertising.py#L24
    def __advertising_payload(limited_disc=False, br_edr=False, name=None, services=None):
        payload = bytearray()

        def _append(adv_type, value):
            nonlocal payload
            payload += struct.pack('BB', len(value) + 1, adv_type) + value

        _append(
            AD_TYPE_FLAGS,
            struct.pack('B', (0x01 if limited_disc else 0x02) + (0x18 if br_edr else 0x04))
        )

        if name:
            _append(AD_TYPE_COMPLETE_LOCAL_NAME, name)

        if services:
            for uuid in services:
                b = bytes(uuid)
                if len(b) == 2:
                    _append(AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, b)
                elif len(b) == 4:
                    _append(AD_TYPE_32BIT_SERVICE_UUID_COMPLETE, b)
                elif len(b) == 16:
                    _append(AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, b)

        return payload

    def success(self) -> bool:
        return len(self.ssid) > 0 and len(self.password) > 0


if __name__ == '__main__':
    import time

    def rx_received_cb(data):
        print(f'received rx data: {data}')

    bleconfig = BLEConfig(rx_received_cb)

    while not bleconfig.success():
        time.sleep(0.5)

    print(f'ssid: {bleconfig.ssid}, password: {bleconfig.password}')

"""
    import ubluetooth as bt
    import ble_config

    ble_config.UART_UUID  = bt.UUID(...)
    ble_config.RX_UUID    = bt.UUID(...)
    ble_config.TX_UUID    = bt.UUID(...)
    ble_config.LOCAL_NAME = ...

    bleconfig = ble_config.BLEConfig()
"""


用的时候扫这个二维码微信小程序配网就行了
在这里插入图片描述
壮大我mpy!
再次吐槽micropython生态真的难,国内不是伸手就是抄,原创的东西太少了,就剩我们几个老家伙偶尔干点正事。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值