Esempio n. 1
0
 public TheOPCUATagThing(TheThing pThing, TheOPCTag pTag)
     : base(pThing)
 {
     MyBaseThing.DeviceType = eOPCDeviceTypes.OPCLiveTag;
     Reset();
     MyBaseThing.RegisterEvent("OnInitialized", sinkInit);
     MyBaseThing.SetIThingObject(this);
 }
Esempio n. 2
0
        void SetPropertyFromVariant(ICDEThing thing, string name, Variant variant, DateTimeOffset sourceTime)
        {
            var            prop      = thing.GetProperty(name, true);
            var            dataValue = new DataValue(variant);
            ePropertyTypes?tType;
            var            cdeValue = TheOPCTag.ChangeType(dataValue, dataValue, out tType);

            prop.cdeT    = (int)(tType ?? ePropertyTypes.TString);
            prop.cdeCTIM = sourceTime;
            prop.Value   = cdeValue;
        }
Esempio n. 3
0
        public override void HandleMessage(ICDEThing sender, object pIncoming)
        {
            TheProcessMessage pMsg = pIncoming as TheProcessMessage;

            if (pMsg == null || pMsg.Message == null)
            {
                return;
            }

            var cmd = pMsg.Message.TXT.Split(':');

            switch (cmd[0])
            {
            case "CALL_METHOD":
            case nameof(MsgOPCUAMethodCall):
                string error         = "Unexpected";
                string exceptionText = "";

                MsgOPCUAMethodCall callInfo        = null;
                byte[]             largeOutput     = null;
                string             outParamsAsJson = null;
                IList <object>     outputArguments = null;
                if (m_Method == null)
                {
                    error = "Method meta data not initialized";
                }
                else if (m_Method.MyOPCServer == null)
                {
                    error = "Method not inititialized";
                }
                else if (m_Method.MyOPCServer.m_session == null)
                {
                    error = "OPC UA session not created";
                }
                else
                {
                    try
                    {
                        if (TheCommonUtils.cdeIsLocked(m_Method))
                        {
                            TheBaseAssets.MySYSLOG.WriteToLog(78401, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM(MyBaseThing.EngineName, String.Format("[{0}] Method called concurrently", m_Method.MyOPCServer.GetLogAddress()), eMsgLevel.l4_Message, String.Format("{0}", MyBaseThing.Address)));
                        }
                        lock (m_Method)
                        {
                            if (m_Method.Args == null)
                            {
                                var browseError = m_Method.MyOPCServer.MethodBrowser(m_Method.TagRef, m_Method.DisplayName, m_Method);
                                if (!string.IsNullOrEmpty(browseError))
                                {
                                    error = "Unable to retrieve method metadata from server: " + browseError;
                                }
                            }
                            if (m_Method.Args == null)
                            {
                                error = "Unable to retrieve method metadata from server";
                            }
                            else
                            {
                                if (!string.IsNullOrEmpty(pMsg.Message.PLS))
                                {
                                    if (cmd[0] == nameof(MsgOPCUAMethodCall))
                                    {
                                        callInfo = TheCommRequestResponse.ParseRequestMessageJSON <MsgOPCUAMethodCall>(pMsg.Message);
                                        foreach (var argument in callInfo.Arguments)
                                        {
                                            TheThing.SetSafeProperty(this, argument.Key, argument.Value, ePropertyTypes.NOCHANGE);
                                        }
                                    }
                                    else
                                    {
                                        var tLst = TheCommonUtils.cdeSplit(pMsg.Message.PLS, ":;:", true, true).ToList();
                                        foreach (string t in tLst)
                                        {
                                            TheThing.SetPropertyFromBagItem(this, t);
                                        }
                                    }
                                }
                                object[] tArgs = new object[InputArgCnt];
                                for (int i = 0; i < InputArgCnt; i++)
                                {
                                    tArgs[i] = TheOPCTag.GetOPCValueFromCDEValue(InputArgs[i].cdeProperty == null ? null : InputArgs[i].cdeProperty.Value, InputArgs[i].OPCType);
                                }
#if OLD_UA
                                outputArguments = m_Method.MyOPCServer.m_session.CallWithTimeout(m_Method.ParentId, m_Method.TagRef, MethodCallTimeout, tArgs);
#else
                                outputArguments = m_Method.MyOPCServer.m_session.Call(m_Method.ParentId, m_Method.TagRef, tArgs);     //CM: C-labs extension: .CallWithTimeout(m_Method.ParentId, m_Method.TagRef, MethodCallTimeout, tArgs);
#endif
                                if (cmd[0] != nameof(MsgOPCUAMethodCall))
                                {
                                    if (TheThing.GetSafePropertyBool(this, "ReturnOutputAsJson"))
                                    {
                                        outParamsAsJson = TheCommonUtils.SerializeObjectToJSONString(outputArguments);
                                        //TheThing.SetSafePropertyString(this, "OutputAsJson", outParamsAsJson);
                                    }
                                    else
                                    {
                                        if (outputArguments != null && outputArguments.Count > 0)
                                        {
                                            for (int i = 0; i < outputArguments.Count; i++)
                                            {
                                                if (i < OutputArgs.Count)
                                                {
                                                    object value;
                                                    if (outputArguments[i] is byte[] && (outputArguments[i] as byte[]).Length > 4096 && largeOutput == null)
                                                    {
                                                        largeOutput = outputArguments[i] as byte[];
                                                        value       = "";
                                                    }
                                                    else
                                                    {
                                                        value = outputArguments[i];
                                                    }

                                                    cdeP tP = OutputArgs[i].cdeProperty;
                                                    if (tP != null)
                                                    {
                                                        //TheOPCTag.UpdateValueProperty(outputArguments[i] as DataValue, tP, outputArguments[i] as DataValue);
                                                        tP.Value = value;
                                                        // tP.SetValue(outputArguments[i], pMsg.Message.GetOriginator().ToString()); // CODE REVIEW: Why did we set the originator here? It's only really needed for remote things to break update cycles...
                                                    }
                                                }
                                                else
                                                {
                                                    TheBaseAssets.MySYSLOG.WriteToLog(78402, TSM.L(eDEBUG_LEVELS.FULLVERBOSE) ? null : new TSM(MyBaseThing.EngineName, String.Format("[{0}] Error processing method response for OPC Server", m_Method.MyOPCServer.GetLogAddress()), eMsgLevel.l2_Warning, String.Format("{0}: too many out parameters in method", MyBaseThing.Address)));
                                                }
                                            }
                                        }
                                    }
                                    MyBaseThing.LastUpdate = DateTimeOffset.Now;
                                    LastMessage            = string.Format("Success at {0}", MyBaseThing.LastUpdate);
                                }
                                error = "";
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        error         = "Method Call failed: " + e.Message;
                        exceptionText = e.ToString();
                        LastMessage   = error;
                        TheBaseAssets.MySYSLOG.WriteToLog(78403, TSM.L(eDEBUG_LEVELS.VERBOSE) ? null : new TSM(MyBaseThing.EngineName, String.Format("[{0}] Method Call failed", m_Method.MyOPCServer.GetLogAddress()), eMsgLevel.l1_Error, String.Format("{0}:{1}", MyBaseThing.Address, e.ToString())));
                    }
                }
                if (cmd[0] == nameof(MsgOPCUAMethodCall))
                {
                    if (callInfo?.ReturnRawJSON == true)
                    {
                        TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, new MsgOPCUAMethodCallResponse {
                            OutputArguments = new List <object> {
                                TheCommonUtils.SerializeObjectToJSONString(outputArguments)
                            }, Error = error
                        });
                    }
                    else
                    {
                        TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, new MsgOPCUAMethodCallResponse {
                            OutputArguments = (List <object>)outputArguments, Error = error
                        });
                    }
                }
                else
                {
                    TSM tTSN = new TSM(MyBaseThing.EngineName, string.Format(String.IsNullOrEmpty(error) ? "CALL_METHOD_RESPONSE:{0}:{1}" : "CALL_METHOD_RESPONSE:{0}:{1}:{2}:{3}", MyBaseThing.ID, cmd[1], error.Replace(":", " "), exceptionText.Replace(":", " ")));
                    if (largeOutput != null && String.IsNullOrEmpty(error))
                    {
                        tTSN.PLB = largeOutput;
                    }
                    if (outParamsAsJson != null && String.IsNullOrEmpty(error))
                    {
                        tTSN.PLS = outParamsAsJson;
                    }
                    if (pMsg.LocalCallback != null)
                    {
                        pMsg.LocalCallback(tTSN);
                    }
                    else
                    {
                        TheCommCore.PublishToOriginator(pMsg.Message, tTSN);
                    }
                }
                break;
            }

            base.HandleMessage(this, pMsg);
        }
Esempio n. 4
0
 public void Setup(TheOPCTag pTag)
 {
     m_Tag    = pTag;
     IsActive = false;
     sinkInit(this, null);
 }
Esempio n. 5
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()}"));
            }
        }