WriteCSV.g

WriteCSV.g — writes data to CSV files.

Code

[Note]

The code for this and other example scripts can be found in the DataHub distribution archive, typically at this location:

C:\Program Files\Cogent\Cogent DataHub\scripts\

Please refer to Section 3.1, “How to Run a Script” for more information on using scripts.

/*
 * Write data to a number of different CSV files.  Each data set is
 * written at a different interval, either per second, per minute or
 * per hour.  A new CSV * file is created every hour or every day.
 *
 * The points names in each data set are read from a file.  The file
 * consists of each full point name (including domain name), one per 
 * line.  The output file will contain a time stamp followed by the 
 * value for each point in the order that the points are listed in 
 * the point name file.
 *
 * To change the format of the file name, change the method
 * "GenerateFileName".
 *
 * To change the extension of the file, change the member variable
 * "filesuffix".
 *
 * To change the file names and timing, change the .NewDataSet calls
 * in the method WriteCSV.constructor.
 */

require ("Application");
require ("CSVSupport");

class WriteCSV Application
{
    datasets;
}

class MyCSVWriter CSVWriter
{
    pointfile;       // The name of a file containing the point list.
    sample_rate;       // one of #second, #minute, #hour or
                       // list(hour,minute,second)
    file_rotate_rate;  // one of #minute, #hour, #day or
                       // list(hour,minute,second)
    filesuffix = ".csv";  // normally .csv.  Override it to create
                          // .txt files.
}

/* This will produce a file name like:
 *     base_20090423_PM3.csv
 */
 
/*
method MyCSVWriter.GenerateFileName()
{
    local tm = localtime(nanoclock());
    format("%s_%d%02d%02d_%s%d%s", .filebase,
           tm.year+1900, tm.mon+1, tm.mday,
           tm.hour >= 12 ? "PM" : "AM",
           tm.hour > 12 ? tm.hour - 12 : (tm.hour == 0 ? 12 :
					  tm.hour), .filesuffix);
}
*/

/* This will produce a file name like:
 *     base-20090423-1545.csv
 */
method MyCSVWriter.GenerateFileName()
{
    local tm = localtime(nanoclock());
    format("%s-%d%02d%02d-%02d%02d%s", .filebase,
           tm.year+1900, tm.mon+1, tm.mday,
           tm.hour, tm.min,
           .filesuffix);
}

/*
 * Create a new writer and start the timers to write new data and to
 * create a new log file.
 */
