I'm sending data from an Arduino to an AI2 app in the format of each setting name is separated by an equals sign from each setting value and each set of name=value are separated by a pipe symbol delimiter. So "name=value|name2=value2|name3=value3".
I'd like to parse this in an AI2 procedure, first splitting the name/value sets with the pipe delimiter and then further splitting each single set by the equals delimiter and have conditional statements where if the local variable settingName matches the label name XXXX, then set the label XXXX to the value of the local variable settingValue.
Am I approaching this correctly with my procedure fn_SplitAndDisplay? I've been reading the documentation and trying to learn the syntax, but I can't get this parsing to work.
currentTimeStamp = millis();
if ((currentTimeStamp - btLastSendTimeStamp) > 2500)
{
BTSerial.println("lblTest1=Standard|lblTest2=Disabled");
btLastSendTimeStamp = millis();
Serial.println("Sending Bluetooth Data");
}
instantiate a global list message_labels (is this a fixed sized array that has to be hard coded to match the number of labels to be updated?)
call the Bluetooth client when it has bytes available, until there are no more bytes and set message to that delimited string being sent by the Arduino
call the function split_and_display, sending it the unparsed string, the delimiter and the array of label names
the function split_and_display will instantiate array named items splitting the string variable message by the delimiter you pass to the function
a foreach loop is called (why start at 1 instead of 0?) (why go from 1 to min and not max?) (why 1 to both arrays, does it mean the it loops to whichever array.count value is lower?)
the loop sets the label[index].text to the item[index].text
Is that understanding accurate? I'm getting a Java error that says "the operation length of list cannot accept the arguments ..." and it shows the entire string I'm sending.
If I were writing this in c#, I would parse the list with something similar to what is below. Can I do this in AI2? The flexibility this offers would allow me to not have to hard code so many things and I could still process lines like arduinoTxLine2 and arduinoTxLine3.
This uses the special case of -1 bytes requested, which scans for the \n in the incoming BT buffer. If no \n yet, it will hang. If a \n found, it will grab what precedes it, but leave the rest in the buffer for the next time around. This factors out all timing considerations, as long as the receiving end can keep up with the sending end eventually. The objective of this is to get exactly one complete message, without receiving fragments or losing messages.
yes ...
AI2 lists start at item 1, not 0 like in some other languages.
The min() call is needed to prevent trying to select item numbers out of range in short lists, in both cases
incoming message has fewer parts than we have Labels
incoming message has more parts than we have Labels
There are alternative ways to handle this, like for a short incoming message blank out the Labels past the list length of the split message, instead of leaving them untouched. On the other hand, if temperature varies fast but humidity varies slowly, and you send temp,humidity once in a while but just temp occasionally, that would leave the humidity Label untouched since last update.
Right.
Pretty much. Hover your cursor over the BlueTooth.ReceiveText block to see its tool tip, for that -1 trick.
Show us. Maybe you used the wrong field delimiter (',' vs '|') ?
(Canned Reply: ABG - Download those blocks and post them here)
Please download and post each of those event block(s)/procedures here ...
P.S. These blocks can be dragged directly into your Blocks Editor workspace.
Bluetooth has a message size limit of 20 bytes, from what I hear, so here is an individually labelled approach:
temperature and humidity on separate lines
If you want to send your temperature and humidity on separate lines, you could alternatively send tag:value pairs, like
T:98.6\n
H:100\n
which would arrive individually if you use Delimiter 10 (\n).
Your AI2 logic would look like
if BT.bytesAvailable > 0 then
set local message to BT.ReadText(-1) (to get only 1 line)
if contains(message, ":") then
set local splits to split message at ":"
If (select item 1 of splits) = "T" then
set LabelTemperature.Text to (select item 2 of splits)
else if (select item 1 of splits) = "H" then
set LabelHumidity.Text to (select item 2 of splits)
else set LabelWhatHappenned to local message
end if
If you don't like the ELSEIF ladder, you could look up Label components in a dictionary based on text prefix.
This format also works well with the AI2 Charts component.
Regarding your blocks, those empty sockets in your Label list look like trouble.