025 - ESP32 MicroPython: ESP32 Bluetooth Low Energy

Introduction

In this article, I will discussed how you can use ESP32 BLE capability using MicroPython.

Bluetooth Low Energy or BLE is very popular on most devices today because of its low power consumption. That is achieve by constantly switching to sleep mode then once in a while wakes up to process Bluetooth functions. With its low power requirements, it is best suited for battery operated applications.

As of this writing, Bluetooth Classic or the traditional Bluetooth communication is not yet supported by MicroPython community so we will just use the BLE instead. By following the example source code given below, you can implement both direction of communication using BLE.

Bill Of Materials

  1. ESP32 development board.

Video Demonstration

Source Code

1. Example # 1: Demo sending and receiving BLE request:

 1from machine import Pin
 2from machine import Timer
 3from time import sleep_ms
 4import ubluetooth
 5
 6ble_msg = ""
 7
 8class ESP32_BLE():
 9    def __init__(self, name):
10        # Create internal objects for the onboard LED
11        # blinking when no BLE device is connected
12        # stable ON when connected
13        self.led = Pin(2, Pin.OUT)
14        self.timer1 = Timer(0)
15        
16        self.name = name
17        self.ble = ubluetooth.BLE()
18        self.ble.active(True)
19        self.disconnected()
20        self.ble.irq(self.ble_irq)
21        self.register()
22        self.advertiser()
23
24    def connected(self):
25        self.led.value(1)
26        self.timer1.deinit()
27
28    def disconnected(self):        
29        self.timer1.init(period=100, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value()))
30
31    def ble_irq(self, event, data):
32        global ble_msg
33        
34        if event == 1: #_IRQ_CENTRAL_CONNECT:
35                       # A central has connected to this peripheral
36            self.connected()
37
38        elif event == 2: #_IRQ_CENTRAL_DISCONNECT:
39                         # A central has disconnected from this peripheral.
40            self.advertiser()
41            self.disconnected()
42        
43        elif event == 3: #_IRQ_GATTS_WRITE:
44                         # A client has written to this characteristic or descriptor.          
45            buffer = self.ble.gatts_read(self.rx)
46            ble_msg = buffer.decode('UTF-8').strip()
47            
48    def register(self):        
49        # Nordic UART Service (NUS)
50        NUS_UUID = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
51        RX_UUID = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
52        TX_UUID = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
53            
54        BLE_NUS = ubluetooth.UUID(NUS_UUID)
55        BLE_RX = (ubluetooth.UUID(RX_UUID), ubluetooth.FLAG_WRITE)
56        BLE_TX = (ubluetooth.UUID(TX_UUID), ubluetooth.FLAG_NOTIFY)
57            
58        BLE_UART = (BLE_NUS, (BLE_TX, BLE_RX,))
59        SERVICES = (BLE_UART, )
60        ((self.tx, self.rx,), ) = self.ble.gatts_register_services(SERVICES)
61
62    def send(self, data):
63        self.ble.gatts_notify(0, self.tx, data + 'n')
64
65    def advertiser(self):
66        name = bytes(self.name, 'UTF-8')
67        adv_data = bytearray('x02x01x02') + bytearray((len(name) + 1, 0x09)) + name
68        self.ble.gap_advertise(100, adv_data)
69        print(adv_data)
70        print("rn")
71                # adv_data
72                # raw: 0x02010209094553503332424C45
73                # b'x02x01x02ttESP32BLE'
74                #
75                # 0x02 - General discoverable mode
76                # 0x01 - AD Type = 0x01
77                # 0x02 - value = 0x02
78                
79                # https://jimmywongiot.com/2019/08/13/advertising-payload-format-on-ble/
80                # https://docs.silabs.com/bluetooth/latest/general/adv-and-scanning/bluetooth-adv-data-basics
81
82led = Pin(2, Pin.OUT)
83but = Pin(0, Pin.IN)
84ble = ESP32_BLE("ESP32BLE")
85
86def buttons_irq(pin):
87    led.value(not led.value())
88    ble.send('LED state will be toggled.')
89    print('LED state will be toggled.')   
90but.irq(trigger=Pin.IRQ_FALLING, handler=buttons_irq)
91
92while True:
93    if ble_msg == 'read_LED':
94        print(ble_msg)
95        ble_msg = ""
96        print('LED is ON.' if led.value() else 'LED is OFF')
97        ble.send('LED is ON.' if led.value() else 'LED is OFF')
98    sleep_ms(100)

