Github Upload Boards Devices Community Docs Blog

BLE write to characteristic

Hello OpenMQTTGateway Community,

I want to use OpenMQTTGateway to connect a BLE device to my Home Assistant installation. My usecase is that when I push a button in Home Assistant, I want to write a specific byte string to a specific characteristic of a specific device.

I installed OpenMQTTGateway on an ESP32 NodeMCU board and connected it to my WiFi and the Mosquitto MQTT Broker running on my Home Assistant. When using MQTT Explorer from my Laptop connected to my Mosquitto installation, I can see that the OpenMQTTGateway publishes a lot of BLE devices into MQTT - especially, it also publishes the device I want to use.

I then proceeded to try and write to a characteristic of my device. I used the examples given in BLE gateway | OpenMQTTGateway v0.9.9beta and adapted them for my device: The topic remains the same, but I substituted the MAC, Service UUID, Characteristic UUID and the data I want to send. I used MQTT Explorer to publish the message.

As you may have guessed by me posting here, it didn’t work. In trying to debug this, I looked at the serial console of OpenMQTTGateway. On the console, I can see messages whenever the BLE Scan finds a new device. I would expect the console to also show that a command was received from MQTT - but nothing.

At this point I did some more experimenting and found interesting things. You actually do have to adjust the topic! The examples state to use the Topic home/OpenMQTTGateway/commands/MQTTtoBT/config. But what you actually need to do is to substitude the “OpenMQTTGateway” for the actual name of your Gateway device. I flashed the esp32dev-ble configuration, where the default name is OpenMQTTGateway_ESP32_BLE. So, publishing to home/OpenMQTTGateway_ESP32_BLE/commands/MQTTtoBT/config, I can suddenly see the message N: Received json : <my payload> appear on the serial console. No other messages regarding to my write command are shown. So that bit is sorted at least. I would suggest updating the documentation, though.

For reference, I publish the following (all values substituted for privacy, but I triple-checked what I am actually sending):

home/OpenMQTTGateway_ESP32_BLE/commands/MQTTtoBT/config

{
  "ble_write_address":"FF:00:FF:00:FF:00",
  "ble_write_service":"9184e8db-850c-4057-b0fc-d49a10738a1b",
  "ble_write_char":"9184fd66-850c-4057-b0fc-d49a10738a1b",
  "ble_write_value":"DEADBEEF",
  "value_type":"HEX",
  "ttl":4
}

As a second step, I started to debug my BLE device. It does produce serial output whenever someone wants to talk to it using BLE. For testing purposes, I whipped up a python script to write to the characteristic using the BLE adapter in my windows laptop. This works and the BLE device performs the expected action. On the serial console of the BLE device I can see the connection attempt, the write and the disconnect from the windows laptop.

However, when attempting the BLE write via OpenMQTTGateway, the serial console of my BLE device remains silent.

I initially tried this using v0.9.8. When I started to get down to more analysis, I moved over to v0.9.9beta. I have not run all tests on v0.9.8.

What can I do to make OpenMQTTGateway write to my BLE device?

Regards
Damian

Hi Damian,

I have a similar interest, and while sending off a battery request and waiting a while for the result works fine for me, writing immediate characteristics is sitll an issue, due to the timed scanning cycle. I logged this recently

Hello,

You have to consider that the connection will be done by default every 10 scans and depending on your scan duration you may have to wait a long time.
For you test purposes I would try with the following macros in config_BT.h:
# define ScanBeforeConnect 1
# define Scan_duration 1000
# define TimeBtwRead 5000

With these parameters, a connection attempt will be issued every second.

Hi @1technophile,

thank you for your reply. Another step forward, but still no success. I’m now seeing the lines

N: BLE Connect begin
N: BLE Connect end

after every scan. If I send a write command via MQTT, there is a pause after the begin. Unfortunately, the connection does not work: I get a timeout message:

N: BLE Connect begin
E NimBLEClient: "Connection failed; status=13 "
E: Connect to: ff:00:ff:00:ff:00 failed
N: BLE Connect end

(status 13 decoded via NimBLE Host Return Codes — Apache Mynewt latest documentation)

The serial console of my BLE device shows nothing - but I think it will only wake its CPU when a connection is successefully established, so I’m not too surprised about this.

Is there anything else I can try to debug this further? Can I somehow get more detailed error codes?

Regards
Damian

Hello @deltaphi ,

We may have to play with connection parameters and timeout to make it work.

Maybe one possibility is to tweak the NimBLEClient example until it works. Once done I will see what parameters need to be added into OMG codebase.

Hi @1technophile,

I got the NimBLE Client Example to work. What I needed to do:

  1. Plug in the correct UUIDs (obviously). At this point, the serial console of my BLE device showed a successful connection from the NimBLE Client, but I could not see the write.
  2. Adjust the write call to expect a response (my BLE Device uses a write with response): pChr->writeValue(0xDEADBEEF, true). The example originally uses a write without response. At this point, the serial console of my BLE device showed a successful write.
  3. Fiddle with the byte ordering of my payload to produce the expected output on my BLE device. This was just a bonus at this point :slight_smile:

While in my case, OpenMQTTGateway does not even manage the connection, I will run into the issue of not being able to select a write with/without response via MQTT soon after fixing the connection problem.

I also had the BLE device output the agreed-upon timing paramers used on an established connection. While the python script from the laptop uses vastly different parameters (latency == 0 being the only obvious similarity), the connection worked regardless of the timing parameters. If needed, I can run more tests whether specific parameters work, but given the number of dimensions I would appreciate a pointer at which parameters and which value ranges I should evaluate. For example, what values does OpenMQTTGateway use? VS Code can’t find a call to setConnectionParams in the codebase.

Regards
Damian

1 Like

@h2zero the service/characteristics/connect sequence seems to work out of the box with NimBLE Arduino example, do you have any advice to make it works with OMG?

Wow, sorry I didn’t see this sooner, not sure why I didn’t getting pinged.

So, to start with, if the device requires a write with response message instead of non-response that is something that can bee added to the command parameters but is for now not supported.

E NimBLEClient: "Connection failed; status=13 "

The status code here is BLE_HS_ETIMEOUT Operation timed out. Likely cause is the device was not advertising when the connection attempt was made.

OMG does not try to connect again on failure so as to not block the other tasks. However, there are some options that could be added to the connection code to run it in a separate task, would require blocking the scan operations while connecting though. Maybe a retry count and timeout parameter could be added for such failure cases.

Maybe one possibility is to tweak the NimBLEClient example until it works. Once done I will see what parameters need to be added into OMG codebase.

The default parameters should work for 90% of cases and should only changed for specific reasons.The issue here I believe is latency between when the device is actively advertising and when we attempt connection. I think we may need to run the connection code in a separate task that can be triggered by the command.