Search code examples
pythonbluetoothbbc-microbit

How can I send MES events to a micro:bit from python over bluetooth


I am trying to send events from my Raspberry Pi Zero W to my micro:bit in Python code to control a Kitronik Servo:Lite board.

I have proved the micro:bit can control the Servo:Lite board using the Kitronik sample code and the Kitronik android gamepad app. In my python code I can successfully connect the Pi to micro:bit like so:

from bluezero import microbit
ubit = microbit.Microbit(adapter_addr='xx:xx:xx:xx:xx:xx',
                     device_addr='yy:yy:yy:yy:yy:yy')
my_text = 'Hello, world'
ubit.connect()

The android app released by Kitronik sends MES events to control the Servo:Lite board. How can I send these from my python code?


Solution

  • The Bluezero library doesn't support the Message Event Service (MES) in the microbit module.

    The goal of Bluezero is to be easy to use as an introduction to BLE. I have not had the need to use the MES service so have not taken the time to build a beginner friendly API using the information from the micro:bit Bluetooth Profile.

    My understanding is that in your application, on connection the Python code should read the MicroBit Requirements characteristic (UUID: E95DB84C-251D-470A-A062-FA1922DFA9A8)

    And then send commands via the Client Event characteristic (UUID: E95D5404-251D-470A-A062-FA1922DFA9A8)

    As you will see in the micro:bit Bluetooth Profile document, the events are numbers. Some of these numbers are can be obtained from: https://lancaster-university.github.io/microbit-docs/ble/event-service/#microbit-code-for-the-buggy-controller.

    To get you something with as few lines of code as possible, here is an example using the BLE-GATT library.

    from time import sleep
    import BLE_GATT
    
    ubit_address = 'yy:yy:yy:yy:yy:yy'
    ubit_req = 'E95DB84C-251D-470A-A062-FA1922DFA9A8'
    client_event = 'E95D5404-251D-470A-A062-FA1922DFA9A8'
    MES_DPAD_CONTROLLER = 1104
    MES_DPAD_1_BUTTON_UP_ON = 1
    MES_DPAD_1_BUTTON_UP_OFF = 2
    MES_DPAD_1_BUTTON_DOWN_ON = 3
    MES_DPAD_1_BUTTON_DOWN_OFF = 4
    MES_DPAD_1_BUTTON_LEFT_ON = 5
    MES_DPAD_1_BUTTON_LEFT_OFF = 6
    MES_DPAD_1_BUTTON_RIGHT_ON = 7
    MES_DPAD_1_BUTTON_RIGHT_OFF = 8
    MES_DPAD_2_BUTTON_UP_ON = 9
    MES_DPAD_2_BUTTON_UP_OFF = 10
    MES_DPAD_2_BUTTON_DOWN_ON = 11
    MES_DPAD_2_BUTTON_DOWN_OFF = 12
    MES_DPAD_2_BUTTON_LEFT_ON = 13
    MES_DPAD_2_BUTTON_LEFT_OFF = 14
    MES_DPAD_2_BUTTON_RIGHT_ON = 15
    MES_DPAD_2_BUTTON_RIGHT_OFF = 16
    
    
    ubit = BLE_GATT.Central(ubit_address)
    ubit.connect()
    
    # Print what micro:bit is interested in
    print(ubit.char_read(ubit_req))
    
    # Send left D-Pad pressed 
    ubit.char_write(client_event, MES_DPAD_CONTROLLER.to_bytes(2, byteorder='little') + MES_DPAD_1_BUTTON_UP_ON.to_bytes(2, byteorder='little'))
    
    # Wait 3 seconds
    sleep(3)
    
    # Release the button
    ubit.char_write(client_event, MES_DPAD_CONTROLLER.to_bytes(2, byteorder='little') + MES_DPAD_1_BUTTON_UP_OFF.to_bytes(2, byteorder='little'))
    
    ubit.disconnect()
    

    I have no way of testing if that is what is required for the Kitronik Servo:Lite board and is just my best guess. If you have more information then I can update the answer.