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.

I am running into the same issue, have a device I am trying to control with OMG, and it only responds to write REQUEST not write COMMAND. Verified with another tool (nRF), and can initiate actions. Have you found any way to make this work through MQTT?

Thanks

This issue was raised by @deltaphi not sure if he solved it.
Note that during my test with switchbot s1 I have found that the mac_type is required to be able to connect to the device. Not sure it is helpfull but just in case.

Hello Everyone,

nice to see that there are more people interested in writing to BLE chips! I can report that I gave this another unsuccessful go using the release version of v0.9.9.

The suggestions by @h2zero are certainly interesting. However, it appears that one would have to dig fairly deep into the architecture of OMG in order to find out where to add the extra task and how to make it communicate correctly with the scanning task, at least to ensure that both won’t try to access the BLE hardware at the same time. Given that I was actually looking for OMG as a simple solution for BL writes rather than another software project to pick up, I have this suggestion filed away on my To Do list for when I have more spare time (or fewer ongoing projects :wink: ).

Regards
Damian

@deltaphi, did you try this kind of message format with TTL and the immediate parameter and v0.9.11:

{
  "ble_write_address": "FF:AA:BB:FF:DD:EE",
  "ble_write_service": "cba20d00-224d-11e6-9fb8-0002a5d5c51b",
  "ble_write_char": "cba20002-224d-11e6-9fb8-0002a5d5c51b",
  "ble_write_value": "570100",
  "value_type": "HEX",
  "ttl": 4,
  "mac_type":1,
  "immediate": true
}

@1technophile Thank you for this extended message. This does indeed work. With a short delay (very few seconds, typically) OMG connects to my Device and transmits the correct command - my device performs the expected action. This is great, thank you very much!

What is not so great, however, is that there appears to be a bit of a range issue. When I have OMG on my ESP32 and my Device next to each other (<20cm), command execution is very reliable and very fast. However, I want to place my device across the room - about 4-5m of open space, maybe with a chair or a piece of my couch in the direct line of sight. OMG does still receive the broadcasts from my Device, but transmission to the device is slow and sometime only the connection is established, but the write can not be seen on the device.

My device is based on an Olimex MOD-nRF8001, which I used to be able to send to from a Smartphone for about the same distance including a brick wall. Not having a reliable transmission through open space from the ESP32 is a bummer.

Maybe another (low priority) feature request here: Since this is an acknowledged write, the OMG should be aware of whether the write went through. However, there is no feedback to be seen in MQTT. It would be nice to see some feedback there: Is OMG still trying to transmit? Did it find the device? Did the write happen? etc.

Regards
Damian

Another update: I dug out an ESP32 board with an external antenna. That seemed to do the trick - in my tests just now the connection was reliable. Case closed - thank you to all involved!

1 Like