Problem with receiving text from bluetooth module (HC-05)

Greetings, I have built an arduino based medicine dispenser with servo motor. The keypad is used to key in the password and LCD to display the condition of the system. The problem I am facing right now is I can't seem to send the text "access granted" which is prompted when users input in the password for this system to the app as I want it to be displayed on the app. Can someone highlight this issue as I'm not that familiar with MIT app inventor,
Much appreciated

lol1

#include <Keypad.h>
#include <Servo.h>
#include <Wire.h>
#include <LiquidCrystal_I2C.h>
#include <HardwareSerial.h>

// Define LCD address and pins
#define LCD_ADDRESS 0x27
#define GREENLED_PIN PB5
#define REDLED_PIN PB10
#define SERVO_PIN PA11
#define IRSENSOR_PIN PA12 // IR sensor pin

// Bluetooth module RX and TX pins
HardwareSerial Bluetooth(PA10, PA9);

// Create LCD object
LiquidCrystal_I2C lcd(LCD_ADDRESS, 16, 2);
Servo myServo;

// Define keypad rows and columns
const byte ROWS = 4;
const byte COLS = 3;

// Keypad layout
char keys[ROWS][COLS] = {
  {'1', '2', '3'},
  {'4', '5', '6'},
  {'7', '8', '9'},
  {'*', '0', '#'}
};

// Pin connections for keypad
byte rowPins[ROWS] = {PA5, PA6, PA7, PA8};
byte colPins[COLS] = {PC7, PB6, PB4};

// Create keypad object
Keypad keypad = Keypad(makeKeymap(keys), rowPins, colPins, ROWS, COLS);

// Define the correct password
String correctPassword = "28";
String enteredPassword = "";

// Servo control variables
int angle = 0;                  // Current angle of the servo
int angleIncrement = 60;        // Increment angle (60° for 3 compartments)

void setup() {

  // Initialize serial communication
  Serial.begin(9600);
  Bluetooth.begin(9600);

  // Initialize the LCD
  Wire.begin(PB9, PB8);
  lcd.begin(16, 2);
  lcd.init();
  lcd.backlight();

  // Display welcome message
  lcd.clear();
  lcd.setCursor(3, 0);
  lcd.print("Welcome to");
  lcd.setCursor(3, 1);
  lcd.print("Medspenser");
  delay(5000);

  // Check for medicine and show the appropriate message
  checkMedicineAvailability();

  // Initialize LEDs, servo, and IR sensor
  pinMode(GREENLED_PIN, OUTPUT);
  pinMode(REDLED_PIN, OUTPUT);
  pinMode(IRSENSOR_PIN, INPUT);
  myServo.attach(SERVO_PIN);
  myServo.write(angle); // Start at initial angle

  // Turn off LEDs initially
  digitalWrite(GREENLED_PIN, LOW);
  digitalWrite(REDLED_PIN, LOW);
}

void loop() {
  if (digitalRead(IRSENSOR_PIN) == HIGH) {
    // Medicine is not available
    //Bluetooth.print(mnr);  // Send "medicine not ready" status
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Needs to be");
    lcd.setCursor(0, 1);
    lcd.print("refilled");
    delay(3000);

    while (digitalRead(IRSENSOR_PIN) == HIGH) {
      delay(500); // Delay before checking again
      checkMedicineAvailability();
    }

    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Enter Password:");
  }

  char key = keypad.getKey();
 

  if (key) {
    if (key == '0') {
      // Check the entered password
      if (enteredPassword == correctPassword) {
        rotateServo(); // Rotate servo if the password is correct
      } else {
        lcd.clear();
        lcd.setCursor(0, 0);
        lcd.print("Wrong password!");
        digitalWrite(REDLED_PIN, HIGH); // Indicate error
        delay(2000);
        digitalWrite(REDLED_PIN, LOW);
        resetSystem();
      }
    } else if (key == '*') {
      // Reset input
      resetSystem();
    } else {
      // Append key to password
      enteredPassword += key;
      lcd.setCursor(0, 1);
      lcd.print(enteredPassword);
    }
  }
}

void checkMedicineAvailability() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Checking for");
  lcd.setCursor(0, 1);
  lcd.print("medicine...");
  delay(5000);

  if (digitalRead(IRSENSOR_PIN) == HIGH) {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Medicine is not");
    lcd.setCursor(0, 1);
    lcd.print("available");
    delay(2000);
  } else {
    lcd.clear();
    lcd.setCursor(0, 0);
    lcd.print("Medicine is");
    lcd.setCursor(0, 1);
    lcd.print("available");
    delay(2000);
    resetSystem();
  }
}

void rotateServo() {
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Access granted!");
  
  // Increment angle and check if it exceeds 180°
  int newAngle = angle + angleIncrement;

  if (newAngle <= 180) {
    // Rotate to new angle
    while (angle < newAngle) {
      angle += 1;
      myServo.write(angle);
      delay(20); // Smooth rotation
    }

  } else {
    // Reset to 0° if angle exceeds 180°
    while (angle > 0) {
      angle -= 1;
      myServo.write(angle);
      delay(20);
    }
    angle = 0;

  }

  // Indicate success
  digitalWrite(GREENLED_PIN, HIGH);
  delay(3000);
  digitalWrite(GREENLED_PIN, LOW);
  resetSystem();
}

void resetSystem() {
  enteredPassword = "";
  lcd.clear();
  lcd.setCursor(0, 0);
  lcd.print("Enter Password:");
  digitalWrite(GREENLED_PIN, LOW);
  digitalWrite(REDLED_PIN, LOW);
  myServo.write(angle);
}




There are a lot of bits and pieces in your App Inventor code that are wrong or not advisable. If you are going to use Label2 to display received data, that's fine, but use a separate label for messages such as "Access Granted", "Connected" etc.

BytesAvailableToReceive is a flag, use this to get all available bytes:

NumberOfBytes

If the data should arrive as list, check that it has before trying to select from it.

Here is a "bare Bones" Project which should show you what you are missing.

BT_Basic_Setup_Receive_two_vals.aia (7.7 KB)

In your Sketch you have a number of delay(). When you use delay() everything is stopped and that can have a detrimental effect on things like accuracy. I think most of your use of delay() is probably unnecessary, but if there is an occasion where you need a delay, use elapsed milliseconds instead:


//Fake data stream to demo elapsed milliseconds timing


//vars
unsigned long lgUpdateTime;

void setup()
{
               Serial.begin(9600);
               lgUpdateTime = millis();
}

void loop()
{
	           if(millis() - lgUpdateTime > 1000)           //Loop approx every 1 second
               {
                         lgUpdateTime = millis();

                         //Bluetooth to App
                         Serial.print("Hello");
                         Serial.print("|");      //Value delimiter
                         Serial.print("World");
                         Serial.print("|");
                         Serial.println();        //This empty last line tells App "End of Data" = Ascii LineFeed Char Number 10
               }
}

Now, concerning the sending of the message about the password by the Arduino to your App. It's not a List and so shouldn't be handled as such in the App and secondly it is better to send a single char and let the App worry about presenting the whole message. Your code seems to be getting the dispensing of medicine and the confirmation of the password tangled.

  1. Deal with the password first.
  2. If the pass is correct, allow the medicine functions to run.

You have named your Hardware Serial as "Bluetooth", so that should be the communication with the App:

                         //Bluetooth to App
                         Bluetooth.print("A");
                         Bluetooth.println(); //This empty last line tells App "End of Data" = Ascii LineFeed Char Number 10

Re end of data, see the example App Inventor Project 'Delimiter Byte'.