Connecting to a specific BLE devicetype using UUID and Name - fails

I am getting an error when I try to connect to a specific device
image

The docs have the 'type' missing - it's an HTML tag, so I'm guessing this isn't a simple string?
image

  • device ( component ) β€” A component block that represents a Bluetooth Low Energy device - what should I use here?

My code uses string text for both parameter fields but it must be wrong.
image

EDIT:
It gets more interesting.. changing to the block Connect with Service and Name seemed more appropriate..

However, the sound( a ping) repeats indefinitely and there is no connection ever made either.
I'm surprised and confused why I get permanent pings. When I remove the connect block I get a few pings and then it stops.. which is what I would expect.

One of your BLE blocks wants a component block as input, according to the doc fragment you posted.

The component block of a component (in this case your BLE component) is the last block in each component's palette in the Blocks Editor.

OK> I see that.
Strange because the call actually specifies the device anyway which is some what confusing
image

However, I'm now stuck with the perpetual execution of the sound 'ping'

Let's back up a step.

What version of the BLE extension are you using?

Latest is at

Also, see the Tutorials and Guides - MIT App Inventor Community
category for BLE samples.

Extension Version: 20200828
Date Built: 2020-08-28
I originally imported the previous version , but didn't use it when I discovered the newer one.
I didn't create anything ( as far as I can remember ) until I had installed the current version.

It works fine if I use listpicker and connect with address.
I'm trying to get it to find my unique device and connect automatically

It's probably time to post your blocks and your .aia, so we can see the big picture.

Please download and post each of those event block(s)/procedures here ...
(sample video)


Please export your project and post it here.

BluebeamBLE1 (1).aia (554.3 KB)

Note the blocks allow for two connection approaches.. one manual using list picker,
one using the connect by name - which I had intended to be called first anyway.

This is going to be fun.

You're weak on AI2 and I'm weak on BLE.

I see there's new functionality on Advertisements in BLE, so that further complicates the discovery and connection workflow (which I don't have at my fingertips, and don't see at MIT App Inventor + Internet of Things)

Could you point us to the web page for your particular device, in case that will help?

Also, I see upcoming problems for your List Pickers 2-4 (awful names, please rename them)
when you load them in


via ElementsFromString, which expects comma delimited single dimension lists.
The tooltips for DeviceServices and DeviceCharacteristics say those will return 2 dimension tables with 2 and 4 columns respectively. AI2's default list to text coercions can't flatten that. You must do it in a loop using list blocks, and load into the Elements value.
I can post samples if you want, but first read up on How to Work With Lists at

I did not notice any permission blocks in your project, so you might need to review
https://community.appinventor.mit.edu/search?q=ble%20permission

I'm weak on both ...lol>
I will read through this tomorrow - and advise. Thanks

My device is an ESP 32 running close to example code. But is has an OLED display making it great to see whats happening

    Video: https://www.youtube.com/watch?v=oCMOYS71NIU
    Based on Neil Kolban example for IDF: https://github.com/nkolban/esp32-snippets/blob/master/cpp_utils/tests/BLE%20Tests/SampleNotify.cpp
    Ported to Arduino ESP32 by Evandro Copercini

   Create a BLE server that, once we receive a connection, will send periodic notifications.
   The service advertises itself as: 6E400001-B5A3-F393-E0A9-E50E24DCCA9E
   Has a characteristic of: 6E400002-B5A3-F393-E0A9-E50E24DCCA9E - used for receiving data with "WRITE" 
   Has a characteristic of: 6E400003-B5A3-F393-E0A9-E50E24DCCA9E - used to send data with  "NOTIFY"

   The design of creating the BLE server is:
   1. Create a BLE Server
   2. Create a BLE Service
   3. Create a BLE Characteristic on the Service
   4. Create a BLE Descriptor on the characteristic
   5. Start the service.
   6. Start advertising.

   In this example rxValue is the data received (only accessible inside that function).
   And txValue is the data to be sent, in this example just a byte incremented every second. 
*/
#include <BLEDevice.h>
#include <BLEServer.h>
#include <BLEUtils.h>
#include <BLE2902.h>

