App is losing BT connection to HC-05, but BT will maintain a stable connection to BT Serial Terminal

Another smart thermostat post (minor twist is that it's for a hydronic in-floor heating pump) with another BT problem. Not novel I know, but I've done my best troubleshooting and think it must be down to App BT connection stability.

I've been poring through similar posts for a few days, and finally decided to make a new one. As the title says I can connect through BT to the app send and receive signals no problem, but the app will report a 516 between 10-60 seconds later. I cannot find rhyme or reason based on button use(input) frequency. I finally connected the BT to the laptop using Windows Bluetooth Serial Terminal, and this will stay connected indefinitely, which leads me to believe it is not a power issue cycling the HC-05 or a code issue doing the same. However my block code for the app is quite simple, so I need some expert advice to help solve this one.

#include <SimpleDHT.h>
#include <SoftwareSerial.h>

#define DHTPIN 3 // Digital pin connected to the DHT sensor
#define RELAYCONTROL 9 // active low, first stage relay

SimpleDHT11 dht11;

int currenttemp = 0;
int TargetTemp = 30;
char Incoming_value = 0;

SoftwareSerial BTModule(7, 8); // RX | TX

void MasterControlON()
{
digitalWrite(RELAYCONTROL, HIGH);
}

void MasterControlOFF()
{
digitalWrite(RELAYCONTROL, LOW);
}

void TemperatureControl()
{

if(currenttemp <= TargetTemp)
digitalWrite(RELAYCONTROL, LOW); // Active Low Switch = ON
else
digitalWrite(RELAYCONTROL, HIGH); // Active Low Switch = off
}

void StatusCheck() // Command 2 from BT App
{
byte temperature = 0;
byte humidity = 0;
String report; //concatenated result of temp & humidity for display purposes on app
String PumpS; // checks pin status for reporting pump state to app

if (dht11.read(DHTPIN, &temperature, &humidity, NULL))
{
return;
}
// Report to Serial:
Serial.print((int)temperature);
Serial.print(" C");
Serial.print("|");
Serial.print((int)humidity);
Serial.println(" %");

// Report to App
if(digitalRead(RELAYCONTROL) == HIGH)
PumpS = "On";
if(digitalRead(RELAYCONTROL) == LOW)
PumpS = "Off";

report = (String) temperature + "," + (String) humidity + "," + PumpS + "," + (String) TargetTemp;
BTModule.println(report); // send concatenated report, split in app for display

}

void SetTemp()
{
TargetTemp = BTModule.read(); // this function is still WIP
}

void setup()
{
pinMode(RELAYCONTROL, OUTPUT); // Relay Pump Control
digitalWrite(RELAYCONTROL, HIGH);

BTModule.begin(9600); // HC-05
Serial.begin(9600); // For DHT & Serial Monitor

}

void loop()
{

// App Controls
if(BTModule.available() > 0)
{
Incoming_value = BTModule.read();

Serial.print(Incoming_value);        // report latest command to Serial Monitor
Serial.print("\n");  
      
if(Incoming_value == '1')             
   MasterControlON();
else if(Incoming_value == '0')       
  MasterControlOFF(); 
else if(Incoming_value == '2')
  StatusCheck();
else if(Incoming_value == '3')
  SetTemp();

}

}

Thermostat_copy(1).aia (3.4 KB)

You'r blocks to receive text should be ONLY in a fast Clock Timer event, guarded by a check for Bytes Available > 0.

Putting them in Button Click events presumes incoming data is immediately available after sending a command.

If you need to interpret incoming data differently based on what command was just sent, keep a record of that and check it in the Clock Timer.

Your blocks and Clock (too slow):


Screenshot 2022-02-26 194915

Standard BT Delimiter advice:

Please see the Delimiter article in FAQ

Be sure to use println() at the end of each message to send from the sending device, to signal end of message. Do not rely on timing for this, which is unreliable.

In the AI2 Designer, set the Delimiter attribute of the BlueTooth Client component to 10 to recognize the End of Line character.
BlueToothClient1_Properties
Also, return data is not immediately available after sending a request,
you have to start a Clock Timer repeating and watch for its arrival in the Clock Timer event. The repeat rate of the Clock Timer should be faster than the transmission rate in the sending device, to not flood the AI2 buffers.

In your Clock Timer, you should check

  Is the BlueTooth Client still Connected?
  Is Bytes Available > 0?
     IF Bytes Available > 0 THEN
       set message var  to BT.ReceiveText(-1) 

This takes advantage of a special case in the ReceiveText block:

ReceiveText(numberOfBytes)
Receive text from the connected Bluetooth device. If numberOfBytes is less than 0, read until a delimiter byte value is received.

If you are sending multiple data values per message separated by | or comma, have your message split into a local or global variable for inspection before trying to select list items from it. Test if (length of list(split list result) >= expected list length) before doing any select list item operations, to avoid taking a long walk on a short pier. This bulletproofing is necessary in case your sending device sneaks in some commentary messages with the data values.