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.