Please be gentle, I'm still fairly new at this and I'm sure my code is a mess.
As part of a crop pest research project I'm attempting to build an inexpensive environmental condition datalogger that can collect data from a site and dump the log file to my phone once a week (sites are 2.5 hrs from WiFi, but will visit them weekly). Ideally I'd like to avoid deconstructing the logger each week to remove the SD card, and was hoping to use its BLE function to gather each week's log file instead. However, I'm having a lot of trouble figuring out how exactly to send and receive said file, and am starting to wonder whether it's a lost cause.
From what I've gathered BLE is limited in comparison to classic Bluetooth and can only send information in relatively small packets, meaning that I may need to somehow compress my data into a smaller format before sending it, but I can't figure out how to adapt the protocols that I've seen involving strings to something like the .csv file that my setup would produce.
I've spent some time looking around at source documents, references, and similar projects, but much of the information I've found either died years ago, includes solutions that refer to broken links (@Nick_Pyner , do you happen to still have a link to your "Bluetooth graphic file retrieval" code?), describes limited functions that I can't figure out how to adapt to larger files, uses different systems that I don't know how to decipher, or even describes almost exactly what I hope to accomplish but in reverse! (and I can't figure out how you'd go about sending it the other way!)
I'm stuck!
My Setup:
- Arduino Explore IoT kit, including MKR WiFi 1010 board and MKR IoT Carrier
- Android phone using lightBlue as a BLE monitor
My Code:
I've trimmed out any of the carrier-centric display, sensor gathering, clock setting, calibration stuff and left in the SD file creation / validation stuff, as well as anything BLE related.
#include <SPI.h>
#include <SD.h>
#include <Arduino_MKRIoTCarrier.h>
MKRIoTCarrier carrier;
#include <ArduinoBLE.h>
BLEService newService("180A");
BLEStringCharacteristic logFileCharacteristic("2A56", BLERead | BLEWrite, 20);
String fileName = "";
File logFile; //the function used to store our sensor data is named logFile
char logFileName[13] = "a-000000.csv"; // data log file Name
char device_Name[] = "Logger-01";
long previousMillis = 0;
//------------------------ END OF INITIALIZATION ---------------------------
void setup() {
CARRIER_CASE = false;
carrier.begin();
Serial.begin(9600);
while (!Serial); // wait for user to open the serial monitor
Serial.print(device_Name);
Serial.println(" Environmental Data Logger Debug");
Serial.println();
// check the SD card
if (!SD.begin(SD_CS)) {
Serial.println("SD Card initialization failed!");
while (1);
} else {
Serial.println("SD Card found");
}
logFile = SD.open(logFileName, FILE_WRITE); // the name of the file is defined by the logFileName function
if (logFileName) {
logFile.println("Epoch, day, month, year, hour, minute, second, temperature, humidity, pressure, light, Gx, Gy, Gz, Ax, Ay, Az, soil moisture");
logFile.close();
Serial.print("File initialized! Name used: ");
Serial.println(logFileName);
}
else {
Serial.print("Failed to create / open / write to file:");
Serial.println(logFileName);
}
if (SD.exists(logFileName)) { // verify logFileName file creation
Serial.print(logFileName);
Serial.println(" exists.");
} else {
Serial.print(logFileName);
Serial.println(" doesn't exist.");
}
logFile = SD.open(logFileName); // open the logFileName file for a read test
if (logFileName) { // verify contents of logFileName
Serial.print("File opened! Contents of: ");
Serial.println(logFileName);
while (logFile.available()) {
Serial.write(logFile.read());
}
logFile.close();
}
else {
Serial.print("Failed to read file:");
Serial.println(logFileName);
}
Serial.println("BLE Initializing...");
if (!BLE.begin()) { // Try to initialize BLE
Serial.println("Terminal Error: Could not start BLE!");
while (1);
}
BLE.setDeviceName(device_Name); // set advertised device / local name
BLE.setLocalName(device_Name);
BLE.setAdvertisedService(newService);
newService.addCharacteristic(logFileCharacteristic); // add characteristics
BLE.addService(newService);
logFileCharacteristic.writeValue(fileName); // set initial value for characteristic
BLE.advertise();
Serial.print("Device name: ");
Serial.println(device_Name);
Serial.println("Bluetooth device active, waiting for connections...");
}
//----------------------- END OF VOID SETUP --------------------------
void loop() {
BLEDevice central = BLE.central();
if (central)
{
Serial.print("Connected to central: ");
Serial.println(central.address());
while (central.connected())
{
logFile = SD.open(logFileName);
if(logFileCharacteristic.written())
{
while(logFile.available())
{
logFile.read();
fileName = logFileCharacteristic.value();
}
}
}
Serial.print("Disconnected from central: ");
Serial.println(central.address());
}
}
// ----------------------- End of Code ------------------------
The majority of the above code is an amalgamation from multiple sources, so I'm sure that some of it is backwards, out of order, or otherwise wrong (and I would greatly appreciate any advice on how to improve it!), but what I mainly need help with is:
a) How do I format (or process using a protocol) the file "a-000000.csv" so that it can be transmitted via BLE? Is a 20-length string the right idea? Would a different approach be better? Examples would be really helpful!
b) What do I do on the other side of the BLE monitor (when reading the file presented by the logger) to save it as a usable .csv file? Is lightBlue suitable for this purpose or will I likely need to use something else?
If you've read this far, thanks for taking the time to do so! I'd appreciate any helpful advice or comments about this issue - been banging my head against it for a while now, would really like to know whether it's possible and, if so, which method or protocol would best fit this application.