Skip to content

S4 + esp32 (Micropython) - не получается выполнить pair #42

@aalexey07

Description

@aalexey07

Версия модуля: 3.3.5
Модель бризера: S4
Версия прошивки (если известна): 02D2

Описание проблемы

Пишу модуль на микропитоне для esp32, планирую использовать ваши наработки по протоколу для формирования сообщений для бризера S4. Начал с сопряжения и не получается его выполнить. Помогите пожалуйста разобраться с логикой обмена сообщениями с бризером.

Порядок действий, которые приводят к проявлению проблемы

  1. Использую модуль bluetooth (пробовал и с ubluetooth) микропитона https://docs.micropython.org/en/latest/library/bluetooth.html.
  2. Перевожу бризер в режим сопряжения (светодиод на бризере мигает синим цветом).
  3. На esp32 (скетч в конце тикета) отправляю команду ble.connect(1, ubinascii.unhexlify(b'f022a36c3a55')).
  4. Получаю событие об успешном подключении к бризеру.
# _IRQ_PERIPHERAL_CONNECT:
# A successful gap_connect().

Connection_handle:0 addr_type:1 addr:b'f022a36c3a55'
  1. Отправляю команду запроса статуса ble.send(ubinascii.unhexlify(b'8010003aa13232b788d5da1ec11843bbaa')).
  2. Ответа на нее не вижу. Пока представляю себе этот процесс так, что бризер должен уведомить esp32, что положил в ее UUID сообщение и возникнет событие, которое успешно обрабатывается, когда проверял обмен сообщениями с телефоном:
# _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()
  1. Далее пробовал и делать дисконект, и не делать его ble.disconnect(). Пробовал отправлять как одну команду запроса статуса за один сеанс привязки, так и несколько команд за один сеанс. Для отладки пока команды формирую в отдельном файле кодом из вашего модуля с 8 рандомными байтами.
  2. Бризер выходит из режима сопряжения.
  3. Получаю событие о дисконнекте (либо получаю его, когда сам сделал дисконнект)
# _IRQ_PERIPHERAL_DISCONNECT:
# Connected peripheral has disconnected.
  1. На esp32 отправляю команду ble.connect(1, ubinascii.unhexlify(b'f022a36c3a55')) и сразу же получаю событие о дисконнекте.
  2. Делаю вывод, что сопряжение не удалось.

Вопросы:

  1. Нужно ли во время сопряжения перед командой запроса состояния бризера отправлять отдельную команду сопряжения ble.pair()? Посмотрел ваш модуль и не увидел, что она отправляется.

Я ее пробовал отправлять, но модуль на микропитоне ее похоже не поддерживает, т.к. получаю в терминале:

Pairing...
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "main.py", line 168, in con2br
  File "main.py", line 150, in pair
AttributeError: 'BLE' object has no attribute 'gap_pair'

И в описании модуля написано, что на esp32 она не поддерживается, или же pair поддерживается, но не поддерживается bonding...

  1. Корректную ли команду запроса состояния бризера я отправляю?
  2. Как вы предполагаете, почему не получается сделать сопряжение?

Логи

Вставьте сюда debug-log, в момент проявления проблемы

Скетч для esp32:

from machine import Pin
from machine import Timer
from machine import soft_reset
from time import sleep_ms, sleep
# import ubluetooth
import bluetooth
import ubinascii

ble_msg = ""


