Thanks, all - that’s exactly what I was looking for! In case it’s helpful to others, here is my routine as a snippet.
I’m reading a 2-column CSV from the SD card where column 0 is a string label and column 1 is a float value.
//
// Reading from a CSV stored on the SD card
// File structure in this example is 2 columns: String,Float
//
File file;
//from https://arduino.stackexchange.com/a/1237
String explode(String data, char separator, int index)
{
int found = 0;
int strIndex[] = { 0, -1 };
int maxIndex = data.length() - 1;
for (int i = 0; i <= maxIndex && found <= index; i++) {
if (data.charAt(i) == separator || i == maxIndex) {
found++;
strIndex[0] = strIndex[1] + 1;
strIndex[1] = (i == maxIndex) ? i + 1 : i;
}
}
return found > index ? data.substring(strIndex[0], strIndex[1]) : "";
}
void PopulateMenuFromCSV()
{
file = SD.open("/myFile.csv", FILE_READ);
if (!file) {
Serial.println("Error opening file.");
return;
}
//first we need to count the number of lines in the file so we know how large to allocate the colleciton
int numlines = 0;
while (file.available())
{
file.readStringUntil('\n'); //in this CSV, each line is terminated with a newline character
numlines++;
}
String line;
file.seek(0); //seek back to the beginning of the file
//Use the BlynkParamAllocated object to contain the menu labels we want to add
BlynkParamAllocated items(sizeof(String)*numlines);
for (int i = 0; i< numlines; i++)
{
line = file.readStringUntil('\n');
//split the line at a comma, expecting line format of String,Float
String name = explode(line, ',', 0); //this will get the item in the first column
String value = explode(line, ',', 1); //this will get the item in the 2nd column
float floatval = value.toFloat(); //we expect the second column to contain floats
if (floatval != 0) //only add a line if we got a valid float (we don't expect 0 as a value in this list)
{
items.add(name); //add it to the collection of menu items
}
}
Blynk.setProperty(V30, "labels", items); //push it back to our menu, in this case, Pin 30
file.close();
}
float GetValueFromMenuSelection(int selectedIndex)
{
//Blynk menus return 1-based index, so we need to decrement
selectedIndex = selectedIndex - 1;
file = SD.open("/myFile.csv", FILE_READ);
if (!file) {
Serial.println("Error opening file.");
return -1;
}
for (int i = 0; i < selectedIndex; i++)
{
if (file.available())
{
file.readStringUntil('\n');
}
else
{
Serial.println("Error seeking to " + String(selectedIndex));
}
}
//the next line we read should be the selected index line
String line = file.readStringUntil('\n');
file.close();
String name = explode(line, ',', 0);
String value = explode(line, ',', 1);
float floatval = value.toFloat();
if (floatval != 0) { //again, a test to see if we got a valid float and we're not expecting a 0
Serial.print("Menu item set to " + name + " : ");
Serial.println(value);
return floatval;
}
else return -1;
}
There’s likely a more efficient way to do this, but hopefully this snippet will help others.
Still, it’d be super awesome to have a menu Widget wrapper that could store both key and value for scenarios like this. The WidgetTable class is so easy to work with in this way - if only I could bind it to a menu
Anyhow, thanks again. The Blynk platform and community are so awesome.