示例#1
0
        public override string ProcessEventData(TheThing thing, object evnt, DateTimeOffset defaultTimestamp)
        {
            if (!(evnt is EventData))
            {
                return "Invalid Payload";
            }
            if (thing == null)
            {
                return "AMQP Converter does not support thing mapping";
            }
            var eventData = evnt as EventData;
            DateTimeOffset time;
            if (eventData.Properties.ContainsKey("time"))
            {
                time = TheCommonUtils.CDate(eventData.Properties["time"]);
            }
            else if (defaultTimestamp == DateTimeOffset.MinValue)
            {
                time = eventData.SystemProperties.EnqueuedTimeUtc;
            }
            else
            {
                time = defaultTimestamp;
            }

            foreach (var prop in eventData.Properties)
            {
                var tProp = thing.SetProperty(prop.Key, prop.Value, time);
                //var tProp = thing.GetProperty(prop.Key, true);
                //tProp.cdeCTIM = time;
                //tProp.Value = prop.Value;
                //tProp.cdeE = 0x40; // NMI visible
            }
            return null;
        }
 public void DateTimeOffsetMinMaxValueTest()
 {
     {
         var date = DateTime.MinValue;
         var dateTimeOffsetValue = TheCommonUtils.CDate(date);
         var expectedValue       = DateTimeOffset.MinValue;
         Assert.AreEqual(expectedValue, dateTimeOffsetValue);
     }
     {
         var date = DateTime.MaxValue;
         var dateTimeOffsetValue = TheCommonUtils.CDate(date);
         var expectedValue       = DateTimeOffset.MaxValue;
         Assert.AreEqual(expectedValue, dateTimeOffsetValue);
     }
     // TODO Figure out a way to run these tests in interesting timezones as they depend on the local machines timezone:
     // UTC, Berlin (UTC+1 DST), UTC-1, Casablanca (UTC with DST), UTC-12 (International dateline West), UTC+12, UTC+14 (Kiritimati Island)
     // For now: run one of the build machines in UTC+1, the other in PST.
     {
         var            date = new DateTime(1, 1, 1, 0, 10, 0, DateTimeKind.Local);
         var            dateTimeOffsetValue = TheCommonUtils.CDate(date);
         var            expectedTimeZone    = TimeZoneInfo.Local.GetUtcOffset(date);
         DateTimeOffset expectedValue;
         if (expectedTimeZone > TimeSpan.Zero)
         {
             expectedValue = DateTimeOffset.MinValue;
         }
         else
         {
             expectedValue = new DateTimeOffset(date);
         }
         Assert.AreEqual(expectedValue, dateTimeOffsetValue);
     }
     {
         var            date = new DateTime(9999, 12, 31, 23, 59, 50, DateTimeKind.Local);
         var            dateTimeOffsetValue = TheCommonUtils.CDate(date);
         DateTimeOffset expectedValue;
         if (TimeZoneInfo.Local.GetUtcOffset(date) < TimeSpan.Zero)
         {
             expectedValue = DateTimeOffset.MaxValue;
         }
         else
         {
             expectedValue = new DateTimeOffset(date);
         }
         Assert.AreEqual(expectedValue, dateTimeOffsetValue);
     }
 }
示例#3
0
        /// <summary>
        /// Checks if a property already matches a desired value.  Sets the property and
        /// notifies listeners only when necessary.
        /// </summary>
        /// <typeparam name="T">Type of the property.</typeparam>
        /// <param name="storage">Reference to a property with both getter and setter.</param>
        /// <param name="value">Desired value for the property.</param>
        /// <param name="cdeT">Type of this property - important for comparison with old value</param>
        /// <param name="cdeE">Extended Flags of the value</param>
        /// <param name="propertyName">Name of the property used to notify listeners.  This
        /// value is optional and can be provided automatically when invoked from compilers that
        /// support CallerMemberName.</param>
        /// <returns>True if the value was changed, false if the existing value matched the
        /// desired value.</returns>
        protected bool SetProperty <T>(ref T storage, T value, int cdeT, int cdeE, string propertyName = null)
        {
            if ((cdeE & 8) == 0)
            {
                if ((cdeE & 1) != 0)    //Required in case the property is encrypted.
                {
                    if (Equals(storage, value))
                    {
                        return(false);
                    }
                }
                else
                {
                    switch (cdeT)
                    {
                    case 1:
                        if (Math.Abs(TheCommonUtils.CDbl(storage) - TheCommonUtils.CDbl(value)) < Double.Epsilon &&
                            (storage == null && value == null || storage != null && value != null))        // 3.217: treat 0 and null as different
                        {
                            return(false);
                        }
                        break;

                    case 2:
                        if (TheCommonUtils.CBool(storage) == TheCommonUtils.CBool(value) &&
                            (storage == null && value == null || storage != null && value != null))        // 3.217: treat 0 and null as different
                        {
                            return(false);
                        }
                        value = (T)((object)TheCommonUtils.CBool(value));
                        break;

                    case 3:
                        if (storage != null && value != null && TheCommonUtils.CDate(storage) == TheCommonUtils.CDate(value))
                        {
                            return(false);
                        }
                        break;

                    case 4:     //Binary Comparison - TODO:CODEREVIEW Could be very expensive to do Byte[] comparison
                        if ((storage == null && value == null))
                        {
                            return(false);                                       // || ((storage as byte[]).GetHashCode() == (value as byte[]).GetHashCode())) return false;
                        }
                        break;

                    case 5:     //Function - Never Set it!
                        return(false);

                    case 6:
                        if (TheCommonUtils.CGuid(storage) == TheCommonUtils.CGuid(value))
                        {
                            return(false);
                        }
                        break;

                    default:
                        if (Equals(storage, value))
                        {
                            return(false);
                        }
                        break;
                    }
                }
            }
            storage = value; // CORE REVIEW Markus: SHould we clone the value here to prevent future modification?
            // CODE REVIEW: There is a race condition between setting mHasChanged and delivering the change notification. Should we raise the notification outside or is this mostly obsolete anyway (XAML only)?
            OnPropertyChanged(propertyName);
            return(true);
        }
示例#4
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()}"));
            }
        }