class ESP32_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 = bluetooth.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=100, 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()

        elif event == 5:  # _IRQ_SCAN_RESULT:
            # A single scan result.
            addr_type, addr, adv_type, rssi, adv_data = data
            print(
                'Addr_type:{} addr:{} adv_type:{} rssi:{} adv_data:{}'.format(addr_type, ubinascii.hexlify(addr),
                                                                              adv_type, rssi,
                                                                              ubinascii.hexlify(adv_data)))

        elif event == 6:    # _IRQ_SCAN_DONE:
            # Scan duration finished or manually stopped.
            print('Scan stopped (duration finished or manually)')

        elif event == 7:  # _IRQ_PERIPHERAL_CONNECT:
            # A successful gap_connect().
            print('Connected')
            conn_handle, addr_type, addr = data
            print('Connection_handle:{} addr_type:{} addr:{}'.format(conn_handle, addr_type, ubinascii.hexlify(addr)))

        elif event == 8:        # _IRQ_PERIPHERAL_DISCONNECT:
            # Connected peripheral has disconnected.
            conn_handle, addr_type, addr = data
            print('Disconnected')

        elif event == 28:       # _IRQ_ENCRYPTION_UPDATE:
            # The encryption state has changed (likely as a result of pairing or bonding).
            conn_handle, encrypted, authenticated, bonded, key_size = data
            print('After pairing: ', conn_handle, encrypted, authenticated, bonded, key_size)

    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_NUS = bluetooth.UUID(NUS_UUID)
        BLE_RX = (bluetooth.UUID(RX_UUID), bluetooth.FLAG_WRITE)
        BLE_TX = (bluetooth.UUID(TX_UUID), bluetooth.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

    def scan(self, duration):
        print('Started scanning')
        self.ble.gap_scan(duration)

    def connect(self, addr_type, mac, scan_duration=2000):
        # addr_type values indicate public or random addresses:
        # 0x00 - PUBLIC
        # 0x01 - RANDOM(either static, RPA, or NRPA, the type is encoded in the address itself)
        print('Connecting')
        x = 0
        while x < 1:
            try:
                self.ble.gap_connect(addr_type, mac, scan_duration)
                # ble.connect(1, ubinascii.unhexlify(b'f022a36c3a55')) breezer
                # ble.connect(1, ubinascii.unhexlify(b'a4c337077418')) iphone
                ble.send(ubinascii.unhexlify(b'8010003aa13232b788d5da1ec11843bbaa'))
                # ble.send(b'\x80\x10\x00:\xa122(?\xfc\xe7\xb9\x16\xd3\x9d\xbb\xaa')
                break
            except Exception:
                pass
            sleep(2)
            x += 1
        print('Failed to connect')

    def disconnect(self, conn_handle=0):
        self.ble.gap_disconnect(conn_handle)

    def pair(self):
        print('Pairing...')
        self.ble.gap_pair(0)


led = Pin(2, Pin.OUT)
but = Pin(0, Pin.IN)
ble = ESP32_BLE("ESP32BLE_2")


def buttons_irq(pin):
    led.value(not led.value())
    ble.send('LED state will be toggled.')
    print('LED state will be toggled.')


but.irq(trigger=Pin.IRQ_FALLING, handler=buttons_irq)

def con2br():
    ble.connect(1, ubinascii.unhexlify(b'f022a36c3a55'))
    # ble.pair()
    ble.send(ubinascii.unhexlify(b'8010003aa132325b1033dcac14955bbbaa'))
    ble.send(ubinascii.unhexlify(b'8010003aa13232810bd0980babd51abbaa'))
    # ble.send(ubinascii.unhexlify(b'8010003aa132325b1033dcac14955bbbaa'))
    # ble.disconnect()

# con2br()

while True:
    if ble_msg.lower() == 'read_led':
        print(ble_msg)
        ble_msg = ""
        print('LED is ON.' if led.value() else 'LED is OFF')
        sleep(10)
        ble.send('LED is ON.' if led.value() else 'LED is OFF')
    elif ble_msg.lower() == 'scan':
        print(ble_msg)
        ble_msg = ""
        ble.scan(30000)     # 10K ms == 10 s
    elif ble_msg.lower() == 'connect':
        print(ble_msg)
        ble_msg = ""
        # print(ubinascii.unhexlify('f022a36c3a55'))
        ble.connect(1, ubinascii.unhexlify(b'f022a36c3a55'))
    elif ble_msg.lower() == 'dis':
        print(ble_msg)
        ble_msg = ""
        #if ble.disconnect():
           # print('Disconnected')
        #else:
           # print('Failed to disconnect')
    elif ble_msg.lower() == 'req':
        print(ble_msg)
        ble_msg = ""
        ble.send(b'\x80\x10\x00:\xa122(?\xfc\xe7\xb9\x16\xd3\x9d\xbb\xaa')
    elif ble_msg != '':
        print(ble_msg)
    sleep_ms(100)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions