歸檔實(shí)戰(zhàn):歷史臺(tái)賬記錄比外掛數(shù)據(jù)庫(kù)更省心)
簡(jiǎn)介WinCC用戶(hù)歸檔案例是一份面向工業(yè)自動(dòng)化工程師與SCADA初學(xué)者的實(shí)踐型資料包圍繞西門(mén)子WinCC中的用戶(hù)歸檔功能重點(diǎn)講解動(dòng)作與標(biāo)準(zhǔn)模塊的協(xié)同使用以及歸檔策略設(shè)計(jì)、數(shù)據(jù)存儲(chǔ)與檢索等關(guān)鍵問(wèn)題。壓縮包共290個(gè)文件大小36.21MB主要包含rpl過(guò)程數(shù)據(jù)文件、mdf/ldf數(shù)據(jù)庫(kù)文件、dum備份文件、pdl畫(huà)面文件、cfg配置文件及腳本和說(shuō)明文檔等可幫助理解歸檔數(shù)據(jù)的生成、存儲(chǔ)與調(diào)用方式。已有1146人學(xué)習(xí)瀏覽適合希望系統(tǒng)掌握用戶(hù)歸檔配置與優(yōu)化的技術(shù)人員。通過(guò)該案例可學(xué)習(xí)動(dòng)作觸發(fā)條件、標(biāo)準(zhǔn)模塊封裝邏輯、歸檔間隔設(shè)定、數(shù)據(jù)保留期限與存儲(chǔ)介質(zhì)選擇等實(shí)操要點(diǎn)并參考示例項(xiàng)目靈活復(fù)用到實(shí)際產(chǎn)線(xiàn)中。 用用戶(hù)歸檔存歷史臺(tái)賬比外掛數(shù)據(jù)庫(kù)省心得多最近接了一套WinCC監(jiān)控系統(tǒng)的項(xiàng)目要記錄每臺(tái)設(shè)備的啟停時(shí)間、操作員信息和關(guān)鍵運(yùn)行參數(shù)方便后續(xù)做質(zhì)量追溯。一開(kāi)始我腦子里蹦出來(lái)的方案是外掛SQL Server但現(xiàn)場(chǎng)就一臺(tái)工控機(jī)再塞一個(gè)數(shù)據(jù)庫(kù)進(jìn)去部署和維護(hù)成本都不小。后來(lái)想起WinCC自帶的用戶(hù)歸檔功能干脆就用它做了整套臺(tái)賬記錄模塊。這一套做下來(lái)我最大的感受是用戶(hù)歸檔這東西平時(shí)存在感低但真用到生產(chǎn)數(shù)據(jù)記錄、操作追溯、配方管理這類(lèi)場(chǎng)景它比變量記錄靈活比外部數(shù)據(jù)庫(kù)省事。這篇就把整個(gè)案例從頭到尾拆開(kāi)講重點(diǎn)說(shuō)用戶(hù)歸檔怎么建、字段怎么定、腳本怎么聯(lián)動(dòng)以及那些說(shuō)明書(shū)里根本不會(huì)寫(xiě)的坑。1. 用戶(hù)歸檔的定位與選型思路1.1 用戶(hù)歸檔到底是什么用戶(hù)歸檔User Archive是WinCC項(xiàng)目?jī)?nèi)嵌的一個(gè)數(shù)據(jù)表模塊。你可以把它理解成一個(gè)輕量級(jí)的、隨項(xiàng)目發(fā)布的迷你數(shù)據(jù)庫(kù)它允許你在項(xiàng)目里定義若干個(gè)“表”每個(gè)表有固定的字段列和記錄行支持增刪改查也能和畫(huà)面控件、腳本順暢聯(lián)動(dòng)。它和WinCC的“變量記錄”完全是兩種東西。變量記錄是把某個(gè)變量的歷史變化曲線(xiàn)存下來(lái)供趨勢(shì)控件讀取用戶(hù)歸檔則是存結(jié)構(gòu)化的事件型數(shù)據(jù)比如“某年某月某日某操作員完成了某個(gè)操作”每條記錄就是一行字段明確查詢(xún)方便。歸檔文件會(huì)跟著項(xiàng)目一起保存和發(fā)布不需要單獨(dú)安裝數(shù)據(jù)庫(kù)服務(wù)運(yùn)行時(shí)WinCC能干活歸檔就能用。正是因?yàn)檫@種內(nèi)嵌特性用戶(hù)歸檔特別適合單機(jī)版的中小型監(jiān)控項(xiàng)目。1.2 為什么用用戶(hù)歸檔而不是普通變量普通變量只能保存當(dāng)前值想存歷史就得上變量記錄。但變量記錄的存儲(chǔ)結(jié)構(gòu)是圍繞“變量”組織的你很難把多個(gè)不同含義的字段組合成一條完整業(yè)務(wù)記錄。舉個(gè)例子你要記錄“操作員張三在2024年6月1日10點(diǎn)23分啟動(dòng)了A設(shè)備”這一條記錄里包含了人員、時(shí)間、操作類(lèi)型、設(shè)備編號(hào)四個(gè)信息。如果只用變量記錄你得建四個(gè)變量然后分別歸檔查的時(shí)候還得自己對(duì)齊時(shí)間軸非常別扭。用戶(hù)歸檔則直接建模成一條記錄設(shè)備編號(hào)、操作員、操作類(lèi)型、時(shí)間戳四個(gè)字段排成一排查詢(xún)時(shí)按條件過(guò)濾一目了然。尤其是后續(xù)做追溯報(bào)表用戶(hù)歸檔天生就是臺(tái)賬結(jié)構(gòu)。1.3 我的選型決策與實(shí)踐考量這個(gè)項(xiàng)目里我一開(kāi)始猶豫要不要用外掛數(shù)據(jù)庫(kù)。后來(lái)發(fā)現(xiàn)問(wèn)題很多現(xiàn)場(chǎng)工控機(jī)系統(tǒng)環(huán)境雜亂數(shù)據(jù)庫(kù)實(shí)例和WinCC之間的連通性受防火墻影響數(shù)據(jù)庫(kù)進(jìn)程占內(nèi)存老工控機(jī)會(huì)卡最重要的是客戶(hù)沒(méi)有專(zhuān)門(mén)的IT人員用外掛數(shù)據(jù)庫(kù)等于給后續(xù)維護(hù)埋雷。選用戶(hù)歸檔的另一個(gè)原因是它和WinCC Runtime深度集成發(fā)布畫(huà)面時(shí)歸檔結(jié)構(gòu)自動(dòng)帶過(guò)去不需要額外部署。對(duì)于設(shè)備啟停記錄這種量級(jí)的輕量應(yīng)用單機(jī)版WinCC跑用戶(hù)歸檔綽綽有余。所以最后我在管理器中直接建了三個(gè)歸檔DeviceLog運(yùn)行記錄、OperatorLog操作記錄、AlarmLog報(bào)警確認(rèn)記錄。2. 用戶(hù)歸檔的創(chuàng)建與配置實(shí)操2.1 打開(kāi)用戶(hù)歸檔管理器新建歸檔在WinCC項(xiàng)目樹(shù)里雙擊“用戶(hù)歸檔”圖標(biāo)打開(kāi)管理器窗口。左側(cè)是歸檔列表右鍵選擇“新建歸檔”起名時(shí)建議用英文字母比如DeviceLog。中文歸檔名在部分腳本和控件綁定場(chǎng)景下容易出現(xiàn)編碼問(wèn)題能用英文就用英文。歸檔建好之后右側(cè)會(huì)有多個(gè)頁(yè)簽最核心的是“字段”和“記錄”。字段頁(yè)定義表結(jié)構(gòu)記錄頁(yè)設(shè)置數(shù)據(jù)來(lái)源和觸發(fā)方式。新建歸檔后系統(tǒng)默認(rèn)會(huì)有一個(gè)“自動(dòng)增量”類(lèi)型的字段建議保留它能在后續(xù)做記錄定位時(shí)充當(dāng)唯一標(biāo)識(shí)。2.2 定義字段與數(shù)據(jù)類(lèi)型雙擊“字段”頁(yè)點(diǎn)“添加字段”逐條建立列。以我的設(shè)備運(yùn)行記錄為例字段定義如下字段名數(shù)據(jù)類(lèi)型說(shuō)明RecordID自動(dòng)增量主鍵唯一標(biāo)識(shí)記錄DeviceID文本設(shè)備編號(hào)Operator文本操作員姓名Action整數(shù)0停止1啟動(dòng)TimeStamp日期時(shí)間記錄時(shí)間字段類(lèi)型一定要和實(shí)際寫(xiě)入的數(shù)據(jù)匹配尤其是“時(shí)間戳”這種不要圖省事設(shè)成字符串否則后面按時(shí)間排序、按時(shí)間過(guò)濾都會(huì)出問(wèn)題。自動(dòng)增量字段我一般只用來(lái)做唯一標(biāo)識(shí)不會(huì)把它顯示在畫(huà)面表格里避免干擾。字段順序也有講究。建議把主鍵字段放第一位查詢(xún)條件字段放前面顯示型字段放后面。這樣做的好處是當(dāng)你在腳本里用SetFieldValue按索引賦值時(shí)索引對(duì)應(yīng)關(guān)系好記憶不容易搞混。2.3 設(shè)置記錄觸發(fā)與變量連接在“記錄”頁(yè)可以給歸檔設(shè)置“記錄模式”。這里有多種選擇手動(dòng)記錄、變化時(shí)記錄、周期記錄等。我這里啟停事件用的是手動(dòng)記錄因?yàn)檫@類(lèi)操作本身有明確的觸發(fā)時(shí)機(jī)手動(dòng)寫(xiě)更干凈。如果你要做連續(xù)型數(shù)據(jù)記錄比如每秒鐘記錄一次溫度那用“周期”模式更合適周期時(shí)間可以精確到毫秒。但要注意周期模式的數(shù)據(jù)量增長(zhǎng)很快用戶(hù)歸檔的分區(qū)文件會(huì)迅速膨脹這是很多人后期遇到“歸檔變慢”的根源。我最終在代碼里顯式調(diào)用插入函數(shù)而不是依賴(lài)自動(dòng)記錄。原因很簡(jiǎn)單手動(dòng)模式能精確控制寫(xiě)入時(shí)機(jī)避免重復(fù)觸發(fā)。自動(dòng)記錄的觸發(fā)條件如果沒(méi)設(shè)置好很容易因?yàn)樾盘?hào)抖動(dòng)寫(xiě)入多條垃圾記錄后期還得手動(dòng)清。3. 畫(huà)面組態(tài)與腳本聯(lián)動(dòng)案例實(shí)現(xiàn)3.1 在畫(huà)面中顯示用戶(hù)歸檔數(shù)據(jù)存進(jìn)歸檔后需要在畫(huà)面上展示。WinCC提供了“用戶(hù)歸檔表格”控件User Archive Control專(zhuān)門(mén)用來(lái)顯示和操作用戶(hù)歸檔數(shù)據(jù)。在WinCC圖形編輯器里拖入控件右鍵打開(kāi)屬性把“歸檔名稱(chēng)”指向DeviceLog控件就會(huì)自動(dòng)列出所有字段。如果覺(jué)得默認(rèn)字段名不好看可以在歸檔管理器的字段編輯中設(shè)置“顯示名稱(chēng)”畫(huà)面表格的列標(biāo)題就會(huì)變成中文名稱(chēng)比如“設(shè)備編號(hào)”“操作員”“操作類(lèi)型”。這個(gè)細(xì)節(jié)對(duì)最終用戶(hù)很重要直接顯示英文列名會(huì)被現(xiàn)場(chǎng)操作員嫌難看??丶€支持多種操作模式只讀、編輯、刪除記錄。如果不想讓操作員隨意刪改歷史就把控件屬性設(shè)為只讀或者隱藏按鈕。安全性方面用戶(hù)歸檔表格控件默認(rèn)允許對(duì)數(shù)據(jù)進(jìn)行完全操作生產(chǎn)環(huán)境必須按角色收權(quán)。3.2 用C腳本實(shí)現(xiàn)置位、復(fù)位與二次確認(rèn)現(xiàn)場(chǎng)操作員經(jīng)常誤碰按鈕所以我在啟動(dòng)和停止按鈕上都加了二次確認(rèn)。C腳本實(shí)現(xiàn)起來(lái)很直接#include apdefap.h void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { if (MessageBox(NULL, 確認(rèn)啟動(dòng)設(shè)備, 二次確認(rèn), MB_YESNO | MB_ICONQUESTION) IDYES) { SetTagBit(StartCmd, 1); SetTagBit(StartCmd, 0); // 置位后復(fù)位產(chǎn)生一個(gè)脈沖 } }置位后立即復(fù)位是為了讓下游PLC只識(shí)別一次上升沿避免按鈕一直按住導(dǎo)致變量長(zhǎng)時(shí)間為1觸發(fā)多次動(dòng)作。這個(gè)習(xí)慣在自動(dòng)化邏輯里很常見(jiàn)叫“脈沖置位”。同時(shí)用戶(hù)要求每次操作都能追溯所以我在腳本里把操作記錄寫(xiě)入OperatorLog歸檔。具體做法是用GetTagChar讀取畫(huà)面上輸入的“操作員”字符串再用用戶(hù)歸檔的InsertRecord和SetFieldValue寫(xiě)入字段值。#include apdefap.h void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { char operatorName[128]; GetTagChar(OperatorInput, operatorName); MyInsertLog(operatorName, 1); }這里的MyInsertLog是我封裝的一個(gè)公共函數(shù)放在全局腳本里這樣可以避免每個(gè)按鈕里重復(fù)寫(xiě)一大段插入代碼。全局腳本的函數(shù)在任意畫(huà)面都能調(diào)用方便統(tǒng)一維護(hù)。3.3 插入記錄與按鈕跳轉(zhuǎn)插入用戶(hù)歸檔記錄有幾種方式最常見(jiàn)的就是用控件對(duì)象的InsertRecord方法。下面這段腳本演示如何在用戶(hù)歸檔表格控件中插入一條記錄并給字段賦值#include apdefap.h void MyInsertLog(char* lpszOperator, int nAction) { OBJECT objArchive; objArchive GetObject(過(guò)程畫(huà)面.用戶(hù)歸檔表格1); // 在歸檔末尾插入新記錄 objArchive.InsertRecord(0, OperatorLog); // 設(shè)置字段值兩個(gè)文本字段和一個(gè)整數(shù)字段 objArchive.SetFieldValue(0, Operator, 0, lpszOperator); objArchive.SetFieldValue(0, Action, 0, nAction); }InsertRecord的第一個(gè)參數(shù)是記錄索引第二個(gè)參數(shù)是歸檔名稱(chēng)。注意InsertRecord插入的是空記錄真正往里面填內(nèi)容要靠SetFieldValue。SetFieldValue的參數(shù)比較繁瑣第一個(gè)參數(shù)是記錄索引第二個(gè)是字段名稱(chēng)第三個(gè)通常填0第四個(gè)是實(shí)際值。畫(huà)面上做按鈕跳轉(zhuǎn)更常用VBS腳本一行就夠ScreenChange(主監(jiān)控畫(huà)面)如果你偏愛(ài)在C腳本里操作也可以用OnOpenPicture或SetPictureName函數(shù)但日常習(xí)慣上頁(yè)面跳轉(zhuǎn)這種界面邏輯用VBS更順手C腳本更適合做變量和數(shù)據(jù)處理。3.4 打印功能實(shí)現(xiàn)現(xiàn)場(chǎng)有時(shí)候需要把用戶(hù)歸檔里的數(shù)據(jù)導(dǎo)出來(lái)打印。最簡(jiǎn)單的做法是利用用戶(hù)歸檔表格控件的導(dǎo)出功能將當(dāng)前數(shù)據(jù)保存為CSV再通過(guò)ShellExecute調(diào)用系統(tǒng)關(guān)聯(lián)程序打開(kāi)讓用戶(hù)手動(dòng)打印。#include apdefap.h #pragma option(1,1) void OnClick(char* lpszPictureName, char* lpszObjectName, char* lpszPropertyName) { OBJECT obj GetObject(過(guò)程畫(huà)面.用戶(hù)歸檔表格1); obj.SaveToFile(C:\\Temp\\DeviceLog.csv); ShellExecute(NULL, open, C:\\Temp\\DeviceLog.csv, NULL, NULL, 1); }這里有個(gè)很重要的細(xì)節(jié)SaveToFile的目錄必須預(yù)先存在否則調(diào)用會(huì)靜默失敗腳本不報(bào)錯(cuò)但文件就是出不來(lái)。我第一次就用直接路徑結(jié)果怎么調(diào)都沒(méi)反應(yīng)后來(lái)加了一句目錄創(chuàng)建才解決。4. 常見(jiàn)問(wèn)題與排查實(shí)錄4.1 WinCC安裝與授權(quán)常見(jiàn)問(wèn)題從你搜的熱詞里我知道很多人卡在WinCC安裝和授權(quán)上?!皐incc怎么卸載干凈”“sim_ekb_install安裝授權(quán)報(bào)錯(cuò)”這些問(wèn)題我在實(shí)施中也遇到過(guò)。WinCC安裝務(wù)必定順序先裝SQL Server再裝WinCC最后裝授權(quán)。順序顛倒會(huì)有一堆莫名其妙的問(wèn)題。卸載WinCC千萬(wàn)別圖省事直接刪文件夾要去控制面板走正規(guī)卸載流程卸載后清理安裝目錄的殘留文件、注冊(cè)表里的相關(guān)鍵值以及臨時(shí)目錄里的緩存文件否則第二次安裝極易報(bào)錯(cuò)。安裝時(shí)如果提示“無(wú)法啟動(dòng)基本應(yīng)用程序”十有八九是SQL Server服務(wù)沒(méi)起來(lái)。到服務(wù)管理器里找到名字類(lèi)似“WINCC”的SQL服務(wù)把它手動(dòng)啟動(dòng)并設(shè)為自動(dòng)啟動(dòng)問(wèn)題基本能解決。授權(quán)時(shí)如果彈出CrypAcquireContext錯(cuò)誤基本是系統(tǒng)的加密服務(wù)出問(wèn)題了重啟一遍電腦或者修復(fù)安裝一下再試別死磕授權(quán)工具。4.2 用戶(hù)歸檔不寫(xiě)入數(shù)據(jù)這是用戶(hù)歸檔模塊被問(wèn)得最多的問(wèn)題。排查順序有講究檢查歸檔“記錄”頁(yè)是否勾選了“可寫(xiě)”權(quán)限。如果不勾腳本寫(xiě)入會(huì)被拒絕。檢查歸檔字段和變量連接的數(shù)據(jù)類(lèi)型是否匹配。文本字段連了整型變量寫(xiě)入必失敗。檢查觸發(fā)條件是否真的滿(mǎn)足。比如用了“變化時(shí)”觸發(fā)但變量根本沒(méi)發(fā)生變化記錄自然不會(huì)產(chǎn)生。如果用的是腳本手動(dòng)插入檢查按鈕事件有沒(méi)有執(zhí)行。我習(xí)慣在腳本開(kāi)頭加一句測(cè)試代碼比如SetTagBit(DebugVar, 1)先確認(rèn)腳本確實(shí)跑了。數(shù)據(jù)寫(xiě)入了表格卻不顯示那就不是寫(xiě)入問(wèn)題是控件數(shù)據(jù)源沒(méi)選對(duì)。用戶(hù)歸檔表格控件默認(rèn)可能指向了空歸檔或者別的歸檔要手動(dòng)在屬性里選回DeviceLog。4.3 畫(huà)面模擬與全局腳本在WinCC里想調(diào)試畫(huà)面布局和腳本邏輯用的是“仿真實(shí)”功能不是“運(yùn)行”按鈕。熱搜詞里有人問(wèn)“wincc unified畫(huà)面模擬點(diǎn)哪個(gè)”其實(shí)Unified和經(jīng)典WinCC V7的模擬入口差不多都在工具欄的“開(kāi)始仿真實(shí)”位置快捷鍵通常是CtrlF5。仿真實(shí)模式下變量不會(huì)真實(shí)讀寫(xiě)PLC但腳本邏輯、畫(huà)面跳轉(zhuǎn)、用戶(hù)歸檔寫(xiě)入都會(huì)正常執(zhí)行。這意味著你可以用模擬模式完整測(cè)一遍“按鈕點(diǎn)擊-二次確認(rèn)-寫(xiě)歸檔-表格刷新”的流程非常方便。全局腳本Global Script則用來(lái)放公共函數(shù)。比如我的MyInsertLog函數(shù)就放在了全局腳本里所有畫(huà)面共用。全局腳本可以設(shè)置觸發(fā)條件比如周期觸發(fā)、變量觸發(fā)、事件觸發(fā)。如果你要做定時(shí)記錄就建一個(gè)周期為1秒的動(dòng)作在里面調(diào)用插入函數(shù)。4.4 C腳本與VB腳本怎么選我接觸過(guò)的WinCC項(xiàng)目中腳本混用很正常。我的判斷標(biāo)準(zhǔn)是涉及位操作、變量讀寫(xiě)、歸檔操作優(yōu)先用C腳本因?yàn)镃在處理數(shù)據(jù)時(shí)更直接涉及窗口跳轉(zhuǎn)、控件屬性設(shè)置、頁(yè)面邏輯用VBS更順手代碼更短可讀性也好。但有一點(diǎn)必須注意別在同一個(gè)按鈕的事件里同時(shí)寫(xiě)C和VBS邏輯容易打架后續(xù)維護(hù)也看不懂。要么一個(gè)按鈕就一個(gè)模塊要么把公共邏輯拆到全局腳本里。打個(gè)比方按鈕點(diǎn)擊后先用C腳本完成變量置位和歸檔寫(xiě)入再用VBS的ScreenChange跳頁(yè)面這是合理的分工。把所有邏輯堆在一個(gè)語(yǔ)言里反而會(huì)讓腳本變得臃腫。最后再補(bǔ)充一個(gè)這幾年做WinCC項(xiàng)目的體會(huì)用戶(hù)歸檔雖然好用但它畢竟是單機(jī)文件存儲(chǔ)數(shù)據(jù)量到了一定級(jí)別比如單個(gè)歸檔超過(guò)幾十萬(wàn)條記錄操作性能就會(huì)出現(xiàn)下降。遇到這種情況優(yōu)先考慮給舊記錄做定期導(dǎo)出和清空而不是用外部數(shù)據(jù)庫(kù)硬扛。畢竟在工控現(xiàn)場(chǎng)穩(wěn)定是第一位的功能再?gòu)?qiáng)大如果三天兩頭出問(wèn)題客戶(hù)也不會(huì)買(mǎi)賬。如果你正在上手用戶(hù)歸檔建議先做一個(gè)小Demo把整個(gè)鏈路跑通建歸檔、定字段、放控件、寫(xiě)腳本、插入記錄、顯示查詢(xún)熟悉一遍流程再去接實(shí)際項(xiàng)目會(huì)從容很多。本文還有配套的精品資源點(diǎn)擊獲取