2. Example # 2, demo continuous sending of BLE message.

In this example is_ble_connected global variable is used. This will represent if a device is connected on the BLE device. If you try to send a BLE message when no device is connected, it will throw an error OS Error: -128.:

 1from machine import Pin
 2from machine import Timer
 3from time import sleep_ms
 4import ubluetooth
 5
 6ble_msg = ""
 7is_ble_connected = False
 8
 9class ESP32_BLE():
10    def __init__(self, name):
11        # Create internal objects for the onboard LED
12        # blinking when no BLE device is connected
13        # stable ON when connected
14        self.led = Pin(2, Pin.OUT)
15        self.timer1 = Timer(0)
16        
17        self.name = name
18        self.ble = ubluetooth.BLE()
19        self.ble.active(True)
20        self.disconnected()
21        self.ble.irq(self.ble_irq)
22        self.register()
23        self.advertiser()
24
25    def connected(self):
26        global is_ble_connected
27        is_ble_connected = True
28        self.led.value(1)
29        self.timer1.deinit()
30
31    def disconnected(self):
32        global is_ble_connected
33        is_ble_connected = False
34        self.timer1.init(period=100, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value()))
35
36    def ble_irq(self, event, data):
37        global ble_msg
38        
39        if event == 1: #_IRQ_CENTRAL_CONNECT:
40                       # A central has connected to this peripheral
41            self.connected()
42
43        elif event == 2: #_IRQ_CENTRAL_DISCONNECT:
44                         # A central has disconnected from this peripheral.
45            self.advertiser()
46            self.disconnected()
47        
48        elif event == 3: #_IRQ_GATTS_WRITE:
49                         # A client has written to this characteristic or descriptor.          
50            buffer = self.ble.gatts_read(self.rx)
51            ble_msg = buffer.decode('UTF-8').strip()
52            
53    def register(self):        
54        # Nordic UART Service (NUS)
55        NUS_UUID = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
56        RX_UUID = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
57        TX_UUID = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
58            
59        BLE_NUS = ubluetooth.UUID(NUS_UUID)
60        BLE_RX = (ubluetooth.UUID(RX_UUID), ubluetooth.FLAG_WRITE)
61        BLE_TX = (ubluetooth.UUID(TX_UUID), ubluetooth.FLAG_NOTIFY)
62            
63        BLE_UART = (BLE_NUS, (BLE_TX, BLE_RX,))
64        SERVICES = (BLE_UART, )
65        ((self.tx, self.rx,), ) = self.ble.gatts_register_services(SERVICES)
66
67    def send(self, data):
68        self.ble.gatts_notify(0, self.tx, data + 'n')
69
70    def advertiser(self):
71        name = bytes(self.name, 'UTF-8')
72        adv_data = bytearray('x02x01x02') + bytearray((len(name) + 1, 0x09)) + name
73        self.ble.gap_advertise(100, adv_data)
74        print(adv_data)
75        print("rn")
76                # adv_data
77                # raw: 0x02010209094553503332424C45
78                # b'x02x01x02ttESP32BLE'
79                #
80                # 0x02 - General discoverable mode
81                # 0x01 - AD Type = 0x01
82                # 0x02 - value = 0x02
83                
84                # https://jimmywongiot.com/2019/08/13/advertising-payload-format-on-ble/
85                # https://docs.silabs.com/bluetooth/latest/general/adv-and-scanning/bluetooth-adv-data-basics
86
87
88ble = ESP32_BLE("ESP32BLE")
89
90while True:
91    if is_ble_connected:
92        ble.send('Hello')
93    sleep_ms(1000)

References And Credits

  1. MicroPython BLE documents: https://docs.micropython.org/en/latest/library/ubluetooth.html

  2. Micropython BLE examples: https://github.com/micropython/micropython/tree/master/examples/bluetooth



Posts in this series



No comments yet!

GitHub-flavored Markdown & a sane subset of HTML is supported.