煙臺龍源電力技術(shù)股份有限公司 王前厚
張家港市繁昌機械有限公司 王炳輝
在小型取暖鍋爐運行中,許多重要運行參數(shù)需要定期記錄,在手工年代,需要工人定期讀表并記錄在表格上,而在自動控制實現(xiàn)之后,則需要用報表來實現(xiàn),其中包含的內(nèi)容有:每一個小時整點記錄的數(shù)據(jù)列表,每個工作日,每個班組內(nèi)對這些數(shù)據(jù)的統(tǒng)計,統(tǒng)計方法有平均值及累加值,即為日報表或班報表。
例如,有業(yè)主要求的理想的報表結(jié)構(gòu)如表1中所示。
表1 鍋爐運行班報表
除了日報表,另外還有月報表,就是可以查詢?nèi)我粋€月的運行情況,其中包含這個月中每一天的數(shù)據(jù)統(tǒng)計表,以及最終對整個月所有數(shù)據(jù)做的數(shù)據(jù)統(tǒng)計,同理如表2所示。
這種應(yīng)用需求的報表,無法用WinCC或其它組態(tài)軟件簡單地用組態(tài)的方式實現(xiàn),因而必須或多或少地進(jìn)行一些編程,通過腳本,控制訪問數(shù)據(jù)庫,得到查詢結(jié)果。在WinCC應(yīng)用中,常把此類報表稱做為自定義報表。
西門子論壇 http://www.ad.siemens.com.cn/club/bbs/ 曾于2009年5月至7月間,組織了大型的專題討論,針對此類自定義報表進(jìn)行了一個全面的探討,眾多網(wǎng)友提供了各種各樣的要求和素材,定時抄表類型的報表是其中的一個大類型,好多報表應(yīng)用都與此或相同或相關(guān)。
這次專題討論,作者作為版區(qū)版主在其中承擔(dān)了牽線引導(dǎo)的職責(zé),引領(lǐng)網(wǎng)友從提供素材開始,面對對象,整理思路,積極發(fā)表看法。而西門子官方的工程師,則在此次討論過程中及討論結(jié)束后分別整理了技術(shù)報告,并制作了簡單示范程序,兩篇最重要的文獻(xiàn)就是《A0296 使用用戶歸檔實現(xiàn)報表簡介》和《A0300 WinCC數(shù)據(jù)報表實現(xiàn)方法介紹》,配套的例子程序則是叫做ForTest.mcp。這兩篇技術(shù)文獻(xiàn)還主要是從原理方面進(jìn)行的分析,例子程序也著重強調(diào)了實現(xiàn)的原理,而對實際應(yīng)用過程中的細(xì)節(jié),則沒有側(cè)重考慮。
表2 鍋爐運行月報表
本文是在A0296基礎(chǔ)上完善而來的,因而是對A0296的補充,本文實現(xiàn)的過程,也同樣有配套例子實現(xiàn),但與A0296已有極大的不同,表現(xiàn)在:
(1)A0296強調(diào)的是西門子產(chǎn)品的使用方法,本例則著重強調(diào)報表實現(xiàn)技術(shù)路線和細(xì)節(jié),強調(diào)在報表實現(xiàn)過程中的細(xì)節(jié)。特別是包含報表系統(tǒng)實現(xiàn)的WinCC項目的可移植性,強調(diào)用戶對例子演示操作的首次體驗。
(2)A0296著重強調(diào)的是報表的打印環(huán)節(jié),與作者持觀點不同。作者認(rèn)為,報表最重要的方面不是打印,而是查詢。就是說,最終需要實現(xiàn)的是隨時隨地均可調(diào)用查詢功能,并分析查詢結(jié)果。引導(dǎo)用戶養(yǎng)成低碳環(huán)保的操作習(xí)慣,一般操作只進(jìn)行查詢,不需要落實到紙面上。而如果確實需要打印時,則在查詢完成之后繼續(xù)操作打印功能,將結(jié)果輸出到打印機。
報表的實現(xiàn),最重要的是要有一條清晰的數(shù)據(jù)走向路線圖,并要盡量依托數(shù)據(jù)庫的思路來實現(xiàn),在其基礎(chǔ)上,將整個報表路線分割成相對獨立的幾個單元,一方面,將每一個單元的具體細(xì)節(jié)實現(xiàn)之后,串聯(lián)起來,就可以構(gòu)成整個報表的實現(xiàn)過程。另一方面,每一個獨立的單元如果有備選的技術(shù)方法實現(xiàn),則只需將相應(yīng)部分替換,可以輕松地實現(xiàn)升級,而不影響整個路線全局。
建立在數(shù)據(jù)庫視角的自定義報表實現(xiàn)路線需要的步驟分別為:
(1)數(shù)據(jù)存儲:報表所需數(shù)據(jù)素材存儲到數(shù)據(jù)庫。
(2)數(shù)據(jù)查詢:前臺用戶通過操作界面接口設(shè)定查詢條件,后臺程序生成查詢所需SQL語句,并對數(shù)據(jù)庫中執(zhí)行查詢操作。
(3)查詢結(jié)果顯示:選擇合適的表格控件將步驟2查詢得到的結(jié)果顯示在運行畫面上。
(4)打印報表或報表導(dǎo)出:將查詢結(jié)果輸出到打印機或?qū)С龅睫k公文件格式。如果步驟3選擇的控件能夠直接支持打印機和導(dǎo)出,則由表格控件實現(xiàn),否則從步驟2的查詢結(jié)果直接輸出實現(xiàn)。
在明確了報表實現(xiàn)的原理之后,下一步就是選擇每一個節(jié)點上可行的技術(shù)方法,最后拼接成一整條可行的技術(shù)路線。不過在確定技術(shù)路線之前,有幾個細(xì)節(jié)的原則問題需要確定,選擇技術(shù)路線時應(yīng)以不違背這些原則為標(biāo)準(zhǔn),如果原則有所違背,則要么更換技術(shù)點,要么通過給這個技術(shù)方法打補丁的方法繞過缺陷。
? 運行:只要WinCC項目有報表要求,報表功能應(yīng)盡量無縫嵌入在WinCC項目內(nèi),除非大規(guī)模運行的項目,有上層MES系統(tǒng)支持,報表是由MES來實現(xiàn)的。
無縫嵌入WinCC項目的好處在于操作者在操作時不必來回切換運行程序。尤其對組態(tài)軟件來說,如果被切換出去,則原本的全屏方式及對計算機運行權(quán)限管理都成為難題。
? 安裝:當(dāng)一個項目被移植到另外一臺新電腦時,除了WinCC軟件本身的安裝要求外,應(yīng)盡量少的附加安裝軟件,尤其是盡量減少對付費軟件的需求。否則會導(dǎo)致維護人員極度反感。
? 配置:在項目移植過程中或系統(tǒng)崩潰后的重新恢復(fù)過程中,報表功能應(yīng)盡量避免要求手工的設(shè)置操作。如要求手工建立一個數(shù)據(jù)庫表或一個ODBC接口等。這些操作一方面對維護人員水平的要求提高了,另一方面也導(dǎo)致系統(tǒng)的健壯性難以保證。
在綜合考慮報表實現(xiàn)的路線,遵循上述的原則,結(jié)合本案例的實際要求及WinCC的實際功能,本文提出了實現(xiàn)的解決方法,仍舊按照實現(xiàn)原理中的四個步驟分別描述如下:
(1)數(shù)據(jù)存儲
數(shù)據(jù)存儲使用用戶歸檔(以下均簡稱UA)實現(xiàn),如A0296中所描述,使用UA歸檔的ID和JOB配合來實現(xiàn)。由于UA這段功能實在太重要了,是本文的精華所在,所以仍需著重描述一下。
UA中的每一個歸檔都可以建立4個控制變量,分別叫做ID,JOB,F(xiàn)ield,Value。按照WinCC的幫助系統(tǒng)的描述,JOB=6時,為讀作業(yè)。讀作業(yè)是WinCC站在UA的視角內(nèi)描述問題,從UA的角度,當(dāng)JOB=6時,把運行的實時變量的值讀取并保存在數(shù)據(jù)庫相應(yīng)的位置,位置按照ID的設(shè)定。而我們站在外部的角度觀察這個操作,其實就是我們通常所說的寫數(shù)據(jù)庫的操作。而相應(yīng)的JOB=7時則為讀取數(shù)據(jù)庫的值到Tag變量中。案例要求的每小時整點時記錄數(shù)據(jù),則只需每判斷到整點到來時運行ID=-1,JOB=6即完成一條數(shù)據(jù)記錄行為。
首先是在UA中建立名字為Boiler的歸檔,然后編制腳本判斷在整點時產(chǎn)生一次增加新條目的操作,及ID=-1,JOB=6。具體可以實現(xiàn)的方法很多,如在全局腳本中通過Hour變量的變化觸發(fā),也可以在1S的循環(huán)周期的腳本中讀取當(dāng)前時間,當(dāng)判斷時間為整點時記錄?;蛘咴赑LC中編程以實現(xiàn)可控制的觸發(fā)。最簡單的,可以參考A0296中描述的實現(xiàn)。這些方法都差別不大。
需要注意的細(xì)節(jié):
? 歸檔中的日期和時間域可以在建立之后重新修改格式為日期/時間格式,便于在查詢時條件匹配。如果以文本方式記錄的日期時間變量,在查詢時是以字符方式比較的,有可能出錯。
? 日期和時間是分成兩個變量域分別存儲,但也可以用一個變量來存儲,各有利弊。
? 如果選擇用一個變量來存儲時間,可以直接使用UA表本身帶的最后修改選項,自動建立一個LastAccess的域,保存了數(shù)據(jù)寫入時的時間值。同樣與通過WinCC變量來保存相比,各有利弊。
? 最后一個域,班次(Turn),是用來記錄班次信息,唯有將班次信息正確完整記錄,才有可能做出成功的班報表。實時運行班次的確定,需要根據(jù)運行現(xiàn)場業(yè)主的倒班原則來確定,可以用編程實現(xiàn)倒班表的切換。但最簡單的方法是通過WinCC用戶管理來實現(xiàn),相應(yīng)的班組接班時登入各自的班組用戶名,報表系統(tǒng)中自然得到正確的班組名稱。
? 關(guān)于WinCC啟動時會觸發(fā)一次腳本并產(chǎn)生一個未在整點的數(shù)據(jù)記錄的問題,可以通過腳本中增加判斷來繞過一次寫操作,但從實際設(shè)備運行的角度,如果由于電腦設(shè)備的原因,導(dǎo)致長時間的停機,必然導(dǎo)致數(shù)據(jù)記錄的缺失,那么在系統(tǒng)恢復(fù)之時,如果能夠盡快地補錄一次數(shù)據(jù),相比之下,時間是否在整點則相對不那么重要了。
(2)數(shù)據(jù)查詢
數(shù)據(jù)查詢的核心是面向數(shù)據(jù)的SQL查詢語言。包括:查詢條件輸入,查詢語句生成以及調(diào)用數(shù)據(jù)庫接口進(jìn)行數(shù)據(jù)查詢的操作。
一個完整的自定義的報表一般至少分為兩個部分,比如班日報表,首先是當(dāng)前班次的所有數(shù)據(jù)的一個排列列表,然后是對這些數(shù)據(jù)的數(shù)學(xué)統(tǒng)計結(jié)果。統(tǒng)計方法可能是平均值或者累加值等,但最后的表現(xiàn)形式都是以表格形式體現(xiàn)的。或許有些特殊的結(jié)果輸出要求為多個表格部分組成,會超過兩部分,但原理上來說,要么是簡單條件查詢的,本文稱為A類查詢,要么就是帶統(tǒng)計的,本文稱為B類查詢。自定義報表最大的難題在于B類查詢。
一個典型的A類SQL查詢的語法如下:
Select ThisDay, F1, F2, F3, F4, F5, F6, F7, F8, F9
From UA#Boiler
Where ThisDay = '10-9-16' and Turn=,A,
查詢功能提供給用戶的操作界面,主要的目的就是來產(chǎn)生這樣的查詢語法。其中,Select語句之后的為查詢需要顯示的列,一般為固定的內(nèi)容,程序中則為固定的字符串。From語法之后為UA中建立的表的名字,同樣也為固定的。所以最終要的是Where之后的條件的產(chǎn)生。
為方便用戶使用,查詢條件的輸入日期時間部分使用專用時間控件,而班次則使用下拉菜單實現(xiàn)。盡可能避免手工鍵盤輸入,一方面實現(xiàn)輸入直觀快捷,最大程度地提高用戶的操作體驗;另一方面避免了使用過程中容易發(fā)生的格式錯誤,從而在項目交工時也少了專門的培訓(xùn)環(huán)節(jié)。
本文選擇的報表顯示形式為UA控件本身,通過將其工具欄和狀態(tài)欄禁用之后其表格部分就是一個功能完整的Grid控件的主體。而且非常幸運的是,控件本身有一個Filter屬性,即用來設(shè)定過濾所顯示的數(shù)據(jù)條件。所以在腳本程序中不必生成完整的SQL查詢語句,而只需要生成where之后的條件部分即可。
具體的實現(xiàn),控件的Filter屬性綁定一個文本型的tag,查詢腳本中將拼接起來的過濾條件類似 ThisDay = '10-9-16' and Turn=,A, 的字符傳送給tag即可。
B類查詢,對上述的9個變量,F(xiàn)1-F7求平均值,F(xiàn)8,F(xiàn)9求累加值的統(tǒng)計結(jié)果,SQL語句如下:
Select ThisDay,AVG(F1) As F1,AVG(F2) As F2,AVG(F3)As F3,AVG(F4) As F4,AVG(F5) As F5,AVG(F6) As F6,AVG(F7) As F7,SUM(F8) As F8,SUM(F9) AS F9
FROM UA#Boiler
Where ThisDay = '10-9-16' and Turn =,A,
Group BY ThisDay
由于條件部分與A查詢完全相同,所以用戶接口部分使用同一接口,字符串拼接,得到如上的SQL語句。
由于UA控件未提供數(shù)據(jù)分析的功能,B查詢的實現(xiàn)相對麻煩些,需要幾個步驟:
? UA中建立一個空的表S,用于存放查詢結(jié)果
? 通過ADO或者ODBC ADO直接對SQL數(shù)據(jù)庫進(jìn)行查詢,得到統(tǒng)計結(jié)果的RecordSet。
? 刪除S表中的原有數(shù)據(jù)??梢酝ㄟ^S表的控制變量,ID=-6,JOB=8來實現(xiàn)。多行數(shù)據(jù)則循環(huán)實現(xiàn)。
? 仍舊通過S表的控制變量,遍歷RecordSet的結(jié)果,通過ID=-1,JOB=6的方式新增數(shù)據(jù)記錄,寫入到UA表中。
? 畫面增加第2個UA控件,指定到S表,不再指定過濾條件。
核心代碼如下:
Dim Adodc1
Set Adodc1 = ScreenItems("Adodc1")
Adodc1.ConnectionString="DSN=" & HMIRuntime.Tags("@DatasourceNameRT").Read
Adodc1.RecordSource=SQL
Adodc1.Refresh
HMIRuntime.Trace vbCrLf & SQL
Dim taglist
taglist="ThisDay_Gr,F1_AVG,F2_AVG,F3_AVG,F4_AVG,"
taglist=taglist & "F5_AVG,F6_AVG,F7_AVG,F8_SUM,F9_SUM"
Dim TagName
TagName=Split(taglist,",",-1,1)
Dim i, Temp1
If Adodc1.Recordset.recordcount<>0 Then
For i=0 To UBound(TagName)
HMIRuntime.Trace vbCrLf & TagName(i) & "="& Adodc1.Recordset.Fields(i)
HMIRuntime.Tags(TagName(i)).Write Adodc1.Recordset.Fields(i)
Next
HMIRuntime.Tags("@UA_S_ID").Write -1
HMIRuntime.Tags("@UA_S_Job").Write 6
Else
HMIRuntime.Trace vbCrLf & "no data found!!!!"
End If
圖1 實際運行后的效果圖
月報表的準(zhǔn)確描述是月度日報表,與前面的班日報表形式上類似,都是分成兩部分的查詢內(nèi)容,但內(nèi)容上有所區(qū)別。第一部分的查詢內(nèi)容也為統(tǒng)計后的結(jié)果,即A類查詢。本例中,在查詢部分一需要將某一個月內(nèi)所有的工作日的數(shù)據(jù)統(tǒng)計計算,并將結(jié)果按日期羅列起來,而查詢部分二中的內(nèi)容則是以這個月份為對象的整體統(tǒng)計計算。
月報表查詢一的SQL查詢語法為:
Select ThisDay,AVG(F1) As F1,AVG(F2) As F2,AVG(F3) As F3,AVG(F4)As F4,AVG(F5) As F5,AVG(F6) As F6,AVG(F7) As F7,SUM(F8) As F8,SUM(F9) AS F9
From UA#Boiler
Where CONVERT(varchar(10), ThisDay, 120) like '2010-09%'
Group By ThisDay
查詢的主體部分與日報表中的查詢二相似,也都同為B類查詢,但Where后的語法則相差很大。這是因為ThisDay列中保存的是日期數(shù)據(jù),而查詢條件則是年月,即需要將數(shù)據(jù)中年月條件符合的數(shù)據(jù)挑選出來。返回結(jié)果為每日一條數(shù)據(jù),計算的是當(dāng)日的統(tǒng)計值。
這里使用轉(zhuǎn)換方法,把日期數(shù)據(jù)的格式轉(zhuǎn)換為YYYY-MM-DD格式的字符串,然后通過字符串比較的like語法來實現(xiàn)。
查詢二的月統(tǒng)計數(shù)據(jù)的SQL語法:
Select CONVERT(varchar(7),ThisDay,120),AVG(F1) As F1,AVG(F2) As F2,AVG(F3) As F3,AVG(F4) As F4,AVG(F5)As F5,AVG(F6) As F6,AVG(F7) As F7,SUM(F8) As F8,SUM(F9) AS F9
FROM UA#Boiler
WHERE CONVERT(varchar(10), ThisDay,120) like '2010-09%'
GROUP BY CONVERT(varchar(7),ThisDay,120)
這里的WHERE條件與查詢一相同,但Group語法又有所不同,因為需要將整個月的所有數(shù)據(jù)統(tǒng)一統(tǒng)計為一個結(jié)果。所以通過轉(zhuǎn)換方式,把日期數(shù)據(jù)YYYY-MM-DD的前7個字符輸出,得到了YYYY-MM的年+月格式。然后既要在統(tǒng)計結(jié)果中顯示這個年月值,還需要用此作為Group的分組依據(jù)。
(3)查詢結(jié)果顯示
查詢結(jié)果顯示在WinCC運行畫面上,前文已經(jīng)透露過,本文主要的方法即使用UA控件,通過禁用工具欄、狀態(tài)欄并將屬性設(shè)置為只讀,則成為一個簡單表格控件的模式,可以用來顯示查詢結(jié)果。
其中查詢班日報表部分,直接使用源記錄數(shù)據(jù)的歸檔,通過Filter屬性設(shè)置過濾條件,而日報表的查詢統(tǒng)計則通過單獨建立的UA中的歸檔來實現(xiàn)。
而月報表的兩部分查詢則都是使用和班日報表的統(tǒng)計查詢部分一樣的手法,通過建立一個空表,在查詢到結(jié)果時填入數(shù)據(jù)到歸檔中,則畫面的表格中自動充滿數(shù)據(jù)。
(4)打印報表
圖2 打印效果圖
客戶在查詢運行數(shù)據(jù)后,如需打印,則隨時可將查詢的結(jié)果打印出來。由于本文使用的UA控件直接支持打印功能,因而可以直接調(diào)用系統(tǒng)的打印模板實現(xiàn)。唯一差別的是,我們的報表里面包含2個表格 ,因而需在布局中設(shè)計2個“用戶歸檔 DLL運行系統(tǒng)表格”,即可實現(xiàn)完整打印功能,如圖2所示。
? 在WinCC中使用UA配合做報表,可以實現(xiàn)較為完善的功能。
? 本文在數(shù)據(jù)記錄、數(shù)據(jù)查詢、顯示、打印輸出各方面都充分利用UA內(nèi)置提供功能,取得較好的效果。
? 用UA來實現(xiàn)報表,優(yōu)點是需要較少的程序腳本,尤其是數(shù)據(jù)庫操作代碼。UA控件對數(shù)據(jù)格式的自動適應(yīng)與處理,也簡化了程序的工作量。
? 此技術(shù)方法的缺點在于查詢時的效率較低,特別是一個月報表查詢,需要先將UA表內(nèi)的數(shù)據(jù)逐行清空,然后再將查詢結(jié)果逐行寫入。由于使用ID和JOB控制變量來實現(xiàn)讀寫操作,需要等待確認(rèn)前步驟操作完成之后方可繼續(xù)腳本,導(dǎo)致程序運行周期較長。同時程序也不是特別健壯。
? 自定義報表除本文所論及方向和思路之外,還有大量的細(xì)節(jié)工作要做并且很難用文字來描述。為此作者同時還專門制作了詳盡的WinCC例程,并發(fā)布在網(wǎng)絡(luò)上,地址為:http://goo.gl/Mze1
? 例程中除使用UA控件實現(xiàn)之外,還演示了另外兩種直接支持ADO方法的表格控件的實現(xiàn)方法。