#include "SSD1306Wire.h"     // For OLED Display   legacy: #include "SSD1306.h"

SSD1306Wire display(0x3c, 4, 15);  // ADDRESS, SDA, SCL  -  If not, they can be specified manually.
BLECharacteristic *pCharacteristic;
bool deviceConnected = false;
float txValue = 0;
const int readPin = 32; // Use GPIO number. See ESP32 board pinouts
const int LED = 2; // Could be different depending on the dev board. I used the DOIT ESP32 dev board.
std::string rxValue1;

const int OLEDRESET = 16;
bool currentstate;
int counter;

//std::string rxValue; // Could also make this a global var to access it in loop()

// See the following for generating UUIDs:
// https://www.uuidgenerator.net/

#define SERVICE_UUID           "6E400001-B5A3-F393-E0A9-E50E24DCCA9E" // UART service UUID
#define CHARACTERISTIC_UUID_RX "6E400002-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_TX "6E400003-B5A3-F393-E0A9-E50E24DCCA9E"
#define CHARACTERISTIC_UUID_LED "6E400004-B5A3-F393-E0A9-E50E24DCCA9E"



class MyServerCallbacks: public BLEServerCallbacks {
    void onConnect(BLEServer* pServer) {
      deviceConnected = true;
    };

    void onDisconnect(BLEServer* pServer) {
      deviceConnected = false;
    }
};

class MyCallbacks: public BLECharacteristicCallbacks {
    void onWrite(BLECharacteristic *pCharacteristic) {
      std::string rxValue = pCharacteristic->getValue();
      
        rxValue1 = pCharacteristic->getValue();
      if (rxValue.length() > 0) {
        Serial.println("*********");
        Serial.print("Received Value: ");

        for (int i = 0; i < rxValue.length(); i++) {
          Serial.print(rxValue[i]);
        }

        Serial.println();


        // Do stuff based on the command received from the app
        if (rxValue.find("A") != -1) { 
          Serial.print("Turning ON!");
          digitalWrite(LED, HIGH);
           currentstate = true;
        }
        else if (rxValue.find("B") != -1) {
          Serial.print("Turning OFF!");
          digitalWrite(LED, LOW);

             currentstate = false;       
        }

        Serial.println();
        Serial.println("*********");
      }
    }






    
};

void setup() {
  delay(1000);


  pinMode(OLEDRESET, OUTPUT);
  digitalWrite(OLEDRESET, HIGH);
  Serial.begin(57600);

  pinMode(LED, OUTPUT);

  // Initialising the UI will init the display too.
  display.init();

  display.flipScreenVertically();
  display.setFont(ArialMT_Plain_16);


//  display.setTextAlignment(TEXT_ALIGN_RIGHT);
 display.drawString(0, 0,  " Aroma");
 display.drawString(0, 16, " BLE");
 
  // write the buffer to the display
  display.display();


  // Create the BLE Device
  BLEDevice::init("Lume Frag 01"); // Give it a name

  // Create the BLE Server
  BLEServer *pServer = BLEDevice::createServer();
  pServer->setCallbacks(new MyServerCallbacks());

  // Create the BLE Service
  BLEService *pService = pServer->createService(SERVICE_UUID);

  // Create a BLE Characteristic
  pCharacteristic = pService->createCharacteristic(
                      CHARACTERISTIC_UUID_TX,
                      BLECharacteristic::PROPERTY_NOTIFY
                    );
                      
  pCharacteristic->addDescriptor(new BLE2902());

  BLECharacteristic *pCharacteristic = pService->createCharacteristic(
                                         CHARACTERISTIC_UUID_RX,
                                         BLECharacteristic::PROPERTY_WRITE
                                       );

  pCharacteristic->setCallbacks(new MyCallbacks());

  // Start the service
  pService->start();

  // Start advertising
  pServer->getAdvertising()->start();
  Serial.println("Waiting a client connection to notify...");
}

