How to use read command on OpenMQTT Gateway

Hi.
I’ve uploaded this simple code to ESP32 BLE peripheral (server) that reads values on pin32

/*
  Battery Monitor

  This example creates a Bluetooth® Low Energy peripheral with the standard battery service and
  level characteristic. The A0 pin is used to calculate the battery level.

  The circuit:
  - Arduino MKR WiFi 1010, Arduino Uno WiFi Rev2 board, Arduino Nano 33 IoT,
    Arduino Nano 33 BLE, or Arduino Nano 33 BLE Sense board.

  You can use a generic Bluetooth® Low Energy central app, like LightBlue (iOS and Android) or
  nRF Connect (Android), to interact with the services and characteristics
  created in this sketch.

  This example code is in the public domain.
*/

#include <ArduinoBLE.h>

 // Bluetooth® Low Energy Battery Service
BLEService batteryService("180F");

// Bluetooth® Low Energy Battery Level Characteristic
BLEUnsignedCharCharacteristic batteryLevelChar("2A19",  // standard 16-bit characteristic UUID
    BLERead | BLENotify); // remote clients will be able to get notifications if this characteristic changes

int oldBatteryLevel = 0;  // last battery level reading from analog input
long previousMillis = 0;  // last time the battery level was checked, in ms

void setup() {
  Serial.begin(9600);    // initialize serial communication
  while (!Serial);

  pinMode(LED_BUILTIN, OUTPUT); // initialize the built-in LED pin to indicate when a central is connected

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting BLE failed!");

    while (1);
  }

  /* Set a local name for the Bluetooth® Low Energy device
     This name will appear in advertising packets
     and can be used by remote devices to identify this Bluetooth® Low Energy device
     The name can be changed but maybe be truncated based on space left in advertisement packet
  */
  BLE.setLocalName("BatteryMonitor");
  BLE.setAdvertisedService(batteryService); // add the service UUID
  batteryService.addCharacteristic(batteryLevelChar); // add the battery level characteristic
  BLE.addService(batteryService); // Add the battery service
  batteryLevelChar.writeValue(oldBatteryLevel); // set initial value for this characteristic

  /* Start advertising Bluetooth® Low Energy.  It will start continuously transmitting Bluetooth® Low Energy
     advertising packets and will be visible to remote Bluetooth® Low Energy central devices
     until it receives a new connection */

  // start advertising
  BLE.advertise();

  Serial.println("Bluetooth® device active, waiting for connections...");
}

void loop() {
  // wait for a Bluetooth® Low Energy central
  BLEDevice central = BLE.central();

  // if a central is connected to the peripheral:
  if (central) {
    Serial.print("Connected to central: ");
    // print the central's BT address:
    Serial.println(central.address());
    // turn on the LED to indicate the connection:
    digitalWrite(LED_BUILTIN, HIGH);

    // check the battery level every 200ms
    // while the central is connected:
    while (central.connected()) {
      long currentMillis = millis();
      // if 2000ms have passed, check the battery level:
      if (currentMillis - previousMillis >= 2000) {
        previousMillis = currentMillis;
        updateBatteryLevel();
      }
    }
    // when the central disconnects, turn off the LED:
    digitalWrite(LED_BUILTIN, LOW);
    Serial.print("Disconnected from central: ");
    Serial.println(central.address());
  }
}

void updateBatteryLevel() {
  /* Read the current voltage level on the A0 analog input pin.
     This is used here to simulate the charge level of a battery.
  */
  int battery = analogRead(32);
  int batteryLevel = map(battery, 0, 1023, 0, 100);
  
  if (batteryLevel != oldBatteryLevel) {      // if the battery level has changed
    Serial.print("Battery Level % is now: "); // print it
    Serial.println(batteryLevel);
    batteryLevelChar.writeValue(batteryLevel);  // and update the battery level characteristic
    oldBatteryLevel = batteryLevel;           // save the level for next comparison
  }
}

At this point I’d like to read values on Mosquitto via OpenMQTT gateway using MQTT explorer.
For this purpose I’ve used read command like this:

