ReadCSV.g — reads a CSV file and writes the points and values to the DataHub.
![]() | The code for this and other example scripts can be found in the DataHub distribution archive, typically at one of these locations: C:\Program Files\Cogent\OPC DataHub\scripts\ C:\Program Files\Cogent\Cascade DataHub\scripts\ Please refer to Section 3.1, “How to Run a Script” for more information on using scripts. |
/*
* This script reads a CSV file and writes the values found there
* into a set of data points in the DataHub. The format of the
* file is:
*
* row 1: name1, name2, name3, ...
* row 2: value1, value2, value3, ...
* row 3: value1, value2, value3, ...
* ...
* row N: value1, value2, value3, ...
*
* The script will read all rows in the file, but ignore all but
* the first and last. The first row contains the point names and
* the last contains the most recent data.
* If a name is left blank then that column is ignored.
* If a point name does not contain a domain name, then the domain
* set in the "domain" member of the application is used.
*
* e.g.,
* default:point1, default:point2, default:point3
* 1, 2, 3
* 4, 5, 6
*
* will result in:
* default:point1 = 4
* default:point2 = 5
* default:point3 = 6
*
* Strings containing ',' characters must be quoted within double quotes,
* like this:
* "hello, friend"
*
* Double-quotes within strings must be escaped, like this:
* "He said, \"hello\"."
*
* This script will guess whether a value is a number or a string. If the
* value can be parsed to a number, it is treated as a number. Otherwise it
* is a string.
*
* This script looks for new data at a set time interval.
*
* This script will operate in one of two modes:
* In "reload" mode, the file is re-read from the beginning on each
* timer tick.
* In "append" mode, the file is kept open, and the file is read
* from the last read position on each timer tick. This mode will
* not work if the writing application does not open the file
* as "shared".
*
* This script adds a menu item to the OPC DataHub system tray icon that
* allows the user to re-load the file, change reade mode, and toggle logging
* to the Script Log window.
*/
require ("Application");
class ReadCSV Application
{
mode = #reload; // set to #reload or #append
domain = "default";
filename = "c:/tmp/data.csv";
verbose = t;
update_secs = 5;
separators = ","; // e.g, use " " for space separated, or "\t" for tab-separated
/* --- No need to change these --- */
columns;
fptr;
modemenu;
verbosemenu;
}
/* Logging function that prepends the time to the output. */
method ReadCSV.Log (args...)
{
if (.verbose)
{
funcall (princ, cons (date(), cons(": ", args)));
princ("\n");
}
}
/* Open the given file, if possible. */
method ReadCSV.OpenFile (filename)
{
.fptr = open(filename, "r");
if (!.fptr)
{
.Log ("Could not open file: ", filename);
}
else
{
.filename = filename;
.Log ("File: ", filename, " opened");
.ReadColumns();
}
.fptr;
}
method ReadCSV.CloseFile ()
{
if (.fptr)
{
close(.fptr);
.Log ("File: ", .filename, " closed");
.fptr = nil;
}
}
method ReadCSV.Trim(str)
{
local l = strlen(str), start, end;
for (start=0; start<l && strchr(" \t",str[start]) != -1;)
start++;
for (end=l-1; end >= start && strchr(" \t",str[end]) != -1;)
end--;
if (start != 0 || end != l-1)
substr(str,start,end-start+1);
else
str;
}
method ReadCSV.ReadColumns ()
{
local line = read_line (.fptr);
local i;
if (line != _eof_)
{
line = list_to_array(string_split(line,.separators,0,t,"\"\"",t,"\\",nil));
for (i=0; i<length(line); i++)
{
if (.Trim(line[i]) == "")
{
line[i] = nil;
}
else
{
if (strchr(line[i],':') == -1)
line[i] = string(.domain,":",line[i]);
line[i] = symbol(line[i]);
datahub_command(format("(create %s 1)", stringc(line[i])),1);
}
}
.columns = line;
.Log("Set columns to ", .columns);
}
}
method ReadCSV.GuessTypeValue (str)
{
local value;
try
{
value = parse_string(str,nil);
if (!number_p(value))
value = str;
}
catch
{
value = str;
}
value;
}
method ReadCSV.ApplyLine (line)
{
local i, value;
.Log ("Applying line: ", line);
if (line)
{
line = list_to_array(string_split(line,.separators,0,t,"\"\"",nil,"\\",nil));
for (i=0; i<length(.columns); i++)
{
if (.columns[i])
{
value = .GuessTypeValue(line[i]);
//.Log ("Set: ", .columns[i], " to ", stringc(value));
if (value)
set(.columns[i], value);
}
}
}
}
method ReadCSV.ReadLines ()
{
local line, input;
.Log ("Looking for new data...");
while ((input = read_line(.fptr)) != _eof_)
{
if (.Trim(input) != "")
line = input;
}
if (line)
{
.ApplyLine(line);
}
}
method ReadCSV.ReadFile (filename)
{
if (!.fptr)
.OpenFile(filename);
if (.fptr)
{
.ReadLines();
if (.mode == #reload)
.CloseFile();
}
}
method ReadCSV.SetMode (mode)
{
.mode = mode;
.Log("Set read mode to ", mode);
.ChangeMenuItemLabel(.modemenu,
string("Set ", (mode == #append) ? "Reload" : "Append",
" Mode"));
if (.filename)
.Reload(.filename);
}
method ReadCSV.ToggleMode ()
{
.SetMode((.mode == #append) ? (#reload) : (#append));
}
method ReadCSV.ToggleVerbose ()
{
.SetVerbose(!.verbose);
}
method ReadCSV.SetVerbose (mode)
{
.verbose = t;
.Log("Set verbosity to ", (mode ? "verbose" : "quiet"));
.verbose = mode;
.ChangeMenuItemLabel(.verbosemenu,
string(mode ? "Quiet" : "Verbose", " Mode"));
}
method ReadCSV.Reload (filename)
{
.CloseFile();
.ReadFile(filename);
}
/* Write the 'main line' of the program here. */
method ReadCSV.constructor ()
{
.TimerEvery(.update_secs, `(@self).ReadFile((@self).filename));
.AddCustomSubMenu("CSV File Reader");
.AddCustomMenuItem("Reload CSV File", `(@self).Reload((@self).filename));
.modemenu = .AddCustomMenuItem("Set Append Mode", `(@self).ToggleMode());
.verbosemenu = .AddCustomMenuItem("Verbose", `(@self).ToggleVerbose());
.SetVerbose(.verbose);
.SetMode(.mode);
}
method ReadCSV.ChangeMenuItemLabel (menuitemid, label)
{
local parent = .CreateSystemMenu();
local info = new MENUITEMINFO();
if (cons_p(menuitemid))
menuitemid = car(menuitemid);
info.cbSize = 48;
info.fMask = MIIM_STRING | MIIM_ID;
info.fMask |= (WINVER < 0x0500 ? MIIM_TYPE : MIIM_FTYPE);
info.fType = MFT_STRING;
info.wID = menuitemid;
info.dwTypeData = label;
SetMenuItemInfo (parent, menuitemid, 0, info);
}
method ReadCSV.destructor ()
{
.CloseFile();
}
ApplicationSingleton (ReadCSV);
Copyright © 1995-2010 by Cogent Real-Time Systems, Inc. All rights reserved.