private void PrintValueAsJson(string name, DataValue value) { var jsonEncoder = new JsonEncoder(m_session.MessageContext, JsonReversible); jsonEncoder.WriteDataValue(name, value); var textbuffer = jsonEncoder.CloseAndReturnText(); // prettify using (var stringWriter = new StringWriter()) { try { using (var stringReader = new StringReader(textbuffer)) { var jsonReader = new JsonTextReader(stringReader); var jsonWriter = new JsonTextWriter(stringWriter) { Formatting = Formatting.Indented, Culture = CultureInfo.InvariantCulture }; jsonWriter.WriteToken(jsonReader); Console.WriteLine(stringWriter.ToString()); } } catch (Exception ex) { Console.WriteLine("Failed to format the JSON output:", ex.Message); Console.WriteLine(textbuffer); Console.WriteLine(stringWriter.ToString()); ExitCode = ExitCode.ErrorJSONDecode; throw; } } }
private void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e) { try { MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification; if (notification == null) { return; } DataValue value = notification.Value as DataValue; if (value == null) { return; } using (var encoder = new JsonEncoder(monitoredItem.Subscription.Session.MessageContext, false)) { string applicationURI = monitoredItem.Subscription.Session.Endpoint.Server.ApplicationUri; encoder.WriteString("ApplicationUri", applicationURI); encoder.WriteString("DisplayName", monitoredItem.DisplayName); encoder.WriteNodeId("MonitoredItem", monitoredItem.ResolvedNodeId); // suppress output of server timestamp in json by setting it to minvalue value.ServerTimestamp = DateTime.MinValue; encoder.WriteDataValue("Value", value); string json = encoder.CloseAndReturnText(); var properties = new Dictionary <string, string>(); properties.Add("content-type", "application/opcua+uajson"); properties.Add("deviceName", Id); if (SharedAccessKey != null) { properties.Add("source", "mapping"); properties.Add("deviceKey", SharedAccessKey); } try { Module.Publish(new Message(json, properties)); } catch (Exception ex) { Console.WriteLine("Opc.Ua.Client.SampleModule: Failed to publish message, dropping..."); Console.WriteLine(ex.ToString()); } } } catch (Exception exception) { Console.WriteLine("Opc.Ua.Client.SampleModule: Error processing monitored item notification."); Console.WriteLine(exception.ToString()); } }
/// <summary> /// The notification that the data for a monitored item has changed on an OPC UA server /// </summary> public static void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args) { try { if (args.NotificationValue == null || monitoredItem.Subscription.Session == null) { return; } MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification; if (notification == null) { return; } DataValue value = notification.Value as DataValue; if (value == null) { return; } JsonEncoder encoder = new JsonEncoder(monitoredItem.Subscription.Session.MessageContext, false); string applicationURI = monitoredItem.Subscription.Session.Endpoint.Server.ApplicationUri; encoder.WriteString("ApplicationUri", (applicationURI + (string.IsNullOrEmpty(ShopfloorDomain) ? "" : $":{ShopfloorDomain}"))); encoder.WriteString("DisplayName", monitoredItem.DisplayName); // write NodeId as ns=x;i=y NodeId nodeId = monitoredItem.ResolvedNodeId; encoder.WriteString("NodeId", new NodeId(nodeId.Identifier, nodeId.NamespaceIndex).ToString()); // suppress output of server timestamp in json by setting it to minvalue value.ServerTimestamp = DateTime.MinValue; encoder.WriteDataValue("Value", value); string json = encoder.CloseAndReturnText(); // add message to fifo send queue Trace(Utils.TraceMasks.OperationDetail, "Enqueue a new message:"); Trace(Utils.TraceMasks.OperationDetail, " ApplicationUri: " + (applicationURI + (string.IsNullOrEmpty(ShopfloorDomain) ? "" : $":{ShopfloorDomain}"))); Trace(Utils.TraceMasks.OperationDetail, $" DisplayName: {monitoredItem.DisplayName}"); Trace(Utils.TraceMasks.OperationDetail, $" Value: {value}"); Program.IotHubMessaging.Enqueue(json); } catch (Exception e) { Trace(e, "Error processing monitored item notification"); } }
/// <summary> /// The notification that the data for a monitored item has changed on an OPC UA server. /// </summary> public void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs args) { try { if (args == null || args.NotificationValue == null || monitoredItem == null || monitoredItem.Subscription == null || monitoredItem.Subscription.Session == null) { return; } MonitoredItemNotification notification = args.NotificationValue as MonitoredItemNotification; if (notification == null) { return; } DataValue value = notification.Value as DataValue; if (value == null) { return; } JsonEncoder encoder = new JsonEncoder(monitoredItem.Subscription.Session.MessageContext, false); string applicationURI = monitoredItem.Subscription.Session.Endpoint.Server.ApplicationUri; encoder.WriteString("ApplicationUri", (applicationURI + (string.IsNullOrEmpty(ShopfloorDomain) ? "" : $":{ShopfloorDomain}"))); encoder.WriteString("DisplayName", monitoredItem.DisplayName); // use the node Id as configured, to also have the namespace URI in case of a ExpandedNodeId. encoder.WriteString("NodeId", ConfigNodeId); // suppress output of server timestamp in json by setting it to minvalue value.ServerTimestamp = DateTime.MinValue; encoder.WriteDataValue("Value", value); string json = encoder.CloseAndReturnText(); // add message to fifo send queue Trace(Utils.TraceMasks.OperationDetail, $"Enqueue a new message from subscription {monitoredItem.Subscription.Id} (publishing interval: {monitoredItem.Subscription.PublishingInterval}, sampling interval: {monitoredItem.SamplingInterval}):"); Trace(Utils.TraceMasks.OperationDetail, " ApplicationUri: " + (applicationURI + (string.IsNullOrEmpty(ShopfloorDomain) ? "" : $":{ShopfloorDomain}"))); Trace(Utils.TraceMasks.OperationDetail, $" DisplayName: {monitoredItem.DisplayName}"); Trace(Utils.TraceMasks.OperationDetail, $" Value: {value}"); IotHubCommunication.Enqueue(json); } catch (Exception e) { Trace(e, "Error processing monitored item notification"); } }
/// <summary> /// The notification that the data for a monitored item has changed on an OPC UA server /// </summary> public static void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e) { try { if (e.NotificationValue == null || monitoredItem.Subscription.Session == null) { return; } MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification; if (notification == null) { return; } DataValue value = notification.Value as DataValue; if (value == null) { return; } JsonEncoder encoder = new JsonEncoder(monitoredItem.Subscription.Session.MessageContext, false); string applicationURI = monitoredItem.Subscription.Session.Endpoint.Server.ApplicationUri; encoder.WriteString("ApplicationUri", applicationURI); encoder.WriteString("DisplayName", monitoredItem.DisplayName); // write NodeId as ns=x;i=y NodeId nodeId = monitoredItem.ResolvedNodeId; encoder.WriteString("NodeId", new NodeId(nodeId.Identifier, nodeId.NamespaceIndex).ToString()); // suppress output of server timestamp in json by setting it to minvalue value.ServerTimestamp = DateTime.MinValue; encoder.WriteDataValue("Value", value); string json = encoder.CloseAndReturnText(); // add message to fifo send queue m_sendQueue.Enqueue(json); } catch (Exception exception) { Trace("Error processing monitored item notification: " + exception.ToString()); } }
/// <summary> /// The notification that the data for a monitored item has changed on an OPC UA server. /// </summary> public void MonitoredItemNotificationEventHandler(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e) { try { if (e == null || e.NotificationValue == null || monitoredItem == null || monitoredItem.Subscription == null || monitoredItem.Subscription.Session == null) { return; } if (!(e.NotificationValue is MonitoredItemNotification notification)) { return; } if (!(notification.Value is DataValue value)) { return; } MessageData messageData = new MessageData(); if (IotCentralMode) { // for IoTCentral we use the DisplayName as the key in the telemetry and the Value as the value. if (monitoredItem.DisplayName != null) { // use the DisplayName as reported in the MonitoredItem messageData.DisplayName = monitoredItem.DisplayName; } if (value.Value != null) { // use the Value as reported in the notification event argument encoded with the OPC UA JSON endcoder JsonEncoder encoder = new JsonEncoder(monitoredItem.Subscription.Session.MessageContext, false); value.ServerTimestamp = DateTime.MinValue; value.SourceTimestamp = DateTime.MinValue; value.StatusCode = StatusCodes.Good; encoder.WriteDataValue("Value", value); string valueString = encoder.CloseAndReturnText(); // we only want the value string, search for everything till the real value starts // and get it string marker = "{\"Value\":{\"Value\":"; int markerStart = valueString.IndexOf(marker, StringComparison.InvariantCulture); messageData.PreserveValueQuotes = true; if (markerStart >= 0) { // we either have a value in quotes or just a value int valueLength; int valueStart = marker.Length; if (valueString.IndexOf("\"", valueStart, StringComparison.InvariantCulture) >= 0) { // value is in quotes and two closing curly brackets at the end valueStart++; valueLength = valueString.Length - valueStart - 3; } else { // value is without quotes with two curly brackets at the end valueLength = valueString.Length - marker.Length - 2; messageData.PreserveValueQuotes = false; } messageData.Value = valueString.Substring(valueStart, valueLength); } Logger.Debug($" IoTCentral key: {messageData.DisplayName}"); Logger.Debug($" IoTCentral values: {messageData.Value}"); } } else { // update the required message data to pass only the required data to HubCommunication EndpointTelemetryConfiguration telemetryConfiguration = GetEndpointTelemetryConfiguration(EndpointUrl); // the endpoint URL is required to allow HubCommunication lookup the telemetry configuration messageData.EndpointUrl = EndpointUrl; if (telemetryConfiguration.NodeId.Publish == true) { messageData.NodeId = OriginalId; } if (telemetryConfiguration.MonitoredItem.ApplicationUri.Publish == true) { messageData.ApplicationUri = (monitoredItem.Subscription.Session.Endpoint.Server.ApplicationUri + (string.IsNullOrEmpty(OpcSession.PublisherSite) ? "" : $":{OpcSession.PublisherSite}")); } if (telemetryConfiguration.MonitoredItem.DisplayName.Publish == true && monitoredItem.DisplayName != null) { // use the DisplayName as reported in the MonitoredItem messageData.DisplayName = monitoredItem.DisplayName; } if (telemetryConfiguration.Value.SourceTimestamp.Publish == true && value.SourceTimestamp != null) { // use the SourceTimestamp as reported in the notification event argument in ISO8601 format messageData.SourceTimestamp = value.SourceTimestamp.ToString("o", CultureInfo.InvariantCulture); } if (telemetryConfiguration.Value.StatusCode.Publish == true && value.StatusCode != null) { // use the StatusCode as reported in the notification event argument messageData.StatusCode = value.StatusCode.Code; } if (telemetryConfiguration.Value.Status.Publish == true && value.StatusCode != null) { // use the StatusCode as reported in the notification event argument to lookup the symbolic name messageData.Status = StatusCode.LookupSymbolicId(value.StatusCode.Code); } if (telemetryConfiguration.Value.Value.Publish == true && value.Value != null) { // use the Value as reported in the notification event argument encoded with the OPC UA JSON endcoder JsonEncoder encoder = new JsonEncoder(monitoredItem.Subscription.Session.MessageContext, false); value.ServerTimestamp = DateTime.MinValue; value.SourceTimestamp = DateTime.MinValue; value.StatusCode = StatusCodes.Good; encoder.WriteDataValue("Value", value); string valueString = encoder.CloseAndReturnText(); // we only want the value string, search for everything till the real value starts // and get it string marker = "{\"Value\":{\"Value\":"; int markerStart = valueString.IndexOf(marker, StringComparison.InvariantCulture); messageData.PreserveValueQuotes = true; if (markerStart >= 0) { // we either have a value in quotes or just a value int valueLength; int valueStart = marker.Length; if (valueString.IndexOf("\"", valueStart, StringComparison.InvariantCulture) >= 0) { // value is in quotes and two closing curly brackets at the end valueStart++; valueLength = valueString.Length - valueStart - 3; } else { // value is without quotes with two curly brackets at the end valueLength = valueString.Length - marker.Length - 2; messageData.PreserveValueQuotes = false; } messageData.Value = valueString.Substring(valueStart, valueLength); } } // currently the pattern processing is done here, which adds runtime to the notification processing. // In case of perf issues it can be also done in CreateJsonMessageAsync of IoTHubMessaging.cs. // apply patterns messageData.ApplyPatterns(telemetryConfiguration); Logger.Debug($" ApplicationUri: {messageData.ApplicationUri}"); Logger.Debug($" EndpointUrl: {messageData.EndpointUrl}"); Logger.Debug($" DisplayName: {messageData.DisplayName}"); Logger.Debug($" Value: {messageData.Value}"); } // add message to fifo send queue if (monitoredItem.Subscription == null) { Logger.Debug($"Subscription already removed. No more details available."); } else { Logger.Debug($"Enqueue a new message from subscription {(monitoredItem.Subscription == null ? "removed" : monitoredItem.Subscription.Id.ToString(CultureInfo.InvariantCulture))}"); Logger.Debug($" with publishing interval: {monitoredItem.Subscription.PublishingInterval} and sampling interval: {monitoredItem.SamplingInterval}):"); } HubCommunication.Enqueue(messageData); } catch (Exception ex) { Logger.Error(ex, "Error processing monitored item notification"); } }
/// <summary> /// Encodes a dataSet field /// </summary> private void EncodeField(JsonEncoder encoder, Field field) { string fieldName = field.FieldMetaData.Name; Variant valueToEncode = field.Value.WrappedValue; // The StatusCode.Good value is not encoded cor3ectly then it shall be ommited if (valueToEncode == StatusCodes.Good && m_fieldTypeEncoding != FieldTypeEncodingMask.Variant) { valueToEncode = Variant.Null; } switch (m_fieldTypeEncoding) { case FieldTypeEncodingMask.Variant: // If the DataSetFieldContentMask results in a Variant representation, // the field value is encoded as a Variant encoded using the reversible OPC UA JSON Data Encoding // defined in OPC 10000-6. encoder.ForceNamespaceUri = false; encoder.WriteVariant(fieldName, valueToEncode, true); break; case FieldTypeEncodingMask.RawData: // If the DataSetFieldContentMask results in a RawData representation, // the field value is a Variant encoded using the non-reversible OPC UA JSON Data Encoding // defined in OPC 10000-6 encoder.ForceNamespaceUri = true; encoder.WriteVariant(fieldName, valueToEncode, false); break; case FieldTypeEncodingMask.DataValue: DataValue dataValue = new DataValue(); dataValue.WrappedValue = valueToEncode; if ((FieldContentMask & DataSetFieldContentMask.StatusCode) != 0) { dataValue.StatusCode = field.Value.StatusCode; } if ((FieldContentMask & DataSetFieldContentMask.SourceTimestamp) != 0) { dataValue.SourceTimestamp = field.Value.SourceTimestamp; } if ((FieldContentMask & DataSetFieldContentMask.SourcePicoSeconds) != 0) { dataValue.SourcePicoseconds = field.Value.SourcePicoseconds; } if ((FieldContentMask & DataSetFieldContentMask.ServerTimestamp) != 0) { dataValue.ServerTimestamp = field.Value.ServerTimestamp; } if ((FieldContentMask & DataSetFieldContentMask.ServerPicoSeconds) != 0) { dataValue.ServerPicoseconds = field.Value.ServerPicoseconds; } // If the DataSetFieldContentMask results in a DataValue representation, // the field value is a DataValue encoded using the non-reversible OPC UA JSON Data Encoding encoder.ForceNamespaceUri = true; encoder.WriteDataValue(fieldName, dataValue, false); break; } }
/// <summary> /// The notification that the data for a monitored item has changed on an OPC UA server /// </summary> public static void MonitoredItem_Notification(MonitoredItem monitoredItem, MonitoredItemNotificationEventArgs e) { try { if (e.NotificationValue == null || monitoredItem.Subscription.Session == null) { return; } MonitoredItemNotification notification = e.NotificationValue as MonitoredItemNotification; if (notification == null) { return; } DataValue value = notification.Value as DataValue; if (value == null) { return; } JsonEncoder encoder = new JsonEncoder(monitoredItem.Subscription.Session.MessageContext, false); string applicationURI = monitoredItem.Subscription.Session.Endpoint.Server.ApplicationUri; encoder.WriteString("ApplicationUri", applicationURI); encoder.WriteString("DisplayName", monitoredItem.DisplayName); // write NodeId as ns=x;i=y NodeId nodeId = monitoredItem.ResolvedNodeId; encoder.WriteString("NodeId", new NodeId(nodeId.Identifier, nodeId.NamespaceIndex).ToString()); // suppress output of server timestamp in json by setting it to minvalue value.ServerTimestamp = DateTime.MinValue; encoder.WriteDataValue("Value", value); string json = encoder.CloseAndReturnText(); byte[] bytes = new UTF8Encoding(false).GetBytes(json); // publish var properties = new Dictionary <string, string>(); properties.Add("content-type", "application/opcua+uajson"); properties.Add("deviceName", m_deviceName); if (m_accessKey != null) { properties.Add("source", "mapping"); properties.Add("deviceKey", m_accessKey); } try { Publish(new Message(json, properties)); Trace("Opc.Ua.Publisher.Module: Published: " + json + " from " + m_deviceName); } catch (Exception ex) { Trace("Opc.Ua.Publisher.Module: Failed to publish message, dropping..."); Trace(ex.ToString()); } } catch (Exception exception) { Trace("Opc.Ua.Publisher.Module: Error processing monitored item notification: " + exception.ToString()); } }