public async Task <MsgOPCUAMethodCallResponse> CallMethodAsync(string methodId, Dictionary <string, object> parameters, bool returnRawJSON = false) { MethodRegistration methodRegistration; if (!_MethodRegistrations.TryGetValue(methodId, out methodRegistration)) { return(null); } if (methodRegistration.MethodThingAddress == null) { await UpdateRegistrationsAsync(false); } if (methodRegistration.MethodThingAddress == null) { return(null); } var methodCall = new MsgOPCUAMethodCall { Arguments = parameters, ReturnRawJSON = returnRawJSON }; MsgOPCUAMethodCallResponse response; if (methodRegistration.MethodInfo.CallTimeout > 0) { response = await TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUAMethodCall, MsgOPCUAMethodCallResponse>(OwnerAddress, methodRegistration.MethodThingAddress, methodCall, new TimeSpan(0, 0, 0, 0, methodRegistration.MethodInfo.CallTimeout + 15)); } else { response = await TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUAMethodCall, MsgOPCUAMethodCallResponse>(OwnerAddress, methodRegistration.MethodThingAddress, methodCall); } return(response); }
public override void HandleMessage(ICDEThing sender, object pIncoming) { TheProcessMessage pMsg = pIncoming as TheProcessMessage; if (pMsg == null || pMsg.Message == null) { return; } var cmd = TheCommonUtils.cdeSplit(pMsg.Message.TXT, ":", false, false); switch (cmd[0]) { case nameof(MsgAddConnectionThing <TConnectionThingParam>): var addMsg = TheCommRequestResponse.ParseRequestMessageJSON <MsgAddConnectionThing <TConnectionThingParam> >(pMsg.Message); var responseMsg = new MsgAddConnectionThingResponse { Error = "Unexpected" }; if (addMsg != null) { var thingToAdd = addMsg.ThingToAdd; if (thingToAdd != null) { var currentThing = MyConnectionThings.MyMirrorCache.GetEntryByID(thingToAdd.cdeMID); var newThing = new TConnectionThing(); newThing.Initialize(thingToAdd); if (currentThing == null) { MyConnectionThings.AddAnItem(newThing); responseMsg.Error = null; } else { if (!newThing.IsEqual(currentThing)) { UpdateConnectionThing(currentThing, newThing); MyConnectionThings.UpdateItem(newThing); Connect(); } responseMsg.Error = null; } } else { responseMsg.Error = "INVALIDARGS"; } } TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, responseMsg); break; default: base.HandleMessage(sender, pIncoming); break; } }
public async Task <string> DisconnectAsync() { var response = await TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUADisconnect, MsgOPCUADisconnectResponse>(OwnerAddress, OpcThingAddress, new MsgOPCUADisconnect()); if (response == null) { return("Error sending disconnect message"); } return(response.Error); }
public async Task <MsgOPCUAReadTagsResponse> ReadTagsAsync(List <string> nodeIds, TimeSpan callTimeout) { var response = await TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUAReadTags, MsgOPCUAReadTagsResponse>(OwnerAddress, OpcThingAddress, new MsgOPCUAReadTags { Tags = nodeIds.Select((n) => new MsgOPCUAReadTags.TagInfo { NodeId = n }).ToList() }, callTimeout); return(response); }
public void HandleMessage(TSM message) { var cmd = TheCommonUtils.cdeSplit(message.TXT, ":", false, false); switch (cmd[0]) { case nameof(TheThing.MsgSubscribeToThings): { TheCommRequestResponse.DoHandleMessage <MsgSubscribeToThings <TSubscription>, MsgSubscribeToThingsResponse>(message, #if !CDE_NET4 async #endif (request, response) => { response.SubscriptionStatus = new List <TheThing.TheThingSubscriptionStatus>(); foreach (var subscription in request.SubscriptionRequests) { #if !CDE_NET4 response.SubscriptionStatus.Add(await _subscribeHandler(subscription)); #else response.SubscriptionStatus.Add(_subscribeHandler(subscription).Result); #endif } _refreshSubscriptionStateHandler(); } ); break; } case nameof(TheThing.MsgGetThingSubscriptions): { TheCommRequestResponse.DoHandleMessage <MsgGetThingSubscriptions, MsgGetThingSubscriptionsResponse <TSubscription> >(message, (request, response) => { response.ThingSubscriptions = _getSubscriptionsHandler(request.Generalize ?? false); }); break; } case nameof(TheThing.MsgUnsubscribeFromThings): { TheCommRequestResponse.DoHandleMessage <TheThing.MsgUnsubscribeFromThings, TheThing.MsgUnsubscribeFromThingsResponse>(message, (request, response) => { response.Failed = _unsubscribeHandler(request.SubscriptionIds, request.UnsubscribeAll); } ); break; } default: break; } }
public Task <MsgUnsubscribeSensorsResponse> UnsubscribeSensorsAsync(MsgUnsubscribeSensors unsubscribeRequest, bool bypassCapabilityCheck) { if (!bypassCapabilityCheck && !this.Capabilities.Contains(eThingCaps.SensorProvider)) { return(TheCommonUtils.TaskFromResult(new MsgUnsubscribeSensorsResponse { Error = "Thing is not a sensor provider" })); } ; var unsubscribeResponseTask = TheCommRequestResponse.PublishRequestJSonAsync <MsgUnsubscribeSensors, MsgUnsubscribeSensorsResponse>(this, unsubscribeRequest); return(unsubscribeResponseTask); }
public Task <MsgGetSensorSubscriptionsResponse> GetSensorProviderSubscriptionsAsync(MsgGetSensorSubscriptions getSubscriptionsRequest, bool bypassCapabilityCheck) { if (!bypassCapabilityCheck && !this.Capabilities.Contains(eThingCaps.SensorProvider)) { return(TheCommonUtils.TaskFromResult(new MsgGetSensorSubscriptionsResponse { Error = "Thing is not a sensor provider" })); } ; var getSubscriptionResponseTask = TheCommRequestResponse.PublishRequestJSonAsync <MsgGetSensorSubscriptions, MsgGetSensorSubscriptionsResponse>(this, getSubscriptionsRequest); return(getSubscriptionResponseTask); }
public Task <MsgSubscribeSensorsResponse <subscriptionT> > SubscribeSensorsAsync <subscriptionT>(MsgSubscribeSensors <subscriptionT> subscribeRequest, bool bypassCapabilityCheck) where subscriptionT : TheSensorSubscription { if (!bypassCapabilityCheck && !this.Capabilities.Contains(eThingCaps.SensorProvider)) { return(TheCommonUtils.TaskFromResult(new MsgSubscribeSensorsResponse <subscriptionT> { Error = "Thing is not a sensor provider" })); } ; var subscribeResponseTask = TheCommRequestResponse.PublishRequestJSonAsync <TheThing.MsgSubscribeSensors <subscriptionT>, TheThing.MsgSubscribeSensorsResponse <subscriptionT> >(this, subscribeRequest); return(subscribeResponseTask); }
public Task <MsgBrowseSensorsResponse> ProviderBrowseSensorsAsync(TheThing.MsgBrowseSensors browseRequest, bool bypassCapabilityCheck) { if (!bypassCapabilityCheck && !this.Capabilities.Contains(eThingCaps.SensorProvider)) { return(TheCommonUtils.TaskFromResult(new MsgBrowseSensorsResponse { Error = "Thing is not a sensor provider" })); } ; var browseResponseTask = TheCommRequestResponse.PublishRequestJSonAsync <TheThing.MsgBrowseSensors, TheThing.MsgBrowseSensorsResponse>(this, browseRequest); return(browseResponseTask); }
public static TheRecordHolder MeshQueryRecordHolder(int idRecord, Guid node, string strEngineName, Guid cdeMIdThing) { TheRecordHolder trh = null; // Package up request info. MsgMileRecordHolder msgRequest = new MsgMileRecordHolder() { id = idRecord }; // Start asynchronous task to send a message and wait for a reply. // Sends a message named nameof(MsgMileRecordHolder) // Receives a reply named nameof(MsgMileRecordHolderResponse) // See function "HandleMessage" for actual handling. Task <MsgMileRecordHolderResponse> t = null; try { TheMessageAddress tma = new TheMessageAddress() { Node = Guid.Empty, EngineName = strEngineName, ThingMID = cdeMIdThing, SendToProvisioningService = false, }; t = TheCommRequestResponse.PublishRequestJSonAsync <MsgMileRecordHolder, MsgMileRecordHolderResponse>(tma, msgRequest); } catch (Exception ex) { string strMessage = ex.Message; } // Wait for a bit t.Wait(20000); bool bTaskCompleted = t.IsCompleted; // Check for success. if (bTaskCompleted) { MsgMileRecordHolderResponse msgResponse = t.Result; trh = msgResponse.data; } return(trh); }
public async Task <string> ConnectAsync(OPCUAConnectParameters connectParams = null, bool logEssentialOnly = false) { if (connectParams != null) { ConnectParameters = new OPCUAConnectParameters(connectParams); } if (ConnectParameters != null) { // TODO make this work for remote things as well var tThing = GetOpcThing(); TheThing.SetSafePropertyString(tThing, "UserName", ConnectParameters.UserName); TheThing.SetSafePropertyString(tThing, "Password", ConnectParameters.Password); } var response = await TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUAConnect, MsgOPCUAConnectResponse>(OwnerAddress, OpcThingAddress, new MsgOPCUAConnect { LogEssentialOnly = logEssentialOnly }); if (response == null) { return("Error sending connect message"); } return(response.Error); }
private void SendButton_Click(object sender, RoutedEventArgs e) { var msgHello = new MsgChatHello { Message = MessageText.Text, SenderName = UserName.Text, }; var target = new TheMessageAddress { EngineName = strChatEngine, // Send to this engine Node = Guid.Empty // Send to all nodes in the mesh }; var response = TheCommRequestResponse.PublishRequestJSonAsync <MsgChatHello, MsgChatHelloResponse>( TheThingRegistry.GetBaseEngineAsThing(eEngineName.ThingService), // Since we have no plug-in, use an arbitrary existing thing in the system as the originator target, msgHello, new TimeSpan(0, 0, 10)) // Wait 10 seconds for ackknowledge message .Result; if (response == null) { MessageBox.Show("Error sending message or no acknowlege received."); } else { if (response.Acknowledged) { } else { MessageBox.Show("Message not acknowledged."); } } }
/// <summary> /// Handles Messages sent from a host sub-engine to its clients /// </summary> /// <param name="sender"></param> /// <param name="pIncoming"></param> public void HandleMessage(ICDEThing sender, object pIncoming) { TheProcessMessage pMsg = pIncoming as TheProcessMessage; if (pMsg == null) { return; } string[] cmd = pMsg.Message.TXT.Split(':'); switch (cmd[0]) { case "CDE_INITIALIZED": MyBaseEngine.SetInitialized(pMsg.Message); break; case nameof(MsgMileRecordHolder): if (g_EnableMeshDataResponse) { // Request from another node for mile record holder information. var request = TheCommRequestResponse.ParseRequestMessageJSON <MsgMileRecordHolder>(pMsg.Message); var MsgResponse = new MsgMileRecordHolderResponse(); if (request != null) { MsgResponse.data = TheRecordHolder.QueryRecordHolder(request.id); } TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, MsgResponse); MsgResponse = null; // Prevent legacy response handler for being sent. } break; default: break; } }
virtual void HandleMessage(ICDEThing sender, object pIncoming) { TheProcessMessage pMsg = pIncoming as TheProcessMessage; if (pMsg == null || pMsg.Message == null) { return; } var cmd = TheCommonUtils.cdeSplit(pMsg.Message.TXT, ":", false, false); switch (cmd[0]) { case "RUREADY": if (cmd.Length > 1 && cmd[1] == TheCommonUtils.cdeGuidToString(MyBaseThing.cdeMID)) { TheCommCore.PublishToOriginator(pMsg.Message, new TSM(pMsg.Message.ENG, "IS_READY:" + TheCommonUtils.cdeGuidToString(MyBaseThing.cdeMID), mIsInitialized.ToString()) { FLG = 8 }, true); } break; case "CONNECT_SERVER": Connect(); break; case nameof(MsgConnectDisconnect): { var request = TheCommRequestResponse.ParseRequestMessageJSON <MsgConnectDisconnect>(pMsg.Message); var responseMsg = new MsgConnectDisconnectResponse(); if (request == null) { responseMsg.Error = "Error parsing request message"; } else { try { if (request.Connect.HasValue && request.Reconnect.HasValue) { responseMsg.Error = "Can specify at most one of Connect Reconnect"; } else if (!request.Connect.HasValue && !request.Reconnect.HasValue && !request.AutoConnect.HasValue) { responseMsg.Error = "Must specify at least one of Connect Reconnect AutoConnect"; } else { if (request.Connect.HasValue) { if (request.Connect == true) { Connect(); } else { Disconnect(true); } } if (request.Reconnect.HasValue) { Disconnect(true); if (request.WaitTimeBeforeReconnect.HasValue) { try { #if !NET40 await TheCommonUtils.TaskDelayOneEye(request.WaitTimeBeforeReconnect.Value, 100).ConfigureAwait(false); #else TheCommonUtils.TaskDelayOneEye(request.WaitTimeBeforeReconnect.Value, 100).Wait(); #endif } catch (System.Threading.Tasks.TaskCanceledException) { } } Connect(); } if (request.AutoConnect.HasValue) { AutoConnect = request.AutoConnect.Value; } responseMsg.Connected = IsConnected; } } catch (Exception e) { responseMsg.Error = e.Message; } } TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, responseMsg); } break; } }
/// <summary> /// /// </summary> /// <param name="reRegisterAll"></param> /// <returns></returns> public async Task <List <RegistrationError> > UpdateRegistrationsAsync(bool reRegisterAll = false, bool bulkApply = false) { var tags = new List <TagRegistration>(); var methods = new List <MethodRegistration>(); var events = new List <EventRegistration>(); foreach (var tagRegistration in _TagRegistrations.Values) { if (reRegisterAll || !String.IsNullOrEmpty(tagRegistration.Error)) { tagRegistration.Error = "pending"; tags.Add(tagRegistration); } } foreach (var methodRegistration in _MethodRegistrations.Values) { if (reRegisterAll || !String.IsNullOrEmpty(methodRegistration.Error)) { methodRegistration.Error = "pending"; methods.Add(methodRegistration); } } foreach (var eventRegistration in _EventRegistrations.Values) { if (reRegisterAll || !String.IsNullOrEmpty(eventRegistration.Error)) { eventRegistration.Error = "pending"; events.Add(eventRegistration); } } if (tags.Count == 0 && methods.Count == 0 && events.Count == 0) { return(new List <RegistrationError>()); } var response = await TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUACreateTags, MsgOPCUACreateTagsResponse>(OwnerAddress, OpcThingAddress, new MsgOPCUACreateTags { Tags = tags.Count > 0 ? tags.Select((t) => t.TagInfo).ToList() : null, Methods = methods.Count > 0 ? methods.Select((m) => m.MethodInfo).ToList() : null, Events = events.Count > 0 ? events.Select(e => e.EventInfo).ToList() : null, BulkApply = bulkApply }); if (response == null) { return(null); } if (response.Results == null) { return(new List <RegistrationError> { new RegistrationError { Error = response.Error, } }); } if (response.Results.Count != tags.Count + methods.Count + events.Count) { return(new List <RegistrationError> { new RegistrationError { Error = String.Format("Internal error (result count mismatch: {0}, expected {1}", response.Results.Count, tags.Count + methods.Count), } }); } var registrationErrors = new List <RegistrationError>(); int resultIndex = 0; var results = response.Results; foreach (var tag in tags) { var error = results[resultIndex].Error; if (String.IsNullOrEmpty(error)) { tag.Error = null; } else { tag.Error = error; registrationErrors.Add(new RegistrationError { PropertyName = tag.PropertyName, NodeId = tag.TagInfo.NodeId, Error = error, }); } resultIndex++; } foreach (var method in methods) { var error = results[resultIndex].Error; if (String.IsNullOrEmpty(error)) { method.Error = null; method.MethodThingAddress = results[resultIndex].MethodThingAddress; } else { method.Error = error; registrationErrors.Add(new RegistrationError { MethodId = method.MethodId, Error = error, }); } resultIndex++; } foreach (var eventRegistration in events) { var error = results[resultIndex].Error; if (String.IsNullOrEmpty(error)) { eventRegistration.Error = null; } else { eventRegistration.Error = error; registrationErrors.Add(new RegistrationError { PropertyName = eventRegistration.PropertyName, NodeId = eventRegistration.EventInfo.NodeId, Error = error, }); } resultIndex++; } return(registrationErrors); }
public Task <MsgSubscribeToThingsResponse> SubscribeToThingsAsync(MsgSubscribeToThings subscribeThingsRequest) { return(TheCommRequestResponse.PublishRequestJSonAsync <MsgSubscribeToThings, MsgSubscribeToThingsResponse>(this, subscribeThingsRequest)); }
private void HandleMessage(ICDEThing arg1, object arg2) { var msg = (arg2 as TheProcessMessage).Message; if (msg == null) { return; } var messageName = TheCommRequestResponse.ParseRequestOrResponseMessage(msg, out var messageParameters, out var correlationToken); switch (messageName) { case nameof(MsgChatHello): { var request = TheCommRequestResponse.ParseRequestMessageJSON <MsgChatHello>(msg); if (request != null) { // Messages come in on a .Net Threadpool thread, so need to dispatch it to the WPF main thread before we can access any WPF controls this.Dispatcher.InvokeAsync(() => { var chatMessage = new ChatMessage { MessageId = correlationToken, SenderName = request.SenderName, Message = request.Message, SeenBy = 0, Sent = msg.TIM, Received = DateTimeOffset.Now, }; MessageList.Items.Insert(0, chatMessage); }); TheCommRequestResponse.PublishResponseMessageJson(msg, new MsgChatHelloResponse { Acknowledged = true }); } else { TheCommRequestResponse.PublishResponseMessageJson(msg, new MsgChatHelloResponse { Acknowledged = false }); } } break; case nameof(MsgChatHello) + "_RESPONSE": { var request = TheCommRequestResponse.ParseRequestMessageJSON <MsgChatHelloResponse>(msg); if (request != null) { this.Dispatcher.InvokeAsync(() => { if (request.Acknowledged) { int i = 0; foreach (var item in MessageList.Items) { var chatMessage = item as ChatMessage; if (chatMessage != null) { if (chatMessage.MessageId == correlationToken) { chatMessage.SeenBy++; MessageList.Items.RemoveAt(i); MessageList.Items.Insert(i, chatMessage); break; } } i++; } } else { MessageBox.Show($"Somebody ({msg.ORG}) rejected our message {correlationToken}"); } }); } else { // Somebody is sending MsgChatHelloResponse messages in an unknown/incompatible format, or somebody rejected a message for some reason this.Dispatcher.InvokeAsync(() => { MessageBox.Show($"Received invalid MsgChatHelloResponse: {msg}"); }); } } break; } }
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); }
static protected TheThing StartOPCServer(bool disableSecurity) { #if OPCUASERVER // TODO Actually use our own OPC Server for the unit test var opcServerThing = TheThingRegistry.GetThingsOfEngine("CDMyOPCUAServer.cdeMyOPCServerService").FirstOrDefault(); Assert.IsNotNull(opcServerThing, $"Unable to obtain OPC Server thing: error loading plug-in or server not yet initialized?"); lock (opcServerStartupLock) { if (!TheThing.GetSafePropertyBool(opcServerThing, "IsRunning")) { TheThing.SetSafePropertyBool(opcServerThing, "DisableSecurity", disableSecurity); TheThing.SetSafePropertyBool(opcServerThing, "NoServerCertificate", disableSecurity); var theOpcThing = new TheThing(); theOpcThing.EngineName = "OPCTestEng"; theOpcThing.DeviceType = "OPCTestDT"; theOpcThing.Address = "OPCTestAddress"; theOpcThing.SetProperty("OpcProp01", "0001"); theOpcThing.SetProperty("OpcProp02", "0002"); theOpcThing.SetProperty("OpcProp03", "0003"); theOpcThing.SetProperty("OpcProp04", "0004"); theOpcThing.SetProperty("OpcProp05", "0005"); theOpcThing.SetProperty("OpcProp06", "0006"); theOpcThing.SetProperty("OpcProp07", "0007"); theOpcThing.SetProperty("OpcProp08", "0008"); theOpcThing.SetProperty("OpcProp09", "0009"); theOpcThing.SetProperty("OpcProp10", "0010"); var tThing = TheThingRegistry.RegisterThing(theOpcThing); Assert.IsNotNull(tThing); var addThingResponse = TheCommRequestResponse.PublishRequestJSonAsync <MsgAddThingsToServer, MsgAddThingsToServerResponse>(myContentService, opcServerThing, new MsgAddThingsToServer ( new TheThingToAddToServer { cdeMID = Guid.NewGuid(), ReplaceExistingThing = false, ThingMID = TheCommonUtils.cdeGuidToString(theOpcThing.cdeMID), } ), new TimeSpan(0, 0, 30)).Result; Assert.IsNotNull(addThingResponse, "No reply to OPC Server MsgAddThingToServer"); Assert.IsTrue(string.IsNullOrEmpty(addThingResponse.Error), $"Error adding thing to OPC Server: '{addThingResponse.Error}'."); Assert.AreEqual(1, addThingResponse.ThingStatus.Count, $"Error adding thing to OPC Server."); Assert.IsTrue(string.IsNullOrEmpty(addThingResponse.ThingStatus[0].Error), $"Error adding thing to OPC Server: '{addThingResponse.ThingStatus[0].Error}'."); MsgStartStopServerResponse responseStart; int retryCount = 1; do { responseStart = TheCommRequestResponse.PublishRequestJSonAsync <MsgStartStopServer, MsgStartStopServerResponse>(myContentService, opcServerThing, new MsgStartStopServer { Restart = true, }, new TimeSpan(0, 0, 30)).Result; retryCount--; } while (retryCount >= 0 && responseStart == null); Assert.IsNotNull(responseStart, "Failed to send MsgStartStopServer message to restart OPC UA Server"); Assert.IsTrue(string.IsNullOrEmpty(responseStart.Error), $"Error restarting OPC Server: '{addThingResponse.Error}'."); Assert.IsTrue(responseStart.Running, $"OPC Server not running after MsgStartStopServer Restart message"); } } return(opcServerThing); #else return(null); #endif }
public void CreateOPCWizard() { TheFieldInfo tTargetButton = null; var flds = TheNMIEngine.AddNewWizard <TheOPCSetClass>(new Guid("{56565656-6AD1-45AE-BE61-96AF02329614}"), Guid.Empty, TheNMIEngine.GetEngineDashBoardByThing(MyBaseThing).cdeMID, "Welcome to the OPC Wizard", new nmiCtrlWizard { PanelTitle = "<i class='fa faIcon fa-3x'></i></br>New OPC Client", SideBarTitle = "New OPC Client Wizard", SideBarIconFA = "", TileThumbnail = "FA5:f545" }, (myClass, pClientInfo) => { myClass.cdeMID = Guid.Empty; TheThing tMemTag = null; if (myClass.CreateMemoryTag) { var tReq = new TheThingRegistry.MsgCreateThingRequestV1() { EngineName = "CDMyVThings.TheVThings", DeviceType = "Memory Tag", FriendlyName = myClass.ClientName, OwnerAddress = MyBaseThing, InstanceId = Guid.NewGuid().ToString(), CreateIfNotExist = true }; tMemTag = TheThingRegistry.CreateOwnedThingAsync(tReq).Result; } var tOPCReq = new TheThingRegistry.MsgCreateThingRequestV1() { EngineName = "CDMyOPCUAClient.cdeOPCUaClient", DeviceType = "OPC-UA Remote Server", FriendlyName = myClass.ClientName, Address = myClass.OPCAddress, OwnerAddress = MyBaseThing, InstanceId = Guid.NewGuid().ToString(), CreateIfNotExist = true }; tOPCReq.Properties = new Dictionary <string, object>(); //tOPCReq.Properties["ID"] = Guid.NewGuid().ToString(); tOPCReq.Properties["AutoConnect"] = myClass.AutoConnect; tOPCReq.Properties["SendOpcDataType"] = true; if (!myClass.DisableSecurity) { tOPCReq.Properties["DisableSecurity"] = true; tOPCReq.Properties["AcceptUntrustedCertificate"] = true; tOPCReq.Properties["DisableDomainCheck"] = true; tOPCReq.Properties["AcceptInvalidCertificate"] = true; tOPCReq.Properties["Anonymous"] = true; } if (tMemTag != null) { tOPCReq.Properties["TagHostThingForSubscribeAll"] = tMemTag.cdeMID; } var tOPCServer = TheThingRegistry.CreateOwnedThingAsync(tOPCReq).Result; try { if (tOPCServer != null && myClass.Prop2Tag && myClass.AutoConnect) { var response = TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUAConnect, MsgOPCUAConnectResponse>(MyBaseThing, tOPCServer, new MsgOPCUAConnect { LogEssentialOnly = true, WaitUntilConnected = true }).Result; if (response != null && string.IsNullOrEmpty(response.Error)) { var tBrowseResponse = TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUABrowse, MsgOPCUABrowseResponse>(MyBaseThing, tOPCServer, new MsgOPCUABrowse()).Result; if (string.IsNullOrEmpty(tBrowseResponse.Error)) { TheCommCore.PublishToNode(pClientInfo.NodeID, new TSM(eEngineName.NMIService, "NMI_TOAST", $"OPC UA Client browse error: {tBrowseResponse.Error}")); return; } else { List <MsgOPCUACreateTags.TagInfo> tTagList = tBrowseResponse.Tags; if (tTagList != null && tTagList.Count > 0) { var tres = TheCommRequestResponse.PublishRequestJSonAsync <MsgOPCUACreateTags, MsgOPCUACreateTagsResponse>(MyBaseThing, tOPCServer, new MsgOPCUACreateTags { Tags = tTagList, BulkApply = true }).Result; if (tres != null && string.IsNullOrEmpty(tres.Error)) { TheCommCore.PublishToNode(pClientInfo.NodeID, new TSM(eEngineName.NMIService, "NMI_TOAST", "OPC UA Client Created and memory tag ready")); } } } } } TheCommCore.PublishToNode(pClientInfo.NodeID, new TSM(eEngineName.NMIService, "NMI_TOAST", "OPC UA Client Created and ready")); } catch (Exception) { TheCommCore.PublishToNode(pClientInfo.NodeID, new TSM(eEngineName.NMIService, "NMI_TOAST", "Something went wrong! Check the OPC and Memory Tag settings")); } tTargetButton.SetUXProperty(pClientInfo.NodeID, $"OnClick=TTS:{tOPCServer.GetBaseThing().cdeMID}"); TheCommonUtils.SleepOneEye(2000, 100); }); var tMyForm2 = flds["Form"] as TheFormInfo; var tFlds = TheNMIEngine.AddNewWizardPage(MyBaseThing, tMyForm2, 0, 1, 2, null /*"Name and Address"*/); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleEnded, 1, 1, 2, 0, "Connection Name", "ClientName", new TheNMIBaseControl { Explainer = "1. Enter name for the new OPC connection.", }); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleEnded, 1, 2, 2, 0, "OPC Server Address", "OPCAddress", new TheNMIBaseControl { Explainer = "1. Enter address of the OPC server.", }); tFlds = TheNMIEngine.AddNewWizardPage(MyBaseThing, tMyForm2, 1, 2, 3, null /* "Settings"*/); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleCheck, 2, 1, 2, 0, "OPC Server requires Security", "DisableSecurity", new nmiCtrlSingleCheck { Explainer = "Check if the OPC Server requires security" }); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleCheck, 2, 2, 2, 0, "Create a Memory Tag", "CreateMemoryTag", new nmiCtrlSingleCheck { TileWidth = 3, Explainer = "Check to create a Memory Tag and check to subscribes all Tags into it" }); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleCheck, 2, 3, 2, 0, "All Tags in Memory Tag", "Prop2Tag", new nmiCtrlSingleCheck { TileWidth = 3 }); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SingleCheck, 2, 4, 2, 0, "Auto Connect to Server", "AutoConnect", new nmiCtrlSingleCheck { TileWidth = 3, Explainer = "Don't select this if your server requires security settings" }); tFlds = TheNMIEngine.AddNewWizardPage(MyBaseThing, tMyForm2, 2, 3, 0, null /*"Final Settings"*/); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SmartLabel, 3, 2, 0, 0, null, null, new nmiCtrlSmartLabel { Text = "Once you click finish, the Wizard will create the items you requested. It will notify you with a toast when its done", TileHeight = 5, TileWidth = 7, NoTE = true }); //HELP SECTION final step help section TheNMIEngine.AddWizardProcessPage(MyBaseThing, tMyForm2, 4); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SmartLabel, 4, 1, 0, 0, null, null, new nmiCtrlSmartLabel { NoTE = true, TileWidth = 7, Text = "Creating the new instance..please wait", TileHeight = 2 }); TheNMIEngine.AddWizardFinishPage(MyBaseThing, tMyForm2, 5); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.SmartLabel, 5, 1, 0, 0, null, null, new nmiCtrlSmartLabel { NoTE = true, TileWidth = 7, Text = "Done...what do you want to do next?", TileHeight = 2 }); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.TileGroup, 5, 2, 0, 0, null, null, new nmiCtrlTileGroup { TileWidth = 1, TileHeight = 2, TileFactorX = 2 }); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.TileButton, 5, 3, 2, 0, "Go to Dashboard", null, new nmiCtrlTileButton { NoTE = true, TileHeight = 2, TileWidth = 3, OnClick = $"TTS:{mMyDashboard.cdeMID}", ClassName = "cdeTransitButton" }); TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.TileGroup, 5, 4, 0, 0, null, null, new nmiCtrlTileGroup { TileWidth = 1, TileHeight = 2 }); tTargetButton = TheNMIEngine.AddWizardControl(MyBaseThing, tMyForm2, eFieldType.TileButton, 5, 5, 2, 0, "Go to New OPC Client", null, new nmiCtrlTileButton { NoTE = true, TileHeight = 2, TileWidth = 3, ClassName = "cdeTransitButton" }); }
public Task <MsgGetThingSubscriptionsResponse> GetThingSubscriptionsAsync(MsgGetThingSubscriptions getSubscriptionsRequest) { return(TheCommRequestResponse.PublishRequestJSonAsync <MsgGetThingSubscriptions, MsgGetThingSubscriptionsResponse>(this, getSubscriptionsRequest)); }
/// <summary> /// Handles Messages sent from a host sub-engine to its clients /// </summary> /// <param name="Command"></param> /// <param name="pMessage"></param> public override void HandleMessage(ICDEThing sender, object pIncoming) { TheProcessMessage pMsg = pIncoming as TheProcessMessage; if (pMsg == null) { return; } string[] cmd = pMsg.Message.TXT.Split(':'); switch (cmd[0]) { case nameof(TheThing.MsgBrowseSensors): var browseRequest = TheCommRequestResponse.ParseRequestMessageJSON <TheThing.MsgBrowseSensors>(pMsg.Message); var browseResponse = new TheThing.MsgBrowseSensorsResponse { Error = "Internal error", Sensors = new List <TheThing.TheSensorSourceInfo>() }; foreach (FieldMapping fld in MyModFieldStore.TheValues) { browseResponse.Sensors.Add(new TheThing.TheSensorSourceInfo { SourceType = fld.SourceType, cdeType = ePropertyTypes.TNumber, SensorId = TheCommonUtils.CStr(fld.cdeMID), ExtensionData = new Dictionary <string, object> { { nameof(FieldMapping.SourceOffset), fld.SourceOffset }, { nameof(FieldMapping.SourceSize), fld.SourceSize }, { nameof(FieldMapping.AllowWrite), fld.AllowWrite } }, DisplayNamePath = new string[] { MyBaseEngine.GetEngineName(), MyBaseThing.FriendlyName, fld.PropertyName } }); } browseResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, browseResponse); break; case nameof(TheThing.MsgSubscribeSensors): var subscribeRequest = TheCommRequestResponse.ParseRequestMessageJSON <TheThing.MsgSubscribeSensors>(pMsg.Message); var subscribeResponse = new TheThing.MsgSubscribeSensorsResponse { Error = "Internal error", SubscriptionStatus = new List <TheThing.TheSensorSubscriptionStatus>() }; if (subscribeRequest.ReplaceAll) { MyModFieldStore.RemoveAllItems(); } var subscriptionStatus = new List <TheThing.TheSensorSubscriptionStatus>(); foreach (TheThing.TheSensorSubscription sub in subscribeRequest.SubscriptionRequests) { FieldMapping fld = new FieldMapping() { PropertyName = sub.TargetProperty, cdeMID = TheCommonUtils.CGuid(sub.SensorId) }; if (fld.cdeMID == Guid.Empty) { fld.cdeMID = Guid.NewGuid(); } object sourceType; if (sub.ExtensionData != null) { if (sub.ExtensionData.TryGetValue(nameof(TheThing.TheSensorSourceInfo.SourceType), out sourceType)) { fld.SourceType = TheCommonUtils.CStr(sourceType); } object offset; if (sub.ExtensionData.TryGetValue("SourceOffset", out offset)) { fld.SourceOffset = TheCommonUtils.CInt(offset); } object size; if (sub.ExtensionData.TryGetValue("SourceSize", out size)) { fld.SourceSize = TheCommonUtils.CInt(size); } object allowWrite; if (sub.ExtensionData.TryGetValue("AllowWrite", out allowWrite)) { fld.AllowWrite = TheCommonUtils.CBool(allowWrite); } MyModFieldStore.AddAnItem(fld); subscriptionStatus.Add(CreateSubscriptionStatusFromFieldMapping(fld)); } else { subscriptionStatus.Add(new TheThing.TheSensorSubscriptionStatus { Error = "Missing source info", Subscription = sub, }); } } subscribeResponse.SubscriptionStatus = subscriptionStatus; subscribeResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, subscribeResponse); break; case nameof(TheThing.MsgGetSensorSubscriptions): var getResponse = new TheThing.MsgGetSensorSubscriptionsResponse { Error = "Internal error" }; getResponse.Subscriptions = MyModFieldStore.TheValues.Select(fld => CreateSubscriptionStatusFromFieldMapping(fld).Subscription).ToList(); getResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, getResponse); break; case nameof(TheThing.MsgUnsubscribeSensors): var unsubscribeRequest = TheCommRequestResponse.ParseRequestMessageJSON <TheThing.MsgUnsubscribeSensors>(pMsg.Message); var unsubscribeResponse = new TheThing.MsgUnsubscribeSensorsResponse { Error = "Internal error", Failed = new List <TheThing.TheSensorSubscriptionStatus>() }; if (unsubscribeRequest.UnsubscribeAll) { MyModFieldStore.RemoveAllItems(); if (MyModFieldStore.GetCount() > 0) { unsubscribeResponse.Failed = MyModFieldStore.TheValues.Select(fld => CreateSubscriptionStatusFromFieldMapping(fld)).ToList(); } } else { List <FieldMapping> toRemove = MyModFieldStore.TheValues.FindAll(fld => unsubscribeRequest.SubscriptionIds.Contains(fld.cdeMID)); MyModFieldStore.RemoveItems(toRemove, null); foreach (FieldMapping fld in MyModFieldStore.TheValues) { if (toRemove.Any(t => t.cdeMID == fld.cdeMID)) { unsubscribeResponse.Failed.Add(CreateSubscriptionStatusFromFieldMapping(fld)); } } } unsubscribeResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, unsubscribeResponse); break; case nameof(TheThing.MsgExportConfig): var exportRequest = TheCommRequestResponse.ParseRequestMessageJSON <TheThing.MsgExportConfig>(pMsg.Message); var exportResponse = new TheThing.MsgExportConfigResponse { Error = "Internal error" }; // No custom config beyond config properties and subscriptions exportResponse.Error = null; TheCommRequestResponse.PublishResponseMessageJson(pMsg.Message, exportResponse); break; case nameof(TheThing.MsgApplyConfig): break; default: break; } TheThing.TheSensorSubscriptionStatus CreateSubscriptionStatusFromFieldMapping(FieldMapping fld) { return(new TheThing.TheSensorSubscriptionStatus { Subscription = new TheThing.TheSensorSubscription { TargetProperty = fld.PropertyName, SensorId = TheCommonUtils.CStr(fld.cdeMID), SubscriptionId = fld.cdeMID, ExtensionData = new Dictionary <string, object> { { nameof(FieldMapping.SourceType), fld.SourceType }, { nameof(FieldMapping.SourceOffset), fld.SourceOffset }, { nameof(FieldMapping.SourceSize), fld.SourceSize }, { nameof(FieldMapping.AllowWrite), fld.AllowWrite } }, TargetThing = new TheThingReference(MyBaseThing), SampleRate = (int?)this.Interval }, Error = null, }); } }
private async Task RunScriptAsync(TheScript script, TheThing variables, int stepNumber = 1, bool replay = false) { TheThing variablesSnapshot; try { for (; stepNumber <= script.Steps.Length; stepNumber++) { //Clone thing before step occurs variablesSnapshot = new TheThing(); variables.CloneThingAndPropertyMetaData(variablesSnapshot, true); var step = script.Steps[stepNumber - 1]; var existingSnapshot = MyScriptTableStorage.MyMirrorCache.GetEntryByFunc(snapshot => snapshot.ScriptName == script.Name && snapshot.ScriptStep == stepNumber); if (existingSnapshot?.Disabled == true) { TheBaseAssets.MySYSLOG.WriteToLog(175002, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyBaseThing.EngineName, "Finished script step: skipped step because it was disabled", eMsgLevel.l3_ImportantMessage, TheCommonUtils.SerializeObjectToJSONString(new Dictionary <String, object> { { "Script", script.Name }, { "Step", stepNumber }, { "Message", step.Message.MessageName }, { "Target", step.Message.Target }, }))); UpdateStorageList(script.Name, "Disabled", stepNumber, script, variablesSnapshot, replay); continue; } if (step.Condition != null) { var condition = TheCommonUtils.GenerateFinalStr(step.Condition, variables); if ( (condition == "" || condition.ToLowerInvariant() == "false" || condition.Trim() == "0") || (condition.StartsWith("!") && condition.Length >= 1 && (condition.Substring(1).ToLowerInvariant() == "true") || condition.Substring(1).Trim() == "1")) { TheBaseAssets.MySYSLOG.WriteToLog(175002, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyBaseThing.EngineName, "Finished script step: skipped step due to condition not met", eMsgLevel.l3_ImportantMessage, TheCommonUtils.SerializeObjectToJSONString(new Dictionary <String, object> { { "Script", script.Name }, { "Step", stepNumber }, { "Message", step.Message.MessageName }, { "Target", step.Message.Target }, { "Condition", step.Condition }, { "ConditionEvaluated", condition }, }))); UpdateStorageList(script.Name, "Condition Not Met", stepNumber, script, variablesSnapshot, replay); continue; } } var messageType = TheCommonUtils.GenerateFinalStr(step.Message.MessageName, variables); var txtPayload = TheCommonUtils.GenerateFinalStr(step.Message.Parameters?.ToString(), variables); { var txtPayload2 = txtPayload?.Replace("\"\\\"", ""); var txtPayload3 = txtPayload2?.Replace("\\\"\"", ""); txtPayload = txtPayload3; } // TODO Need a simpler and more flexible way to specify thing address in the script JSON var target = step.Message.Target; if (target == null) { if (txtPayload.Contains("EngineName")) { var payloadDict = TheCommonUtils.DeserializeJSONStringToObject <Dictionary <string, object> >(txtPayload); object engineNameInferred = null; if (payloadDict?.TryGetValue("EngineName", out engineNameInferred) == true && !string.IsNullOrEmpty(engineNameInferred?.ToString())) { target = new TheMessageAddress { EngineName = engineNameInferred.ToString() }; } } } if (target.EngineName.StartsWith("%") || target.EngineName.StartsWith("{")) { target.EngineName = TheCommonUtils.GenerateFinalStr(target.EngineName, variables); // TODO Clean this up: support a serialized TheMessageAddress in the engine name, so that an output variable can be fed into a method invocation try { var newTarget = TheCommonUtils.DeserializeJSONStringToObject <TheMessageAddress>(target.EngineName); if (newTarget != null) { target = newTarget; } } catch { // parsing error: ignore, will result in other errors downstream } } await TheThingRegistry.WaitForInitializeAsync(target); bool bDoRetry; int remainingRetryCount = step.RetryCount ?? 0; do { existingSnapshot = MyScriptTableStorage.MyMirrorCache.GetEntryByFunc(snapshot => snapshot.ScriptName == script.Name && snapshot.ScriptStep == stepNumber); if (existingSnapshot?.Disabled == true) { TheBaseAssets.MySYSLOG.WriteToLog(175002, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyBaseThing.EngineName, "Finished script step: skipped step because it was disabled", eMsgLevel.l3_ImportantMessage, TheCommonUtils.SerializeObjectToJSONString(new Dictionary <String, object> { { "Script", script.Name }, { "Step", stepNumber }, { "Message", step.Message.MessageName }, { "Target", step.Message.Target }, }))); UpdateStorageList(script.Name, "Disabled", stepNumber, script, variablesSnapshot, replay); break; } bDoRetry = false; var response = await TheCommRequestResponse.PublishRequestAsync(MyBaseThing, target, messageType, new TimeSpan(0, 0, 0, 0, step.Message.timeout), null, txtPayload, null); if (!string.IsNullOrEmpty(response?.PLS)) { var outputs = TheCommonUtils.DeserializeJSONStringToObject <Dictionary <string, object> >(response.PLS); if (outputs != null) { if (step.Message.outputs != null) { foreach (var output in step.Message.outputs) { if (output.Key == "*") { variables.SetProperty(output.Value, response.PLS); } else if (outputs.TryGetValue(output.Key, out var outputValue)) { variables.SetProperty(output.Value, outputValue); if (output.Value.Contains("Error") && !string.IsNullOrEmpty(TheCommonUtils.CStr(outputValue))) { TheBaseAssets.MySYSLOG.WriteToLog(175004, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyBaseThing.EngineName, "Error in script step: output reported error", eMsgLevel.l1_Error, TheCommonUtils.SerializeObjectToJSONString(new Dictionary <String, object> { { "Script", script.Name }, { "Step", stepNumber }, { "Message", messageType }, { "Target", target }, { "PLS", txtPayload }, { "Response", response }, { "ResponsePLS", response?.PLS }, }))); UpdateStorageList(script.Name, $"Error {outputValue} in output", stepNumber, script, variablesSnapshot, replay); if (remainingRetryCount < 0 || remainingRetryCount > 0) { remainingRetryCount--; bDoRetry = true; } string retriesRemaining = bDoRetry ? (remainingRetryCount >= 0 ? $"{remainingRetryCount + 1}" : "infinite") : "none"; MyBaseThing.SetStatus(3, $"Error in script '{script?.Name}', step {stepNumber}: output '{output.Value}' reported error {outputValue}. Retries remaining: {retriesRemaining}"); } } else { // TODO provide access to sub-elements in the JSON //var outputParts = output.Key.Split('/'); //dynamic currentNode = outputs; //foreach (var outputPart in outputParts) //{ // if (currentNode.TryGetValue(outputPart, out var nextNode)) // { // currentNode = nextNode; // } //} } } } TheBaseAssets.MySYSLOG.WriteToLog(175003, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyBaseThing.EngineName, "Finished script step", eMsgLevel.l3_ImportantMessage, TheCommonUtils.SerializeObjectToJSONString(new Dictionary <String, object> { { "Script", script.Name }, { "Step", stepNumber }, { "Message", messageType }, { "Target", target }, { "PLS", txtPayload }, { "ResponsePLS", response.PLS }, }))); UpdateStorageList(script.Name, "Finished", stepNumber, script, variablesSnapshot, replay); } else { TheBaseAssets.MySYSLOG.WriteToLog(175004, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyBaseThing.EngineName, "Error in script step: no outputs found in response", eMsgLevel.l1_Error, TheCommonUtils.SerializeObjectToJSONString(new Dictionary <String, object> { { "Script", script.Name }, { "Step", stepNumber }, { "Message", messageType }, { "Target", target }, { "PLS", txtPayload }, { "Response", response }, { "ResponsePLS", response?.PLS }, }))); UpdateStorageList(script.Name, "Error: No Output", stepNumber, script, variablesSnapshot, replay); if (step.DontRetryOnEmptyResponse != true && (remainingRetryCount < 0 || remainingRetryCount > 0)) { remainingRetryCount--; bDoRetry = true; } string retriesRemaining = bDoRetry ? (remainingRetryCount >= 0 ? $"{remainingRetryCount + 1}" : "infinite") : "none"; MyBaseThing.SetStatus(3, $"Error in script '{script?.Name}', step {stepNumber}: no outputs found in response. Retries remaining: {retriesRemaining}"); } } else { TheBaseAssets.MySYSLOG.WriteToLog(175005, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyBaseThing.EngineName, "Error Script step: timeout", eMsgLevel.l1_Error, TheCommonUtils.SerializeObjectToJSONString(new Dictionary <String, object> { { "Script", script.Name }, { "Step", stepNumber }, { "Message", messageType }, { "Target", target }, { "PLS", txtPayload }, { "Response", response }, }))); UpdateStorageList(script.Name, "Error: Timeout", stepNumber, script, variablesSnapshot, replay); //Retries infinitely unless count is specified if (remainingRetryCount < 0 || remainingRetryCount > 0) { remainingRetryCount--; bDoRetry = true; } string retriesRemaining = bDoRetry ? (remainingRetryCount >= 0 ? $"{remainingRetryCount + 1}" : "infinite") : "none"; MyBaseThing.SetStatus(3, $"Error in script '{script?.Name}', step {stepNumber}: timeout. Retries remaining: {retriesRemaining}"); } if (bDoRetry) { await TheCommonUtils.TaskDelayOneEye(30000, 100).ConfigureAwait(false); } } while (bDoRetry && TheBaseAssets.MasterSwitch); } } catch (Exception e) { TheBaseAssets.MySYSLOG.WriteToLog(175006, TSM.L(eDEBUG_LEVELS.OFF) ? null : new TSM(MyBaseThing.EngineName, "Error in script step", eMsgLevel.l1_Error, TheCommonUtils.SerializeObjectToJSONString(new Dictionary <String, object> { { "Script", script.Name }, { "Exception", e.Message }, }))); MyBaseThing.SetStatus(3, $"Error in script '{script?.Name}': {e.Message}"); //Save variables instead of snapshot in case of error UpdateStorageList(script.Name, $"Error: {e.Message}", stepNumber, script, variables, replay); } }
public Task <MsgUnsubscribeFromThingsResponse> UnsubscribeFromThingsAsync(MsgUnsubscribeFromThings unsubscribeThingsRequest) { return(TheCommRequestResponse.PublishRequestJSonAsync <MsgUnsubscribeFromThings, MsgUnsubscribeFromThingsResponse>(this, unsubscribeThingsRequest)); }