MonitoredItem
每個監控項均指明了要監控的項目(item)和用來發送通知的訂閱。
item可以是一個節點的屬性(node attribute)。


- MonitorItem可以監控一個屬性,一個變量或者一個事件
- 可以通過MonitorItem定義的過濾器(fiter),來決定是否產生一個通知
- Queue attribute定義了可以被緩存的通知數量,可以通過配置策略決定丟棄新消息還是最老的消息
Triggering model
- MonitoredItem服務允許某item只有在關聯Item被觸發時才會被觸發
- 這是通過在觸發對象和被觸發對象間建立連接來實現的

Notification
描述了數據變化和事件的數據結構,通知會被打包為NotificationMessage並傳送給Client。
訂閱會以客戶定義的發布間隔周期性的發送NotificationMessage。
Subscription
訂閱用來向客戶端報告通知,其行為可以被總結如下:
- 訂閱包含一組由客戶端分配的監控項。監控項可以生成通知,這些通知,由訂閱發送給客戶端
- 訂閱擁有一個發布間隔,訂閱的發布間隔定義了訂閱執行的循環率。每次執行,訂閱均試圖發送一條NotificationMessages,NotificationMessages中包含了還沒有報告給客戶端的通知
- 訂閱以回應發布請求的方式向客戶端發送NotificationMessages。發布請求通常以接收順序存儲到Session中,當有通知需要發送時,在每次發布循環時,會從隊列中取出相應的請求,並發送通知到客戶端,如果沒有待發送通知,請求則不會從隊列中被刪除
- 在循環的開始,如果已經存在待發送通知但還沒有發布請求,服務器將會進入等待狀態,一旦接收到發布請求,則立即向客戶端發送通知,無需等待另外一次循環
- 訂閱有一個存活計數器,保存了沒有發送通知的周期循環次數,當循環次數達到用戶在創建訂閱時配置的預置,則會發送一條存活消息到客戶端,同時從隊列中取出一條發布請求,用於表示該訂閱仍然處於存活狀態。存活NotificationMessage中不包含通知,但包含下一條消息的序列號
- 訂閱是否發布通知可以由客戶端在創建時指定,也可以后續通過SetPublishMode服務設置,設置為Fasle時,訂閱將停止向客戶端推送通知,但是訂閱會繼續執行,且持續發送存活消息
- 訂閱包含一個壽命計數器,保存了在沒有發布請求時經歷的循環次數,當達到閾值時,會刪除這個訂閱以及與訂閱相關的監控項。在刪除訂閱時,會發送一條StateChangeNotification消息,並攜帶狀態碼Bad_Timeout
- Session維護了已發送通知的轉發隊列,只有當客戶端確認消息接收后,才會從隊列宗移除,服務器應當保存有兩倍於發送請求數量的消息,這種能力可以由服務器的profile定義,如果轉發隊列滿,則刪除最舊的消息。當訂閱被轉移到另外的session時,轉發隊列同時也需要遷移過去
序列號是一個UINT32,並從1開始向前滾動。
當訂閱創建后,在第一個周期結束時,會向client發送一條消息,用於通知客戶端訂閱可用。如果有通知要發送,則發送NotificationMessage,如果沒有,則發送存活消息,並設置序列號為1,這是唯一不需要等待到keep alive閾值的場景。
客戶端接受消息要比發布周期更加頻繁,因一個發布周期可能包含有多條消息,但客戶端可以設置服務器不緩存發布通知來減輕壓力,但會增加響應的延時。
在訂閱的聲明周期中,序列號不會被重置,也即在40億消息中不會出現重復的消息ID。
消息序列號還可以用於消息重發。
訂閱被設計為獨立於具體的通信協議,短暫的連接丟失不會導致丟失數據和事件。在設計時,要確保該特性得以正確實現,也即能夠處理較長時間的通訊中斷和有計划斷鏈。如果服務器支持該特性,服務器的緩存區將會設計的比較大。
HasEventSource
HasEventSource引用類型是一個具體的引用類型,並可以直接被使用,是HierarchicalReferences的子類。
這個引用類型的語義是將event source(事件源)以一種層次化的、非循環的方式關聯起來。該類型以及該類型的所有子類是打算用來幫助發現服務器能夠產生的事件。但對於服務器來說,並不需要強制的建立從事件源(EventSource,產生事件)到事件通知器的關系,例如server對象,其隱含的表示是所有事件源的通知器。
該關系的起點是一個事件訂閱的源(一個對象,該對象的EventNotifer屬性的SubscribeToEvent位有效)。
該關系的終點可以是任意NodeClass節點,只要該節點能夠通過訂閱產生事件通知,並傳遞給關系源端。
另外,從”A“點開始,沿着HasEventSource或其子關系不能再回到A點,但是允許存在多條路徑都指向節點“B“。
HasNotifier
HasNotifier引用也是一個可以被直接使用的關系。
HasNotifier引用的語義是將作為通知器的節點與其他通知器對象節點關聯起來。該引用的目的是建立事件通知對象(event notifying object)的層次化結構,而且HasNotifer是HasEventSource的子類。
該引用的起點需要是能夠作為事件訂閱源的對象或視圖,終點同樣。事件訂閱源是指EventNotifier屬性中“SubscribeToEvents”生效的對象。
如果HasNotifier引用的終點產生了一個事件,那么該引用的起點同樣可以提供這個事件。也即通過HasNotifier引用,可以建立起事件通知的層次。


