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
- 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
-
MicroPython BLE documents: https://docs.micropython.org/en/latest/library/ubluetooth.html
-
Micropython BLE examples: https://github.com/micropython/micropython/tree/master/examples/bluetooth
Posts in this series
- 026 - ESP32 MicroPython: MFRC522 RFID Module
- 024 - ESP32 MicroPython: How to Use SD Card in MicroPython
- 023 - ESP32 MicroPython: Binary Clock
- 022 - ESP32 MicroPython: MQTT Part 2: Subscribe
- 021 - ESP32 MicroPython: MQTT Part 1: Publish
- 020 - ESP32 MicroPython: RESTful APIs | Demo READ and WRITE
- 019 - ESP32 MicroPython: OpenWeather | RESTful APIs
- 018 - ESP32 MicroPython: Thingspeak | RESTful APIs
- 017 - ESP32 MicroPython: DHT Values Auto Updates using AJAX
- 016 - ESP32 MicroPython: Web Server | ESP32 Access Point
- 015 - ESP32 MicroPython: Web Server | ESP32 Station Mode in MicroPython
- 014 - ESP32 MicroPython: SIM800L GSM Module in MicroPython
- 013 - ESP32 MicroPython: UART Serial in MicroPython
- 012 - ESP32 MicroPython: HC-SR04 Ultrasonic Sensor in MicroPython
- 011 - ESP32 MicroPython: DHT11, DHT22 in MicroPython
- 010 - ESP32 MicroPython: 0.96 OLED in MicroPython
- 009 - ESP32 MicroPython: Non-blocking Delays and Multithreading | Multitasking
- 008 - ESP32 MicroPython: Hardware Timer Interrupts
- 007 - ESP32 MicroPython: How to make some sound with MicroPython
- 006 - ESP32 MicroPython: How to control servo motor with MicroPython
- 005 - ESP32 MicroPython: Pulse Width Modulation
- 004 - ESP32 MicroPython: External Interrupts
- 003 - ESP32 MicroPython: General Purpose Input Output | GPIO Pins
- 001 - ESP32 MicroPython: What is MicroPython
- 000 - ESP32 MicroPython: How to Get Started with MicroPython
No comments yet!