mosquitto_pub -u test_user -P xxxxxx -t home/OMG_ESP32_BLE/BTtoMQTT/config -m '{
  "ble_read_address":"E8:31:CD:CB:63:3E",
  "ble_read_service":"180F",
  "ble_read_char":"2A19",
  "value_type":"STRING",
  "ttl": 2 }'

Anyway on MQTT explorer I read this:

In other words I can’t see values.
I’ve tried even to connect the BLE device to nRF connect installed on iPhone but the result is the same: I can’t read the value.
Any idea?
Thanks in advance

Hi @m4biz

The response should come in the device topic, i.e. the E831CDCB633E one, which also shows a message with the “Battery Monitor” name, even if it is an unsuccessful response.

Any response at all in the message history of E831CDCB633E?

You missed the commands in

home/OMG_ESP32_BLE/commands/MQTTtoBT/config

and the direction MQTTtoBT to send the command from MQTT to BT - the other direction from the incoming BTtoMQTT messages :wink:

With you trying to get the default battery level service/char it’s best to try with "value_type":"HEX", or "value_type":"INT",

Hi DigiH, thanks for you reply.
I’ve tried your suggestions but in MQTT explorer I still can’t see values:

mosquitto_pub -u test_user -P xxxxxx -t home/OMG_ESP32_BLE/commands/MQTTtoBT/config -m '{
  "ble_read_address":"E8:31:CD:CB:63:3E",
  "ble_read_service":"180F",
  "ble_read_char":"2A19",
  "value_type":"INT",
  "ttl": 2 }'

And this indipendently if ESP32 BLE peripheral is connected or not to central device (like nRF connect on iPhone).
Where am I wrong?

Which version of OpenMQTTGateway are you actually running? The 1.6.0 release or the development branch?

The last available: 1.6.0 uploaded on ESP32 from
https://docs.openmqttgateway.com/upload/web-install.html

Then the command structure should be fine, there has been a slight change in the latest development branch, which will also be in the next release, as visible in the development docs

But you might need to also add the mac_type to your read command, depending on what mac_type your device has. This can be seen in its MQTT messages when setting Advertisement and Advanced data to true.

You might also want to add an "immediate":true to your READ command to see any response shortly after sending the command. E. g.

mosquitto_pub -u test_user -P xxxxxx -t home/OMG_ESP32_BLE/commands/MQTTtoBT/config -m '{
  "ble_read_address":"E8:31:CD:CB:63:3E",
  "mac_type":1,
  "ble_read_service":"180F",
  "ble_read_char":"2A19",
  "value_type":"HEX",
  "ttl": 4 }'

Hi DigiH.
Sorry for the big , big delay in the reply.
Your suggestions works.


And now I can read characteristc’s values.

Neverthless there are two questions still open:

  1. When I issue the mosquitto_pub command , I can read only once the characteristc’s values and , at the next update, I can’t see it anymore

  2. If I need to issue mosquitto_pub command to see characteristc’s values, how may I integrate it in home assistant’s dashboard?

I hope I’ve been clear.
Any idea?
Thanks in advance

Hi @m4biz

Good to hear you got it working to get the battery level value with the READ command :slight_smile:

Do I understand you correctly, that the next messages received dont’ have the battery level any more, but are the generic broadcast advertising messages seen in your screenshots further above?
If so, this is expected and correct behaviour, as the response to the READ command only comes in once, shortly after the READ command has been issued.

So to use this with any controller you would check for the reply containing “success”: true and/or the existence of the “read” key, with its value.

That “read” key would be assigned to an item/entity in your controller and would keep its value until the next appropriate “read” key value would replace it with a newer battery level.

So yes, you would need to issue the READ command in regular intervals to get the latest battery level reading, or possibly also add a manual READ push button in your controller for immediate battery level requests.

As I’m pretty new to Home Assistant myself, I’m not the best one to ask for how to implement this in HA, which might be answered by someone else here, or be a better posting in the HA forum, or searching there for others asking about manually assigning MQTT keys to entities.

I know though that it is as easily possible to implement this in HA as it is with any other controller.

Hope this clarifies things a bit more.

Hi DigiH.
Thanks for your reply that is very clear as usual.
I’ll try your suggestions asap and than I’ll update you and the community’s users about results.