1,编译环境搭建:基于MicroPython的ESP32环境搭建
2,代码直接复制
"""
The MIT License (MIT)
Copyright © 2020 Walkline Wang (https://walkline.wang)
Gitee: https://gitee.com/walkline/esp32-ble-uart
Original repo: https://github.com/micropython/micropython/blob/master/examples/bluetooth/ble_uart_peripheral.py
"""
import ubluetooth as bt
__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")
__UART_SERVICE = (
__UART_UUID,
(
(__TX_UUID, bt.FLAG_NOTIFY,),
(__RX_UUID, bt.FLAG_WRITE,),
),
)
class BLEUART:
def __init__(self, ble, rx_callback=None, name="mpy-uart", rxbuf=100):
self.__ble = ble
self.__rx_cb = rx_callback
self.__conn_handle = None
self.__write = self.__ble.gatts_write
self.__read = self.__ble.gatts_read
self.__notify = self.__ble.gatts_notify
self.__ble.active(False)
print("activating ble...")
self.__ble.active(True)
print("ble activated")
self.__ble.config(rxbuf=rxbuf)
self.__ble.irq(self.__irq)
self.__register_services()
self.__adv_payload = BLETools.advertising_generic_payload(
services=(__UART_UUID,),
appearance=BLEConst.Appearance.GENERIC_COMPUTER,
)
self.__resp_payload = BLETools.advertising_resp_payload(
name=name
)
self.__advertise()
def __register_services(self):
(
(
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 == BLEConst.IRQ.IRQ_CENTRAL_CONNECT:
self.__conn_handle, addr_type, addr, = data
print("[{}] connected, handle: {}".format(BLETools.decode_mac(addr), self.__conn_handle))
self.__ble.gap_advertise(None)
elif event == BLEConst.IRQ.IRQ_CENTRAL_DISCONNECT:
self.__conn_handle, _, addr, = data
print("[{}] disconnected, handle: {}".format(BLETools.decode_mac(addr), self.__conn_handle))
self.__conn_handle = None
self.__advertise()
elif event == BLEConst.IRQ.IRQ_GATTS_WRITE:
conn_handle, value_handle = data
if conn_handle == self.__conn_handle and value_handle == self.__rx_handle:
if self.__rx_cb:
self.__rx_cb(self.__read(self.__rx_handle))
def send(self, data):
"""
将数据写入本地缓存,并推送到中心设备
"""
self.__write(self.__tx_handle, data)
if self.__conn_handle is not None:
self.__notify(self.__conn_handle, self.__tx_handle, data)
#从tools.py中摘取。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
import struct
from ubluetooth import UUID
PACK = struct.pack
UNPACK = struct.unpack
class BLETools(object):
"""
Payload Generator Functions
"""
# Advertising payloads are repeated packets of the following form:
# 1 byte data length (N + 1)
# 1 byte type (see constants below)
# N bytes type-specific data
@staticmethod
def advertising_generic_payload(limited_disc=False, br_edr=False, name=None, services=None, appearance=0):
"""
Generate a payload to be passed to gap_advertise(adv_data=...).
"""
payload = bytearray()
def _append(adv_type, value):
nonlocal payload
payload += PACK('BB', len(value) + 1, adv_type) + value
_append(BLEConst.ADType.AD_TYPE_FLAGS, PACK('B', (0x01 if limited_disc else 0x02) + (0x00 if br_edr else 0x04)))
if name:
_append(BLEConst.ADType.AD_TYPE_COMPLETE_LOCAL_NAME, name)
if services:
for uuid in services:
b = bytes(uuid)
if len(b) == 2:
_append(BLEConst.ADType.AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, b)
elif len(b) == 4:
_append(BLEConst.ADType.AD_TYPE_32BIT_SERVICE_UUID_COMPLETE, b)
elif len(b) == 16:
_append(BLEConst.ADType.AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, b)
# See org.bluetooth.characteristic.gap.appearance.xml
_append(BLEConst.ADType.AD_TYPE_APPEARANCE, PACK(', appearance))
return payload
@staticmethod
def advertising_resp_payload(name=None, services=None):
"""
Generate payload for Scan Response
"""
payload = bytearray()
def _append(adv_type, value):
nonlocal payload
payload += PACK('BB', len(value) + 1, adv_type) + value
if name:
_append(BLEConst.ADType.AD_TYPE_COMPLETE_LOCAL_NAME, name)
if services:
for uuid in services:
b = bytes(uuid)
if len(b) == 2:
_append(BLEConst.ADType.AD_TYPE_16BIT_SERVICE_UUID_COMPLETE, b)
elif len(b) == 4:
_append(BLEConst.ADType.AD_TYPE_32BIT_SERVICE_UUID_COMPLETE, b)
elif len(b) == 16:
_append(BLEConst.ADType.AD_TYPE_128BIT_SERVICE_UUID_COMPLETE, b)
return payload
@staticmethod
def decode_mac(addr):
"""
Decode readable mac address from advertising 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])
#从const.py中摘取。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
from micropython import const
class BLEConst(object):
class IRQ(object):
IRQ_CENTRAL_CONNECT = const(1)
IRQ_CENTRAL_DISCONNECT = const(2)
IRQ_GATTS_WRITE = const(3)
class Appearance(object):
Unknown = const(0) # None
GENERIC_PHONE = const(64) # Generic category
GENERIC_COMPUTER = const(128) # Generic category
class ADType(object):
'''
Advertising Data Type
'''
AD_TYPE_FLAGS = const(0x01) # Flags for discoverability.
AD_TYPE_16BIT_SERVICE_UUID_COMPLETE = const(0x03) # Complete list of 16 bit service UUIDs.
AD_TYPE_32BIT_SERVICE_UUID_COMPLETE = const(0x05) # Complete list of 32 bit service UUIDs.
AD_TYPE_128BIT_SERVICE_UUID_COMPLETE = const(0x07) # Complete list of 128 bit service UUIDs.
AD_TYPE_COMPLETE_LOCAL_NAME = const(0x09) # Complete local device name.
AD_TYPE_APPEARANCE = const(0x19) # Appearance.
def demo():
from machine import Pin
def rx_callback(data):
print("rx received: {}".format(data))
led.value(1 if data == b'on\0' else 0)
uart.send("on" if led.value() else "off")
def button_callback(pin):
led.value(not led.value())
uart.send("on" if led.value() else "off")
ble = bt.BLE()
uart = BLEUART(ble, rx_callback)
led = Pin(2, Pin.OUT, value=0)
button = Pin(0, Pin.IN, Pin.PULL_UP)
button.irq(button_callback, Pin.IRQ_RISING)
demo()
3,代码说明
demo()函数就是测试用的,可只在这个函数里面修改,其他不改。
注意:用APP Inventor文本传输的是带有’\0’的字符串,如果使用nRF Connect软件发送的数据是不带’\0’的,在判断时应去掉。
代码中所提到的const.py和tools.py文件是官方固件所没有的,在这里可以不用管,如果不修改广播,我已经把要用到的摘取下来了,可以直接把上述代码复制到一个文件里。如果要修改,请参考:MicroPython for ESP32 开发板低功耗蓝牙
4,APP代码:ESP32与APP通信–基于APP Inventor的BLE蓝牙篇
5,其他参考
ESP32 快速参考