method WriteCSV.NewDataSet (output_file_base, pointfile, sample_rate,
			    file_rotate_rate, separate_lines)
{
    local	writer = new MyCSVWriter();
    if (writer.ReadPointsFromCSV(pointfile))
    {
        writer.sample_rate = sample_rate;
        writer.file_rotate_rate = file_rotate_rate;
        writer.SetFileBase(output_file_base);
        writer.SetSeparateLines(separate_lines);
		
        switch(writer.sample_rate)
        {
            case (#second):
                .TimerAt(nil,nil,nil,nil,nil,nil,
			 `(@self).WriteData(@writer));
            case (#minute):
                .TimerAt(nil,nil,nil,nil,nil,0,
			 `(@self).WriteData(@writer));
            case (#hour):
                .TimerAt(nil,nil,nil,nil,0,0,
			 `(@self).WriteData(@writer));
            case (#day):
                .TimerAt(nil,nil,nil,0,0,0,
			 `(@self).WriteData(@writer));
            default:
                if (list_p(writer.sample_rate))
                {
                    // List of hour, minute, second specification
                    local  times = list_to_array(writer.sample_rate);
                    .TimerAt(nil,nil,nil,times[0],times[1],times[2],
			     `(@self).WriteData(@writer));
                }
                else // Default is hourly
                {
                    .TimerAt(nil,nil,nil,nil,0,0,
			     `(@self).WriteData(@writer));
                }
        }
        switch(writer.file_rotate_rate)
        {
            case (#minute):
                .TimerAt(nil,nil,nil,nil,nil,0,
			 `(@self).RotateFile(@writer));
            case (#hour):
                .TimerAt(nil,nil,nil,nil,0,0,
			 `(@self).RotateFile(@writer));
            case (#day):
                .TimerAt(nil,nil,nil,0,0,0,
			 `(@self).RotateFile(@writer));
            default:
                if (list_p(writer.file_rotate_rate))
                {
                    // List of hour, minute, second specification
                    local  times =
		      list_to_array(writer.file_rotate_rate);
                    .TimerAt(nil,nil,nil,times[0],times[1],times[2],
			     `(@self).RotateFile(@writer));
                }
                else // Default is hourly
                {
                    .TimerAt(nil,nil,nil,nil,0,0,
			     `(@self).RotateFile(@writer));
                }
        }
        .datasets = cons(writer, .datasets);
    }
}

method WriteCSV.WriteData(writer)
{
    writer.WriteLine();
}

method WriteCSV.RotateFile(writer)
{
    .TimerAfter(0.1, `(@writer).IncrementFileName());
}

/* Write the 'main line' of the program here. */
method WriteCSV.constructor ()
{
    /* Specify the CSV files to write.  Modify the .NewDataSet lines
     * to specify how to write each CSV file.
     * Arguments are:
     *    output_file_base:  The first part of the file, before the
     *                       date string
     *    pointfile:  The name of a file containing the point names
     *                for this data set
     *    sample_rate:  One of #second, #minute, #hour or
     *                  list(hour,minute,second) telling how
     *                  frequently to write a line to the CSV file
     *    file_rotate_rate:  One of #minute, #hour, #day
     *                       or list(hour,minute,second) telling how
     *                       frequently to create a new CSV file.
     *    separate_lines:  If this is nil, write all point values on
     *                     one line.  If this is t, write each point
     *                     value on a separate line.
     *
     * This function will read the pointfile as a CSV file and treat
     * the first field in each row as the name of a point to be
     * recorded into the output file.
     *
     * When specifying timing, the input is the list of
     * (hour,minute,second) as accepted by the "at" function
     * (see documentation).  A value of nil for hour, minute or
     * second stands for all values for that parameter.  A list of
     * values for hour, minute or second specifies an event only
     * when the hour, minute or second matches one of the values in
     * the list.
     * Examples:
     *    list(nil,nil,nil)		- every second
     *    list(nil,list(0,15,30,45),0)	- every 15 minutes
     *	  list(nil,list(0,15,30,45),30) - every 15 minutes,
     *                                    30 seconds past the minute
     *    list(list(0,8,16), 0, 0)      - at midnight, 8AM and 4PM
     *                                    exactly
     *    list(list(0,8,16), 5, 0)      - at 12:05AM, 8:05AM and
     *                                    4:05PM 
     * 
     * The symbols #second, #minute, #hour, #day are conveniences for:
     *    second:   list(nil,nil,nil)  - any hour, any minute,
     *                                   every second
     *    minute:   list(nil,nil,0)    - any hour, every minute
     *                                   at 0 seconds
     *    hour:     list(nil,0,0)      - every hour, on the hour
     *    day:      list(0,0,0)        - at midnight (0 hour,
     *                                   0 minute, 0 second)
     */
    .NewDataSet("c:/tmp/Group1", "c:/tmp/Group1_Points.txt",
                #second, #hour, nil);
    .NewDataSet("c:/tmp/Group2", "c:/tmp/Group2_Points.txt",
                #second, list(nil,list(0, 15,30,45),0), nil);
    .NewDataSet("c:/tmp/Group3", "c:/tmp/Group3_Points.txt",
                #second, list(nil,nil,0), nil);
}

/* Any code to be run when the program gets shut down. */
method WriteCSV.destructor ()
{
    with writer in .datasets do
    {
        destroy(writer);
    }
}

/* Start the program by instantiating the class.  If your
 * constructor code does not create a persistent reference to
 * the instance (self), then it will be destroyed by the
 * garbage collector soon after creation.  If you do not want
 * this to happen, assign the instance to a global variable, or
 * create a static data member in your class to which you assign
 * 'self' during the construction process.  ApplicationSingleton()
 * does this for you automatically. */
ApplicationSingleton (WriteCSV);