使用基于定时器的伽玛脚本从Cogent Datahub到数据库的数据日志

2022-01-28 06:52:54 标签 databaseopcopc-da

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

# # #

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);

这个脚本的主要部分是constructordestructorclasses和方法。这个程序首先使用提供的详细信息初始化一个ODBC连接,并使用“registerpoint”和“writedata”方法写入每一行数据。请从程序的注释中找到每一行的额外细节。

阅读全文

▼ 版权说明

相关文章也很精彩
推荐内容
更多标签
相关热门
全站排行
随便看看

错说 cuoshuo.com —— 程序员的报错记录

部分内容根据CC版权协议转载;网站内容仅供参考,生产环境使用务必查阅官方文档

辽ICP备19011660号-5

×

扫码关注公众号:职场神器
发送: 1
获取永久解锁本站全部文章的验证码