Hey yall,
I am trying to create an app that has Bluetooth using the Thunkable website. I am using the Arduino MKR Wifi 1010 which supports BLE. I am using Modbus to gather data from a battery charger, and I am trying to send it via Bluetooth to the app. My problem is that when I try and connect to my app via Bluetooth it takes 35-40 seconds to connect. After it connects, my data shows up but also takes 5-10 seconds to appear. Is there any way to make this faster? I will attach my code below. It is quite long but a majority of the code is just Modbus data collection. If there are any other pictures or documents you need me to attach, please let me know!
#include <ArduinoRS485.h>
#include <ArduinoModbus.h>
#include <ArduinoBLE.h>
BLEService heliosService("180F"); // creating the service
BLECharacteristic batteryPercentageChar("00002A19-0000-1000-8000-00805F9B34FB", BLERead, 20);
BLECharacteristic batteryVoltageChar("00002A1C-0000-1000-8000-00805F9B34FB", BLERead, 20);
BLECharacteristic batteryTemperatureChar("00002A1B-0000-1000-8000-00805F9B34FB", BLERead, 20);
long previousMillis = 0;
// Variables
int batteryPercentage = 0;
float batteryVoltage = 0;
float batteryAmperage = 0;
float batteryTemperature = 0.00;
float batteryPower = 0;
float batteryCapacity = 0;
float batteryRuntime = 0;
int batteryType = 0;
float solarVoltage = 0;
float solarAmperage = 0;
float solarPower = 0;
float batteryMinVoltage = 0;
float batteryMaxVoltage = 0;
float inverterVoltage = 0;
float inverterAmperage = 0;
float inverterPower = 0;
float inverterInputAmperage = 0;
float inverterInputVoltage = 0;
float inverterInputPower = 0;
// Battery Registers
const int modbusSlaveAddress = 1; // Replace with the Modbus slave address of your DCC Charger Controller
const int modbusInverterAddress = 2;
const int batteryPercentageRegister = 0x0100; // register address for battery percentage
const int batteryVoltageRegister = 0x0101; // register address for battery voltage
const int batteryAmpsRegister = 0x0102; // register address for battery charging current
const int batteryTempRegister = 0x0103; // register address for battery temperature
const int batteryCapacityRegister = 0xE002; // register address for battery capacity
const int batteryTypeRegister = 0xE004; // register address for battery type
// Solar Panel Registers
const int solarVoltageRegister = 0x0107; // register addresss for solar panel voltage
const int solarAmpsRegister = 0x0108; // register address for solar panel current
const int solarPowerRegister = 0x0109; // register address for solar panel power
// Battery Check Registers
const int batteryMinVoltageRegister = 0x010B; // register address for minimum battery voltage for the day
const int batteryMaxVoltageRegister = 0x010C; // register address for maximum battery volatage for the day
// Inverter Registers
const int inverterVoltageRegister = 4002; // register address for inverter output voltage
const int inverterInputVoltageRegister = 4000; // register address for inverter output voltage
const int inverterInputAmpsRegister = 4001; // register address for inverter output voltage
const int inverterAmpsRegister = 4003; // register address for inverter output current
void setup() {
// Start the serial ports
Serial.begin(9600);
Serial1.begin(9600); // Start serial communication with the Nextion display
if (!BLE.begin()) {
Serial.println("starting Bluetooth® Low Energy failed!");
}
// Start the Modbus client
if (!ModbusRTUClient.begin(9600)) {
Serial.println("Failed to start Modbus RTU Client!");
}
BLE.setLocalName("Helios"); //Setting a name that will appear when scanning for Bluetooth® devices
BLE.setAdvertisedService(heliosService);
// Add characteristics to the service
heliosService.addCharacteristic(batteryPercentageChar);
heliosService.addCharacteristic(batteryVoltageChar);
heliosService.addCharacteristic(batteryTemperatureChar);
BLE.addService(heliosService); // adding the service
BLE.advertise(); //start advertising the service
Serial.println(" Bluetooth® device active, waiting for connections...");
}
void loop() {
BLEDevice central = BLE.central(); // wait for a Bluetooth® Low Energy central
if (central) { // if a central is connected to the peripheral
Serial.print("Connected to central: ");
Serial.println(central.address()); // print the central's BT address
while (central.connected()) {
long currentMillis = millis();
if (currentMillis - previousMillis >= 200) { // if 200ms have passed, we check the battery level
previousMillis = currentMillis;
// Convert to strings
String percentageStr = String(batteryPercentage);
String voltageStr = String(batteryVoltage, 2); // Two decimal places
String temperatureStr = String((batteryTemperature/1000),2);
// Write data to characteristics
batteryPercentageChar.writeValue(percentageStr.c_str());
batteryVoltageChar.writeValue(voltageStr.c_str());
batteryTemperatureChar.writeValue(temperatureStr.c_str());
}
readModbusData();
delay(100);
}
}
Serial.print("Disconnected from central: ");
Serial.println(central.address());
}
readModbusData();
}
void readModbusData() {
// Read Inverter Output Voltage
if (!ModbusRTUClient.requestFrom(modbusInverterAddress, HOLDING_REGISTERS, inverterVoltageRegister, 1)) {
Serial.print("Failed to read Inverter voltage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
inverterVoltage = ModbusRTUClient.read();
Serial.print("Inverter Voltage: ");
Serial.print(inverterVoltage * 0.1); // Assuming the value is in decivolts
Serial.println("V");
}
// Read Inverter Input Voltage
if (!ModbusRTUClient.requestFrom(modbusInverterAddress, HOLDING_REGISTERS, inverterInputVoltageRegister, 1)) {
Serial.print("Failed to read Inverter Input voltage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
inverterInputVoltage = ModbusRTUClient.read();
Serial.print("Inverter Input Voltage: ");
Serial.print(inverterInputVoltage * 0.1); // Assuming the value is in decivolts
Serial.println("V");
}
// Read Inverter Input Current
if (!ModbusRTUClient.requestFrom(modbusInverterAddress, HOLDING_REGISTERS, inverterInputAmpsRegister, 1)) {
Serial.print("Failed to read Inverter input amperage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
inverterInputAmperage = ModbusRTUClient.read();
Serial.print("Inverter Amperage: ");
Serial.print(inverterInputAmperage*0.01); // Assuming the value is in deciamps
Serial.println("A");
}
// Read Inverter Output Current
if (!ModbusRTUClient.requestFrom(modbusInverterAddress, HOLDING_REGISTERS, inverterAmpsRegister, 1)) {
Serial.print("Failed to read Inverter amperage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
inverterAmperage = ModbusRTUClient.read();
Serial.print("Inverter Amperage: ");
Serial.print(inverterAmperage*0.01); // Assuming the value is in deciamps
Serial.println("A");
}
inverterPower = (inverterVoltage*0.1) * (inverterAmperage*0.01);
Serial.print("Inverter Output Power: ");
Serial.print(inverterPower);
Serial.println("W");
inverterInputPower = (inverterInputVoltage*0.1) * (inverterInputAmperage*0.01);
Serial.print("Inverter Input Power: ");
Serial.print(inverterInputPower);
Serial.println("W");
// For some reason the next sensor read after the Inverter readings fails!! This Sensor read is a place holder and will fail to read. This is good and will not show in the serial monitor
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, 0x0104, 1)) {
} else {
batteryVoltage = ModbusRTUClient.read();
}
//Read battery percentage
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, batteryPercentageRegister, 1)) {
Serial.print("Failed to read battery percentage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
batteryPercentage = ModbusRTUClient.read();
Serial.print("Battery Percentage: ");
Serial.print(batteryPercentage);
Serial.println("%");
}
// Read battery voltage
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, batteryVoltageRegister, 1)) {
Serial.print("Failed to read battery voltage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
batteryVoltage = ModbusRTUClient.read();
Serial.print("Battery Voltage: ");
Serial.print(batteryVoltage * 0.1); // Assuming the value is in decivolts
Serial.println("V");
}
// Read battery amperage
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, batteryAmpsRegister, 1)) {
Serial.print("Failed to read battery amperage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
batteryAmperage = ModbusRTUClient.read();
Serial.print("Battery Amperage: ");
Serial.print(batteryAmperage*0.01); // Assuming the value is in deciamps
Serial.println("A");
}
// Read battery temperature
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, batteryTempRegister, 1)) {
Serial.print("Failed to read battery temperature! ");
Serial.println(ModbusRTUClient.lastError());
} else {
batteryTemperature = ((ModbusRTUClient.read()*1.8)+32);
Serial.print("Battery Temperature: ");
Serial.print(batteryTemperature/1000); // Assuming the value is in deci-degrees Celsius
Serial.println("°F");
}
// Read Solar Panel Voltage
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, solarVoltageRegister, 1)) {
Serial.print("Failed to read Solar voltage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
solarVoltage = ModbusRTUClient.read();
Serial.print("Solar Voltage: ");
Serial.print(solarVoltage * 0.1); // Assuming the value is in decivolts
Serial.println("V");
}
// Read Solar Panel Current
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, solarAmpsRegister, 1)) {
Serial.print("Failed to read Solar amperage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
solarAmperage = ModbusRTUClient.read();
Serial.print("Solar Amperage: ");
Serial.print(solarAmperage*0.01); // Assuming the value is in deciamps
Serial.println("A");
}
// Read Solar Panel Power
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, solarPowerRegister, 1)) {
Serial.print("Failed to read Solar Power! ");
Serial.println(ModbusRTUClient.lastError());
} else {
solarPower = ModbusRTUClient.read();
Serial.print("Solar Power: ");
Serial.print(solarPower); // Assuming the value is in deciamps
Serial.println("W");
}
// Read Minimum Battery Voltage for the day
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, batteryMinVoltageRegister, 1)) {
Serial.print("Failed to read Minimum Battery Voltage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
batteryMinVoltage = ModbusRTUClient.read();
Serial.print("Min Battery Voltage: ");
Serial.print(batteryMinVoltage); // Assuming the value is in deciamps
Serial.println("V");
}
// Read Maximum Battery Voltage for the day
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, batteryMaxVoltageRegister, 1)) {
Serial.print("Failed to read Maximum Battery Voltage! ");
Serial.println(ModbusRTUClient.lastError());
} else {
batteryMaxVoltage = ModbusRTUClient.read();
Serial.print("Max Battery Voltage: ");
Serial.print(batteryMaxVoltage); // Assuming the value is in deciamps
Serial.println("V");
}
//Read battery type
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, batteryTypeRegister, 1)) {
Serial.print("Failed to read battery type! ");
Serial.println(ModbusRTUClient.lastError());
} else {
batteryType = ModbusRTUClient.read();
if (batteryType == 1) {
Serial.print("Battery Type: ");
Serial.println("FLD");
} if (batteryType == 2) {
Serial.print("Battery Type: ");
Serial.println("SLA");
} if (batteryType == 3) {
Serial.print("Battery Type: ");
Serial.println("GEL");
} if (batteryType == 4) {
Serial.print("Battery Type: ");
Serial.println("Lithium");
} if (batteryType == 5) {
Serial.print("Battery Type: ");
Serial.println("Custom");
}
}
batteryPower = (batteryVoltage*0.1) * (batteryAmperage*0.01);
Serial.print("Battery Power:");
Serial.print(batteryPower);
Serial.println("W");
// Read Battery Capacity
if (!ModbusRTUClient.requestFrom(modbusSlaveAddress, HOLDING_REGISTERS, batteryCapacityRegister, 1)) {
Serial.print("Failed to read Battery Capacity! ");
Serial.println(ModbusRTUClient.lastError());
} else {
batteryCapacity = ModbusRTUClient.read();
Serial.print("Battery Capacity: ");
Serial.print(batteryCapacity); // Assuming the value is in deciamps
Serial.println("AH");
}
batteryRuntime = (batteryCapacity*batteryPercentage*batteryVoltage*0.5*0.9)/(10*100*(1 + inverterPower));
Serial.print("Battery Runtime: ");
Serial.print(batteryRuntime);
Serial.println("hours");
}