void loop() {
  if (deviceConnected) {
    // Fabricate some arbitrary junk for now...
    txValue = analogRead(readPin) / 3.456; // This could be an actual sensor reading!
    counter++;
    txValue = counter;
    // Let's convert the value to a char array:
    char txString[8]; // make sure this is big enuffz
    dtostrf(txValue, 1, 2, txString); // float_val, min_width, digits_after_decimal, char_buffer


    
//    pCharacteristic->setValue(&txValue, 1); // To send the integer value
//    pCharacteristic->setValue("Hello!"); // Sending a test message
    pCharacteristic->setValue(txString);
    
    pCharacteristic->notify(); // Send the value to the app!
    Serial.print("*** Sent Value: ");
    Serial.print(txString);
    Serial.println(" ***");
    showcommand (txString);
;
    
    // You can add the rxValue checks down here instead
    // if you set "rxValue" as a global var at the top!
    // Note you will have to delete "std::string" declaration
    // of "rxValue" in the callback function.
//    if (rxValue.find("A") != -1) { 
//      Serial.println("Turning ON!");
//      digitalWrite(LED, HIGH);
//    }
//    else if (rxValue.find("B") != -1) {
//      Serial.println("Turning OFF!");
//      digitalWrite(LED, LOW);
//    }
  }
  delay(500);
}

void showcommand(char *buf){
 //char cstr[rxValue1.size() + 1];

  //strcpy(cstr, rxValue1.c_str());  // or pass &s[0] 
     Serial.println(" Rx Value 1 ");  

     Serial.println (rxValue1.c_str());



    
    display.setColor(BLACK);  
    display.fillRect(0,32,100,16);
     display.setColor(WHITE);     
    display.drawString(0, 32, "TXED");
    display.drawString(60, 32, buf);

  

    display.setColor(BLACK);  
    display.fillRect(0,48,100,16);
     display.setColor(WHITE); 
     if (currentstate==true){
      display.drawString(0, 48, "ON");        
     }
     else
     {
      display.drawString(0, 48, "OFF");       
     }
  
    display.display();
  
}

I see you are using Neil Kolban code.

There are 4 hits on this board for Kolban.
They should be worth reading.

Hello rowifi

Ensure that your phone has Location switched on - this is a Google Security requirement and Bluetooth comms will not work without it.

I may be wrong but I think 'ConnectToDeviceWithServiceAndName' parameter 'name' would be the whole string representing the Device in the Device List - the idea being that the Device is selected via the Device List as a one-off task and there after you can store that List Item (name) in TinyDB and recall it for subsequent App sessions.

How did you obtain the Service UUID? Make sure you have the correct UUID and it is perfect (no typos, match the character case exactly).

Concerning the 'ConnectToDeviceType' Block, I have no idea what 'Device Type' actually means in the context of an AI component Block - the official MIT Help:
http://iot.appinventor.mit.edu/#/bluetoothle/bluetoothleintro
does not mention 'component':
ConnectToDeviceType - Connect to a given device type with a given name. Extensions that use BluetoothLE can leverage this API to simplify establishing a connection.

However the pop-up help of the Block itself does mention 'component', but really does not make any sense (not in English anyway!). I shall ask Evan Patton what he really means.

Edit:
The questions I have put to Evan:
Snap9
The device parameter
Should this be a text block containing the device's Service UUID? The term 'Device Type' is the confusing bit because it suggests that there may be a formal list of types to be referred to - but that is not the case?

The name parameter
Is this a name from the Device List (which could be/include the MAC address) and should it be the entire string of the List Item or only the name extracted from that string?

Let me just clarify.
The BLE module is an ESP32 and the code is posted above.
It provides serial Uart functionality and appears to work correctly because the nordic BLE app can see it and display it's properties and the data it sends out.

The appinventor code also works - to a degree in that it will send a command string when buttons are pressed and it also displays received data ( when that section of the app is enabled.)

The UUIDS and Device name are known and coded into the ESP32 and are used to get the appinventor code to connect successfully when done manually - using a selection from a list.

The permissions must therefore be ok for it to work.

To offer a demo app to a potential customer - I would like the app to do things automatically.
I already start scanning when the app is opened, but now I want it to connect automatically when it finds the known BLE target device. i.e to provide a seamless app that allows the user to turn something on and off without having to go through the manual scan and select process - ( ok for development but not great to show a customer ).

