示例#1
0
        override protected void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e)
        {
            try
            {
                var tEventTag = monitoredItem.Handle as TheOPCEvent;
                if (tEventTag == null)
                {
                    TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Internal error: invalid monitored item handle in Event", eMsgLevel.l1_Error, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                    return;
                }

                var tEventHost = tEventTag.GetHostThing();
                if (tEventHost == null)
                {
                    TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Event host thing not found", eMsgLevel.l1_Error, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                    return;
                }

                EventFieldList notification = e.NotificationValue as EventFieldList;

                if (notification == null)
                {
                    TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Internal error: notification is not an EventFieldList", eMsgLevel.l1_Error, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                    return;
                }

                // check the type of event.
                NodeId eventTypeId = ClientUtils.FindEventType(monitoredItem, notification);

                if (MyOPCServer.EnableOPCDataLogging)
                {
                    var logInfo = new Dictionary <string, object>
                    {
                        { "ReceiveTime", DateTimeOffset.Now },
                        { "TagId", DisplayName },
                        { "EventTypeId", eventTypeId },
                        { "Value", notification.EventFields.Aggregate("", (s, ef) => $"{s} [{ef.TypeInfo},{ef.Value}]") },
                        { "Server", notification.Message.PublishTime },
                        { "MonitoredItem", monitoredItem?.ClientHandle },
                        { "SequenceNumber", notification.Message?.SequenceNumber },
                    };
                    TheOPCTag.LogOPCData(logInfo, MyOPCServer.GetLogAddress(), $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}");
                }


                // ignore unknown events.
                if (NodeId.IsNull(eventTypeId))
                {
                    TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Unknown eventTypeId", eMsgLevel.l1_Error, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}: received {eventTypeId}"));
                    return;
                }

                EventFilter filter = monitoredItem.Status.Filter as EventFilter;

                bool isRefreshEvent = false;

                var            eventData   = new Dictionary <string, object>();
                DateTimeOffset sourceTime  = DateTimeOffset.Now;
                string         conditionId = null;
                bool?          bRetain     = null;

                int index = 0;
                foreach (var field in filter.SelectClauses)
                {
                    var value = index < notification?.EventFields.Count ? notification?.EventFields[index].Value : null;
                    if (value is ExtensionObject || value is ExtensionObject[])
                    {
                        value = MyOPCServer.DecodeExtensionObjectToJson(value, out var ignored);
                    }
                    var name = field?.BrowsePath?.Count > 0 ? field.BrowsePath[0].Name : null;

                    if (value is NodeId)
                    {
                        if (name == "EventType")
                        {
                            var eventType = value as NodeId;
                            if (eventType == Opc.Ua.ObjectTypeIds.RefreshStartEventType)
                            {
                                TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Received Refresh Start event", eMsgLevel.l4_Message, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));

                                _currentConditionsByConditionId.Clear();
                                if (_bRefreshing)
                                {
                                    // Two overlapping refresh starts received
                                    TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Received more than one Refresh Start event", eMsgLevel.l2_Warning, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                                }
                                _bRefreshing          = true;
                                _lastRefreshStartTime = DateTimeOffset.Now;
                                isRefreshEvent        = true;
                            }
                            else if (eventType == Opc.Ua.ObjectTypeIds.RefreshEndEventType)
                            {
                                TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Received Refresh End event", eMsgLevel.l4_Message, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                                if (!_bRefreshing)
                                {
                                    TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Received Refresh End event without matching start event", eMsgLevel.l2_Warning, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                                    // refresh end received without refresh start
                                }
                                _bRefreshing   = false;
                                isRefreshEvent = true;
                                if (EventInfo.AggregateRetainedConditions)
                                {
                                    WriteAggregatedConditionsToProperty(tEventHost, TheCommonUtils.CDate(notification.Message.PublishTime));
                                }
                            }
                        }
                        value = value.ToString();
                    }
                    if (name == null)
                    {
                        if (field.TypeDefinitionId == Opc.Ua.ObjectTypeIds.BaseEventType)
                        {
                            name = "ConditionId";
                        }
                    }
                    if (name != null)
                    {
                        if (aliasMap.TryGetValue(index, out var alias))
                        {
                            eventData[alias] = value;
                        }
                        else
                        {
                            eventData[name] = value;
                        }
                        switch (name)
                        {
                        case "ConditionId":
                            conditionId = value?.ToString();
                            break;

                        case "Retain":
                            bRetain = TheCommonUtils.CBool(value);
                            break;

                        case "Time":
                            sourceTime = TheCommonUtils.CDate(value);
                            break;
                        }
                    }
                    index++;
                }
                if (!isRefreshEvent)
                {
                    var eventInfoProperties = EventInfo.GetPropertyNames();
                    var filteredEventProps  = EventInfo.Properties?.Count > 0 ? eventData.Where(pk => !requiredEventFields.Contains(pk.Key) || eventInfoProperties.Contains(pk.Key))
                                              //.Select(kv =>
                                              //{
                                              //    if (aliasMap.TryGetValue(kv.Key, out var alias))
                                              //    {
                                              //        return new KeyValuePair<string, object>(alias, kv.Value);
                                              //    }
                                              //    return kv;
                                              //})
                                              .ToDictionary(kv => kv.Key, kv => kv.Value) : eventData;

                    //if (_bRefreshing)
                    //{
                    //    filteredEventProps["Refresh"] = true;
                    //}

                    if (!EventInfo.AggregateRetainedConditions)
                    {
                        // Raw events
                        // TODO avoid resending events due to a refresh?
                        var eventAsJson = TheCommonUtils.SerializeObjectToJSONString(filteredEventProps);
                        TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Received raw event {eventAsJson}", eMsgLevel.l6_Debug, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                        tEventHost.GetBaseThing().SetProperty(DisplayName, eventAsJson, TheCommonUtils.CDate(notification.Message.PublishTime));
                    }
                    else
                    {
                        // Aggregated Condition State
                        if (conditionId != null)
                        {
                            if (bRetain == false)
                            {
                                TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Removed current event {conditionId}", eMsgLevel.l6_Debug, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                                _currentConditionsByConditionId.RemoveNoCare(conditionId);
                            }
                            else
                            {
                                TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.ESSENTIALS) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Added current event {conditionId}", eMsgLevel.l6_Debug, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}"));
                                _currentConditionsByConditionId[conditionId] = filteredEventProps;
                            }
                            if (!_bRefreshing)
                            {
                                WriteAggregatedConditionsToProperty(tEventHost, TheCommonUtils.CDate(notification.Message.PublishTime));
                            }
                        }
                    }

                    // Legacy format: do we still need to support this? Existing event support was not really usable...
                    //foreach (var eventField in eventData)
                    //{
                    //    string propertyName;
                    //    if (tEventHost is TheOPCUATagThing) // TODO Create a TheOPCUAEventThing
                    //    {
                    //        // If this is a dedicated event thing, use the original value name
                    //        // TODO Is this really what we want to do or do we also want to use the full browsepath for dedicated event things?
                    //        throw new NotImplementedException("Should never get here");
                    //        //propertyName = field.BrowsePath[0].Name;
                    //    }
                    //    else
                    //    {
                    //        // This is an external, multi-event thing: use the browsepath to avoid collisions with properties from multiple events
                    //        propertyName = DisplayName + "." + eventField.Key;
                    //    }
                    //    SetPropertyFromVariant(tEventHost, propertyName, eventField.Value, sourceTime);
                    //}
                }
            }
            catch (Exception ex)
            {
                TheBaseAssets.MySYSLOG.WriteToLog(78102, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyOPCServer.GetBaseThing().EngineName, $"Internal error processing event notification", eMsgLevel.l1_Error, $"{DisplayName} {GetNodeIdForLogs()} {EventInfo.AggregateRetainedConditions}: {ex.ToString()}"));
            }
        }