0

你们能帮我写一个伽玛脚本来将数据记录到数据库表中吗?标签位于 Cogent Datahub 的 OPC DA 中创建的域内。唯一需要满足的条件是脚本应该每隔一秒记录域中的所有点及其值和时间戳。

4

1 回答 1

1
require ("Application");
require ("ODBCThreadSupport");
require ("Time");
require ("Quality");

class LogData Application
{
DSN = "your ODBC DSN name";      // The DSN name to use for the database 
connection
username = "Database_User";       // The user name for connecting to the 
database
password = "*****";       // The password for connecting to the database
tablename = "table1";      // The name of the database table
cachefile = "C:\Users\AppData\cache.txt";   // Base name for the disk cache file
domain = "Domain name";      // The domain in which to log all points
tableclass;
thread;
mappedPoints = new Dictionary();
prevcount = 0;
}

/* If there is something we only want to perform on the first connection, we can 
test
* is_first_connect to perform the code only once.
*/
method LogData.onConnect()
{
princ ("Connection succeeded\n");
if (.thread.is_first_connect)
{
    // Start the sequence defined by the AddInitStage calls in the constructor
    .thread.BeginAsyncInit();
}
}
/* If the connection fails after having been
* connected, this method is called.
*/
method LogData.onConnectFail()
{
princ ("Connection closed: ", SQLResult.Description, "\n");
}

/* Map the table in the set of table definitions that matches the name in 
.tablename
 * into a Gamma class.  This lets us easily convert between class instances and 
 rows
* in the table.
*/
method LogData.mapTable(name, tabledefinitions)
{
//princ("Mapping table\n");
.tableclass = .thread.ClassFromTable(name, tabledefinitions);
//princ("Table class = ", .tableclass, "\n");
}

method LogData.startLogging()
{
.registerPoints();
}

/* Set up the timer or event handler functions to write to the table. */
method LogData.registerPoints()
{
/* Find all points in the domain */
local info = datahub_domaininfo(.domain)[0];
if (info.n_points != .prevcount)
{
    local points = datahub_points(.domain, nil, nil);
    local pointsym;
    

    princ(info.n_points - .prevcount, " new points are being added to 
logging\n");
    
    with point in points do
    {
        // Filter out branch points
        if ((point.flags & 0x30) == 0)
        {
            pointsym = symbol(string(point.domain,":", point.name));
            if (!.mappedPoints.contains(pointsym))
            {
                local PointName = string(pointsym);
                .TimerEvery(01,`(@self).writeData(@PointName));
                //.mappedPoints.add(pointsym, pointsym);
            }
        }
    }
    .prevcount = info.n_points;
}
}

method LogData.writeData(pointsymbol)
{
local       row = new (.tableclass);
local       pttime, ptltime;
local       timestring;
local       point;
// Generate a timestamp in database-independent format to the millisecond.
// Many databases strip the milliseconds from a timestamp, but it is harmless
// to provide them in case the database can store them.
point = PointMetadata(pointsymbol);
//princ(point,"\n");
if (point && number_p(point.value))
{
    pttime = WindowsTimeToUnixTime(point.timestamp);
    //princ(point,"\n");
    ptltime = localtime(pttime);
    //princ(ptltime,"\n");
    if (!ptltime)
        ptltime = localtime(0);
    timestring = format("{'%04d-%02d-%02d %02d:%02d:%02d'}",
    ptltime.year+1900, ptltime.mon+1, ptltime.mday, ptltime.hour, ptltime.min, 
 ptltime.sec);
    //princ(timestring,"\n");
    // Fill the row.  Since we mapped the table into a Gamma class, we can 
 access
    // the rows in the column as member variables of the mapped class.
    row.ptname = string(pointsymbol);
    row.ptvalue = point.value;
    row.pttime = timestring;
    
    // Perform the insertion.  In this case we are providing no callback on 
 completion.
    .thread.Insert(row, nil);
 }
 }
 /* Write the 'main line' of the program here. */
 method LogData.constructor ()
 {
// Create and configure the database connection object
.thread = new ODBCThread();
.thread.Configure(.DSN, .username, .password, STORE_AND_FORWARD, .cachefile, 0);

// Query the table and map it to a class for each insertion.  We want to run an 
asynchronous event
// within the asynchronous initialization stage, so to do that we specify the 
special method
// cbInitStage as the callback function of our asynchronous event 
(GetTableInfo).  We deal with
// the return from the GetTableInfo in the onSuccess argument of the init stage.
.thread.AddInitStage(`(@.thread).GetTableInfo("", "", (@.tablename), 
"TABLE,VIEW",
                                              `(@.thread).cbInitStage()),
                     `(@self).mapTable(@.tablename, SQLTables), nil);

//.thread.AddInitStage(`(@.thread).GetTableInfo("", "", (@.tablename), 
"TABLE,VIEW",
//                     `(@self).mapTable(@.tablename, SQLTables)), 
`(@.thread).cbInitStage(), nil);

// Do not start writing data to the table until we have successfully created and 
mapped
// the table to a class.  If we wanted to start writing data immediately, then 
we would
// create the table class beforehand instead of querying the database for the 
table
// definition.  Then, even if the database were unavailable we could still cache 
to the
// local disk until the database was ready.
.thread.AddInitStage(nil, `(@self).startLogging(), nil);

// Set up the callback functions for various events from the database thread
.thread.OnConnectionSucceeded = `(@self).onConnect();
.thread.OnConnectionFailed = `(@self).onConnectFail();
.thread.OnFileSystemError = `princ("File System Error: ", SQLResult, "\n");
.thread.OnODBCError = `princ("ODBC Error: ", SQLResult, "\n");
.thread.OnExecuteStored = nil;
.thread.Start();


// Create a menu item in the system tray that allows us to open a window to 
monitor
// the performance of the ODBC thread.  The menu strings can be edited as 
desired.
.AddCustomSubMenu("ODBC Logging");
.AddCustomMenuItem("Monitor Performance",
                   `(@.thread).CreateMonitorWindow((@self), "ODBC Monitor"));
                   
// Automatically update the point list every 1 seconds in case new points are v 
added
// to the domain.
//.TimerEvery(01, `(@self).registerPoints());

   }

   /* Any code to be run when the program gets shut down. */
    method LogData.destructor ()
   {
     if (instance_p(.thread))
       destroy(.thread);
   }

   /* Start the program by instantiating the class. */
   ApplicationSingleton (LogData);

这个 Gamma 脚本的主要部分是构造函数、析构函数、类和方法。该程序首先使用提供的详细信息初始化 ODBC 连接,并使用“registerpoints”和“writedata”方法写入每一行数据。请从程序中的注释中找到每行的更多详细信息。

于 2021-09-08T03:57:19.950 回答