Implementing Bluetooth Low Energy using ESP32 and Micropython

Implementing Bluetooth Low Energy using ESP32 and Micropython

Bluetooth Low Energy is a leading protocol. It is low power protocol operating in licence free frequency band. It is called the subset of Bluetooth classic but not backward compatible. It operates in 2,4 Ghz frequency band. In Ble the communication is done using attributes which have UUID (Unique Universal ID). 

The Advertiser(peripheral)  device advertises the message containing Product Id ,manufactures ID and services offered etc. The  master device(Central device) wishes to  get connected with advertiser device accepts the connect request. When the connection is established between both the devices the data communication starts in terms of packets. The packets can be sent after the connection interval time agreed upon between the two devices ,by the peripheral, In between the peripheral device can sleep, So the device power is saved. More details available on youtube video here.

Micropython is becoming popular nowadays. It uses python as the programming language for working with microcontrollers. It has support for Esp32,ESP8266,CC3200,STM 32,Raspberry Pi and PI boards etc.

This video explains how to implement BLE using ESP32 and Micropython


In this project, the Thonny Ide is used for implementing the code. Some details of the code are discussed below. We have imported some libraries Important among them is ubluetooth library. This library is used to implement the functionality of BLE.The machine library is used to implement the operation related to microcontroller like I/o pin and Time Pin.

from machine import Pin

from machine import Timer

from time import sleep_ms

import ubluetooth

The class BLE has the initialization function __init where initialization related to BLE parameters is done. There callback functions like Connected and Disconnected where some actions items are put.The send functions deals with transmitting the packet over BLe channels.The Advertiser function initializes advertisement data.

The functionality 

The application code initiates advertisement(Led on Esp32 Board flashes) and is connected with the central device.Here we have use mobile App Serial Bluetooth Terminal(It can be downloaded from the Play store) as a Central device.When connetion is established the Led becomes steady. When the key is pressed on Esp32 board the Led status is toggles and one counter value is transmitted to the Mobile App. The status of Led is read using the command Read Led.The Led on Esp Board is turned On and off using the commands Led on and Led Off. The Led blinking command is initiated by using command Led Blink.

The full Source code is as given below.

       
from machine import Pin
from machine import Timer
from time import sleep_ms
import ubluetooth

ble_msg = ""


class BLE():
    def __init__(self, name):
        # Create internal objects for the onboard LED
        # blinking when no BLE device is connected
        # stable ON when connected
        self.led = Pin(2, Pin.OUT)
        self.timer1 = Timer(0)
        
        self.name = name
        self.ble = ubluetooth.BLE()
        self.ble.active(True)
        self.disconnected()
        self.ble.irq(self.ble_irq)
        self.register()
        self.advertiser()

    def connected(self):
        self.led.value(1)
        self.timer1.deinit()

    def disconnected(self):        
        self.timer1.init(period=200, mode=Timer.PERIODIC, callback=lambda t: self.led.value(not self.led.value()))

    def ble_irq(self, event, data):
        global ble_msg
        
        if event == 1: #_IRQ_CENTRAL_CONNECT:
                       # A central has connected to this peripheral
            self.connected()

        elif event == 2: #_IRQ_CENTRAL_DISCONNECT:
                         # A central has disconnected from this peripheral.
            self.advertiser()
            self.disconnected()
        
        elif event == 3: #_IRQ_GATTS_WRITE:
                         # A client has written to this characteristic or descriptor.          
            buffer = self.ble.gatts_read(self.rx)
            ble_msg = buffer.decode('UTF-8').strip()
            
    def register(self):        
        # Nordic UART Service (NUS)
        NUS_UUID = '6E400001-B5A3-F393-E0A9-E50E24DCCA9E'
        RX_UUID = '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
        TX_UUID = '6E400003-B5A3-F393-E0A9-E50E24DCCA9E'
            
        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, )
        ((self.tx, self.rx,), ) = self.ble.gatts_register_services(SERVICES)

    def send(self, data):
        self.ble.gatts_notify(0, self.tx, data + '\n')

    def advertiser(self):
        name = bytes(self.name, 'UTF-8')
        adv_data = bytearray('\x02\x01\x02') + bytearray((len(name) + 1, 0x09)) + name
        self.ble.gap_advertise(100, adv_data)
        print(adv_data)
        print("\r\n")
                # adv_data
                # raw: 0x02010209094553503332424C45
                # b'\x02\x01\x02\t\tESP32BLE'
                #
                # 0x02 - General discoverable mode
                # 0x01 - AD Type = 0x01
                # 0x02 - value = 0x02
                
                # https://jimmywongiot.com/2019/08/13/advertising-payload-format-on-ble/
                # https://docs.silabs.com/bluetooth/latest/general/adv-and-scanning/bluetooth-adv-data-basics



led = Pin(2, Pin.OUT)
but = Pin(0, Pin.IN)
ble = BLE("ESP32BLE")

def buttons_irq(pin):
    led.value(not led.value())
    ble.send('LED state will be toggled.')
    print('LED state will be toggled.')
    
    global counter
    
    if counter >= 20:
        counter = 0
        
    counter = counter + 1
     
    ble.send('counter value is') 
    ble.send(str(counter))
    print('Counter Value', counter)
    
counter = 0
but.irq(trigger=Pin.IRQ_FALLING, handler=buttons_irq)

while True:
    if ble_msg == 'Read Led':
        print(ble_msg)
        ble_msg = ""
        print('LED is ON.' if led.value() else 'LED is OFF')
        ble.send('LED is ON.' if led.value() else 'LED is OFF')
    elif ble_msg == 'Led On':
        print(ble_msg)
        ble_msg = ""
        print('Led is On')
        ble.send('Led is On')
        led.value(1)
    elif ble_msg == 'Led Blink':
        print(ble_msg)
        ble_msg = ""
        print('Led Blinking')
        ble.send('Led Blinking')
        ble.timer1.deinit()
        ble.timer1.init(period=1000, mode=Timer.PERIODIC, callback=lambda t: ble.led.value(not ble.led.value()))
    elif ble_msg == 'Led Off':
        print(ble_msg)
        ble_msg = ""
        print('Led is off')
        ble.send('Led is off')
        led.value(0)
        ble.timer1.deinit()
            
    sleep_ms(100)
       
 



Others :

Use of Tasmota with ESP32+Mqtt

Implementing Mqtt Client in Python|Paho-Mqtt library.

Integrate Tasmota Device with Home Assistant+Mqtt

Integrate ESP Home Device with Home Assistant

Post a Comment

Previous Post Next Post