The “shift string element” example I mentioned here was part of a request I had for a little OptoScript to make a note if a certain tag changed.
For example, we’re working on some new interactive demos (be sure to sign up on groov.com for updates) that involve a “your name in lights” sign where you can change a text string and it shows up “in lights” (visible via a webcam). But we’d like to make a note when someone types in their name or other message.
I wanted to make this code a little generic/reusable since a couple of coworkers of mine wanted to add some similar logic to the controllers in their homes.
Here’s what I came up with (no pointers involved!) – do share if you have questions or other ideas. In the attached chart, which you can import into your own 9.3 Basic or better strategy, I give 2 options for the “make a note” part:
You can write it to a file to get a log like the one shown below (I prefer Firefox for easy reading of a text file on your PAC):
You can store this info a string table, where element  has the most recent entry.
(Or you can do both, which is what the attached chart currently does – adjust as needed.)
In the first OptoScript block, I initialize a list of the names of the tags I want to monitor. (Optional comment/label in the second column of string table initializations here.) I also open the local log file.
// Create a list of the values to log when they change // Optional label (if you want more info than just the tag name) stTagList = "fFloat"; stLabels = "My test float"; stTagList = "nInt32"; stLabels = "An int 32"; stTagList = "di_R1_0000"; stLabels = "digital input"; stTagList = "sSignString"; stLabels = "here's your sign"; // Open file to log to nCHResult = OpenOutgoingCommunication(chLogFile);
In the “Check variables for changes” OptoScript block, I use the handy command GetValueFromName to grab the current value of each tag in my list (as a string) and compare it with the previous value:
// Initialize loop variables nTableIndex = 0; SetVariableFalse(nDone); // Loop through all the tags to check, see if they're different, and make a note if they are while ( IsVariableFalse( nDone ) ) // See if we've reached the end of the list (the first blank or bad tag name) if ( GetValueFromName(stTagList[nTableIndex], stCurrentValue[nTableIndex]) <> 0 ) then SetVariableTrue(nDone); else // we need to compare this value to the last one // see if it's changed if ( 0 == CompareStrings(stCurrentValue[nTableIndex], stLastValue[nTableIndex] ) ) then // the value hasn't changed else // the value has changed, made a note, starting w/a date/timestamp DateToStringDDMMYYYY(sDate); TimeToString(sTime); sLogMessage = sDate + " " + sTime + " " + stTagList[nTableIndex] + " '" + stLabels[nTableIndex] + "' changed to: '" + stCurrentValue[nTableIndex] + "'" + chr(0xD) + chr(0xA); // MAKE A NOTE HERE // update "last value" stLastValue[nTableIndex] = stCurrentValue[nTableIndex]; endif endif IncrementVariable(nTableIndex); if (nTableIndex >= GetLengthOfTable(stTagList)) then SetVariableTrue(nDone); endif wend
In the “MAKE A NOTE” part, I give two options, shown below. But you could also send an email or something else if you’d like.
// MAKE A NOTE HERE /** "make a note" Option #1: write to file *****/ nCHResult = TransmitString(sLogMessage, chLogFile); // Check number of bytes left for RAM filespace nResultRAMbytes = GetAvailableFileSpace(0); // Check to see how much room we have for the log file if (nResultRAMbytes < 100) then // put a warning in the queue AddMessageToQueue(16, "chLogFile out of file space."); elseif (nResultRAMbytes < 1000) then // put a warning in the queue AddMessageToQueue(8, "chLogFile running low on filespace"); endif /** end option 1 */ /*** option 2 (Ben's choice) - string table w/most recent entry at the top */ // Read what's currently in the SP strings (so we can shift them down one) //GetIoUnitScratchPadStringTable(I/O Unit, Length, From Index, To Index, To Table) nSPResult = GetIoUnitScratchPadStringTable(R1, 63, 0, 1, stEventLog); // Load element  of the table stEventLog = sLogMessage; // Write the updated log list to the scratch pad //SetIoUnitScratchPadStringTable(I/O Unit, Length, To Index, From Index, From Table) nSPResult = SetIoUnitScratchPadStringTable(R1, 64, 0, 0, stEventLog); /** end option 2 */
Of course, this will miss any changes that happen inside the scanning interval. But for a simple event log, I thought this might be handy to others out there!
ChangeLogChart.zip (3.09 KB)