So it's currently the automatic connection to my known device that is not working. Neither using 'Connect to device type ' nor 'Connect using service UUID and name'
Both blocks cause the strange behaviour when added to the 'Device found' block.

Normally the Device found block executes a limited number of times - whenever a new device is found, and makes a ping sound ( for convenience and debug). So normally ( without the connection block included ) it pings a few times and stops. The manual select and connect subsequently works fine.

If either connect block is attached within the device found block, to facilitate an automatic connect, the pinging repeats indefinitely, which to me makes no logical sense regardless of whether the parameters are correct or not.

Correctly assumed I don't know much about the blocks at this point - I've copied much from examples, and what you're seeing is me using the lists and labels to see what is being placed in the variables and elements - as a debug and learning phase.
I'm only a day into playing - but am pleased to see how far I've got, but some of the battles at the moment are knowing if it's me or the tools that are buggy. :slight_smile:

Further experimenting..
I created a separate block that connects to a specific device when a button is pressed.
If the device is in the scanned list then it should connect, if not .. it won't.

What happens is that the app pings during scanning when devices are found and eventually stops pinging - even though the scanning is still active.
If, after that point the button is pressed to attempt a specific connection - the ping occurs again, and everytime the connect button is pressed.

I suspect that in the process of trying to connect, the block damages or deletes the data in the scanned list such that it is re-filled whenever the scan finds the 'new' devices again.

As to why it doesn't connect - that is still a mystery. But I'm convinced something untoward is happening to the device list.

You need to have a little 'If' test there, and use a stop scanning Block 'If' the required device is found (and thus is in the Device List).

This is how we did it before the new direct connect Blocks were added (Silent Device List pick using an 'If' test).

Your App might need a manual connection as a backup (which can be hidden unless required) and an ability to repeat the connection request (but never repeat accidently) because BT radio signals can suffer from interference, especially if the distance between the ESP32 and the phone nears the BT limit, but for other alien reasons too, such as temperature and obstacles (e.g. walls).

In your 'Device Found' Block, the List Picker is populated with the Device List, something we have all coded in a similar way - but I remember a recent(ish) remark by Evan where he suggested there was a flaw in this method as the Device List could be incomplete. Therefore, better to make a List (internal AI2 Block List) within a Clock Timer Block, then feed that List to the ListPicker (for manual Select) or pick from it (for auto Select), or indeed not have a List, just test for the Known Device.

This is causing me grief.
I can't iterate through the BLE 'devicelist' because it isn't a 'list' - The blocks don't connect.
I tried to make a new 'List' and add items from the BLE 'devicelist' whenever a device was found but failed.
I'd sooner not use a clock - - and still would need to do as above ( which I haven't worked out how).
Is there an example anywhere of achieving this since it would appear to be a reasonable thing to do instead of having the user keep pressing buttons.
And I'm still in the dark as to what's happening to the device list when I try to connect to a specific device.
Help appreciated BTW.

  • stop the scan sooner.

That depends on what devices might already exist in your customer's premises and all other circumstances that can affect the BT radio signal between your device and your App, but in ideal conditions you do not need a Device List at all because the "unknowns" are already known by you.

Let's wait for Evan's response concerning the direct connection Blocks. He is an extremely busy chap so patience is required.

First news snippet:

The 'ConnectToDeviceType' Block should not be used.

OK, I do not have confirmation as to what the Device Name should comprise in terms of what gets fed into the 'ConnectToDeviceWithServiceAndName' name parameter - should it be the whole device list item collected or should we extract the name from that list item.

If the mac address is to be used in other BLE Blocks, we are not required to extract that from the device list item, the Block function does that for us. So, I'm expecting the same kind of thing for device name, but awaiting Evan to confirm.

Concerning the UUID and Name - are those going to be identical for every customer or unique? That obviously affects how the App is coded. If values are identical for every customer, they can be hard-coded in the App (they can be encrypted if required but relying on Android security is reasonable in most cases). If however the values will be unique to each customer, the code will have to pick the values up first via the ESP32 BT advertising.