Connecting through Bluetooth BLE

Did you test with Companion or the APK?

I've only done the APK

Ask for permissions on Android 11+. Search the forum. I have posted several times on this topic.

You mean on the MIT App site or some other Android 11+ site?

So I just tested my code with the AI Companion and it works just fine. When I Scan for for devices I get all the devices I would expect and my Seeed. However it still does not work as a standalone APK.
I searched the MIT Forum for Anke and Android 11 and didn't see any hits.

Show here the code of the Arduino Sketch.

Juan,

It seems to be an issue with the APK version of the Inventor app. The app works when using companion but eventually I will want it to be a stand alone app.

Here is the arduino code though, it's been reduced to a pretty simple sample at this point as I was trying to figure out what the problem was.

#include <ArduinoBLE.h>

const int ledPin = LED_BUILTIN; // set ledPin to on-board LED
const int buttonPin = 3; // set buttonPin to digital pin 4
int led_st = 0, btn_st = 0;

BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic ledCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite | BLENotify);
// create button characteristic and allow remote device to get notifications
BLEByteCharacteristic buttonCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);

void setup() {
  Serial.begin(9600);
  while (!Serial);

  pinMode(ledPin, OUTPUT); // use the LED as an output
  pinMode(buttonPin, INPUT_PULLUP); // use button pin as an input

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting Bluetooth® Low Energy module failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("ButtonLED");
  // set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(ledService);

  // add the characteristics to the service
  ledService.addCharacteristic(ledCharacteristic);
  ledService.addCharacteristic(buttonCharacteristic);

  // add the service
  BLE.addService(ledService);

  ledCharacteristic.writeValue(led_st);
  buttonCharacteristic.writeValue(btn_st);

  // start advertising
  BLE.advertise();

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

void loop() {
  // poll for Bluetooth® Low Energy events
  BLE.poll();

  // read the current button pin state
  if(digitalRead(buttonPin) != btn_st)
  {
    btn_st = !btn_st;
    Serial.println(btn_st);
    buttonCharacteristic.writeValue(btn_st);
  }

  if (ledCharacteristic.written())
  {
    Serial.print("ledCharacteristic = ");
    Serial.println(ledCharacteristic.value());
    
    // update LED, either central has written to characteristic or button state has changed
    if (ledCharacteristic.value()) {
      Serial.println("LED on");
      digitalWrite(ledPin, HIGH);
    } else {
      Serial.println("LED off");
      digitalWrite(ledPin, LOW);
    }
  }
}

For example:

So I tried the app you shared. It worked and the permissions aren't an issue.
I'm still not able to send info from my AI App to my arduino sketch. The data can be shared through the nRF app, so the Arduino sketch is working as expected. I'm really at a loss for what I'm doing wrong on the AI app.

Just sharing again in case anyone sees a glaring error.
I thought the problem might have been how I was sending the character. So I've tried different blocks in the "when LED_On.Click of sending WriteBytes, WriteInteger, Writetext and they all react the same way in that nothing seems to get sent.

#include <ArduinoBLE.h>

unsigned long previousMillis = 0;        // will store last time LED was updated
const long interval = 1000;           // interval at which to blink (milliseconds)

const int ledPin = LED_BUILTIN; // set ledPin to on-board LED
const int buttonPin = 3; // set buttonPin to digital pin 4
int LED_st = 0, btn_st = 0;
unsigned long currentMillis;
    
BLEService ledService("19B10010-E8F2-537E-4F6C-D104768A1214"); // create service

// create switch characteristic and allow remote device to read and write
BLEByteCharacteristic ledCharacteristic("19B10011-E8F2-537E-4F6C-D104768A1214", BLERead | BLEWrite | BLENotify);
// create button characteristic and allow remote device to get notifications
BLEByteCharacteristic buttonCharacteristic("19B10012-E8F2-537E-4F6C-D104768A1214", BLERead | BLENotify);

void blePeripheralConnectHandler(BLEDevice central) {
  // central connected event handler
  Serial.println();
  Serial.print("Connected event, central: ");
  Serial.println(BLE.address());
}

void setup() {
  Serial.begin(9600);
  while (!Serial);

  pinMode(ledPin, OUTPUT); // use the LED as an output
  pinMode(buttonPin, INPUT_PULLUP); // use button pin as an input

  // begin initialization
  if (!BLE.begin()) {
    Serial.println("starting Bluetooth® Low Energy module failed!");

    while (1);
  }

  // set the local name peripheral advertises
  BLE.setLocalName("ButtonLED");
  // set the UUID for the service this peripheral advertises:
  BLE.setAdvertisedService(ledService);
 BLE.setEventHandler(BLEConnected, blePeripheralConnectHandler);
 
  // add the characteristics to the service
  ledService.addCharacteristic(ledCharacteristic);
  ledService.addCharacteristic(buttonCharacteristic);

  // add the service
  BLE.addService(ledService);

  ledCharacteristic.writeValue(LED_st);
  buttonCharacteristic.writeValue(btn_st);

  // start advertising
  BLE.advertise();

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

  while(!BLE.connected())   // just wait here until a connection is established
  {
    currentMillis = millis();

    if (currentMillis - previousMillis >= interval) {
      // save the last time you blinked the LED
      previousMillis = currentMillis;

      Serial.print(".");
    }
  }
}

void loop() {
  // poll for Bluetooth® Low Energy events
  BLE.poll();

  // read the current button pin state
  if(digitalRead(buttonPin) != btn_st)
  {
    btn_st = !btn_st;
    Serial.println(btn_st);
    buttonCharacteristic.writeValue(btn_st);
  }

  currentMillis = millis();

  if (currentMillis - previousMillis >= interval) {
    // save the last time you blinked the LED
    previousMillis = currentMillis;
  
    Serial.print(ledCharacteristic.value());  Serial.print("\t"); Serial.println(LED_st);
  }

  // update LED, either central has written to characteristic or button state has changed
  if(ledCharacteristic.value() != LED_st)
    if (ledCharacteristic.value()) {
      Serial.print("ledCharacteristic = ");
      Serial.println(ledCharacteristic.value());
      Serial.println("LED on");
      digitalWrite(ledPin, HIGH);
      LED_st = 1;
    } else {
      Serial.print("ledCharacteristic = ");
      Serial.println(ledCharacteristic.value());
      Serial.println("LED off");
      digitalWrite(ledPin, LOW);
      LED_st = 0;
    }
}

So I finally got my test app to work and send data to my arduino. I had to use a "BluetoothLE1.WriteIntegersWithResponse" and I'm not sure why. What is the difference between with and without the ...WithResponse part?

1 Like

See the documentation MIT App Inventor + Internet of Things

WriteIntegersWithResponse – Writes one or more 32-bit integer values to a connected BluetoothLE device and waits for an acknowledgement via the IntegersWritten event

Taifun

The documentation doesn't help explain why my App would actually send the data with the ...WithResponse and it doesn't send the data when it's just WriteIntegers. I don't even use the IntegersWritten event in my app but yet the WriteIntegersWithResponse still sends the data.

I posted this earlier but didn't see it on the forum, sorry if it's a repeat post.

I have my app doing mostly what I want. One thing I would like to do is determine which characteristic is sending short data when shorts are received. So I though an if...then would be the right thing to do. You can see in the lower right corner that I'm receiving shorts and then I try to determine which Characteristic is sending the shorts. Then I want to handle the data appropriately based on the Characteristic. When I put a logic true in the if..then it works but when I put the "get .... = get ...." if seems the comparison isn't done.

Am I even approaching this correctly or doing something wrong with my interpretation of how App Inventor works?

I merged your topics together.

Why? They are two different problems and the first was never really answered.

Well, you are using a Logic comparison when the Characteristics are strings, so normally a string comparison would be performed using a 'compare texts' Block.

The logic comparison does work on strings, though I suppose it is technically correct.
I did solve the issue though. When I initialized the global parameter, I used all upper case letters and the characteristic UUID returned by the function is in all lower case letters. I believe I saw this in a different thread somewhere and didn't think it applied to my case for some reason.

....had you used the text compare in the same format as you used Logic, that difference would have been flagged.

To avoid the issue with any external device, simply use the Text Block 'upcase' on both characteristics in the compare:

Snap4

I'm not sure what you mean the difference would have been flagged. How would it be flagged? I didn't see a warning or anything pop up, it just followed the comparison and the two strings weren't the same since one had upper and one lower.
I have switched the code to use all lower case in my gloabal declarations and included "downcase" before each characteristic get call.

This topic was automatically closed 7 days after the last reply. New replies are no longer allowed.