Alarm
告警是AcknowledgeConditions的特殊化,相比Condition告警增加了活動狀態,以及擱置和抑制狀態。


- 告警如果處於活動狀態(Active)則表明條件所表示的狀況正在發生,如果Active=False則表明處於正常狀態
- 有些告警會引入Active狀態的子狀態,入high level state與critical high state
- 擱置狀態(Shelved)可以由操作員通過OPC UA方法設置,抑制狀態(Suppressed)由服務器出於內部原因設置,告警服務器通常會實現抑制、擱置和停止服務特性,以避免操作員被告警風暴淹沒,而能夠專注於真正嚴重的告警
- 擱置、抑制和停止服務狀態與Disable狀態不同,它們表明告警仍然生效,並繼續通過訂閱分發至客戶端
下圖描述了典型的告警時間線:


在值達到Alarm Limit時,產生了告警
- 在Ack Delay期間,告警處於Unacknowledged狀態,也即在此時間段內,操作員沒有感知到告警,因此未進行操作
- 當操作員感知到告警,並確認后,告警進入了Acknowledged狀態,此時操作員需要時間確認這個告警並作出反應,此時處於Operator Response Delay
- 之后采取行動,進入到Process Delay狀態,到操作生效為止
- 之后產生效果,值向下,並在經過告警死區之后消除並轉入Normal狀態
- 如果不進行操作,則值繼續上升並產生后果
Condition Instance
Condition通常會有狀態和子狀態,因此在AddressSpace中保存Condition的實例是有意義的。如果Server選擇暴露condition,那么condition通常是作為對象的一部分存在的,也即對象“擁有”這個條件。
如:
一個溫度傳感器內置了高溫告警,則這個告警在地址空間中會以溫度傳感器實例的部件(hasComponent)關系的形式作為溫度傳感器的一部分,且這個告警是LimitAlarmType的實例。
有些時候可以選擇不在地址空間中暴露condition,這樣就沒有辦法修改condition的狀態。
告警和狀態的審計是系統中非常重要的安全功能,當用戶調用方法更改Condition的狀態時,會產生AuditConditionAcknowledgeEventType類型的事件。
HasCondition Reference
該引用的語義是關聯ConditionSource和它的Condition,每個ConditionSource都應該是HasEventSource或其子引用的目標節點。
HasCondition關系可以用在VariabeType或者ObjectType之上,也可以用於它們的實例聲明,HasCondition的目標節點則可以是ConditionType類型或者實例。
- 如果在類型中(ObjectType/VariableType)中有HasCondition關系,其實例也要繼承
- 如果類型中引用的是ConditionType,其類型實例也要指向該ConditionType
- 如果類型上不允許配置HasCondition,則可以在實例上增加
AddressSpace Sample

總結來說:
- HasNotifer維護了一個通知器的層次,目的端產生的事件在源端可讀,由此可以在不同的通知器層次有針對性的讀取事件(如只讀Area1或者只讀Tank Farm)
- HasEventSource用於指明事件生成的源,只有HasEventSource及其子類型所指向的目標節點上可以由HasCondition關系
- HasCondition關系表明了能夠具體生成的Condition/告警
- 通常的ConditionType對象是作為對象的一部分存在的,這里的MyAlarmTypeA實際上是從ConditionType繼承而來
- 某些服務器中,HasCondition的target節點可以是ConditionType
另外,在類型中定義的ConditionType是可以在實例中得到繼承的,如下圖所示:


幾個問題
- Event、Condition和Alarm是什么關系
- EventType是ConditionType的父類
- ConditionType是AlarmType的父類
- Event、Condition和Alarm是其實例
- Event最為泛化,主要是定義了事件的基本屬性
- Condition則擁有狀態
- Alarm則擁有更多可被設置的狀態
- HasEventSource、HasNotifier有什么區別
- HasEventSource指明了事件產生的源
- HasNotifier是HasEventSource的子類
- HasNotifer組織的是一張通知器的網,關系的目標節點所產生的事件在源端也可以看到,可供用戶定義自己查看事件的范圍
- Condition只能加到HasEventSource的目標節點上
- GeneratesEvent、AlwaysGenerateEvent引用有什么區別
- GeneratesEvent表明ObjectType,VariableType可能產生事件,以及Method在調用時可能產生事件
- AlwaysGenerateEvent的起點只能是Method,且在每次調用時必然產生事件
- GeneratesEvent和AlwaysGenerateEvent的終點只能是表示EventType及其子類
參考資料
- 《OPC統一架構From馬克》2.10,4.9,5.7章節
- 《OPC UA Part 3 - Address Space Model Release 1.04 Specification》4.6, 7.15, 7.16, 7.17, 7.18章節
- 《OPC UA Part 4 - Services Release 1.04 Specification》5.12, 5.13章節
- 《OPC UA Part 9 - Alarms and Conditions Release 1.04 Specification》 第4章,第5章,第6章,附錄B.2節