public void WriteDict(Dictionary <string, ushort> valueDict) { using (var session = Session.Create(_config, new ConfiguredEndpoint(null, _endpointDesc, EndpointConfiguration.Create(_config)), false, "", 60000, null, null).GetAwaiter().GetResult()) { StatusCodeCollection results = null; DiagnosticInfoCollection infos = null; session.Write(null, GetWriteValueCollection(valueDict), out results, out infos); if (results.Any(sc => StatusCode.IsNotGood(sc))) { var messageBuilder = new StringBuilder(); for (int i = 0; i < results.Count; i++) { if (StatusCode.IsNotGood(results[i])) { messageBuilder.AppendLine($"{valueDict.ElementAt(i).Key}: {StatusCodes.GetBrowseName(results[i].Code)}"); } } throw new KepServerWriteException(messageBuilder.ToString()); } } }
public override DataValue Compute(IAggregationContext context, TimeSlice bucket, AggregateState state) { List <DataValue> l = new List <DataValue>(bucket.Values); DataValue dv = l.Count > 0 ? GetDataValue(l) : null; if (SteppedVariable && dv == null) { dv = bucket.LateBound.Value; } DataValue retval = new DataValue(); StatusCode code = StatusCodes.BadNoData; if (dv != null) { code = StatusCode.IsNotGood(dv.StatusCode) ? StatusCodes.UncertainDataSubNormal : StatusCodes.Good; retval.SourceTimestamp = dv.SourceTimestamp; retval.Value = dv.Value; code.AggregateBits = AggregateBits.Raw; if (bucket.Incomplete) { code.AggregateBits |= AggregateBits.Partial; } } else { retval.SourceTimestamp = bucket.From; } retval.StatusCode = code; return(retval); }
internal async Task <object[]> CallMethodAsync(UaItem item, object[] inputArguments) { var session = Session; if (session != null && session.Connected) { try { var callRequest = new CallRequest { MethodsToCall = { new CallMethodRequest { ObjectId = item.StartNodeId, MethodId = item.ResolvedNodeId, InputArguments = inputArguments.Select(a => new Variant(a)).ToArray() } } }; var callResponse = await session.CallAsync(callRequest).ConfigureAwait(false); for (int i = 0; i < callResponse.Results.Count; i++) { if (StatusCode.IsNotGood(callResponse.Results[i].StatusCode)) { Trace.TraceError("Error calling method with MethodId {0} : {1}", callRequest.MethodsToCall[i].MethodId, callResponse.Results[i].StatusCode); } } return(callResponse.Results[0].OutputArguments.Select(a => a.Value).ToArray()); } catch (Exception ex) { Trace.TraceError("Error calling method with MethodId {0} : {1}", item.ResolvedNodeId, ex.Message); } } else { Trace.TraceError("Error calling method with MethodId {0} : {1}", item.ResolvedNodeId, "Session is null or not connected"); } return(null); }
internal async Task SetValueAsync(UaItem item, DataValue value) { item.CacheValue = value; NotifyPropertyChanged(item.DisplayName); var session = Session; if (session != null && session.Connected) { try { var writeRequest = new WriteRequest { NodesToWrite = { new WriteValue { NodeId = item.ResolvedNodeId, AttributeId = (uint)item.AttributeId, Value = value } } }; var writeResponse = await session.WriteAsync(writeRequest).ConfigureAwait(false); for (int i = 0; i < writeResponse.Results.Count; i++) { if (StatusCode.IsNotGood(writeResponse.Results[i])) { Trace.TraceError("Error writing value for NodeId {0} : {1}", writeRequest.NodesToWrite[i].NodeId, writeResponse.Results[i]); } } } catch (Exception ex) { Trace.TraceError("Error writing value for NodeId {0} : {1}", item.ResolvedNodeId, ex.Message); } } else { Trace.TraceError("Error writing value for NodeId {0} : {1}", item.ResolvedNodeId, "Session is null or not connected"); } }
protected override StatusCode ComputeStatus(IAggregationContext context, int numGood, int numBad, TimeSlice bucket) { StatusCode code = base.ComputeStatus(context, numGood, numBad, bucket); if (bucket.EarlyBound.Value == null || StatusCode.IsNotGood(bucket.EarlyBound.Value.StatusCode)) code = StatusCodes.Uncertain; return code; }
/// <summary> /// Produce network messages from the data set message model /// </summary> /// <param name="messages"></param> /// <param name="encoding"></param> /// <returns></returns> private IEnumerable <NetworkMessage> GetNetworkMessages( IEnumerable <DataSetMessageModel> messages, MessageEncoding encoding) { // TODO: Honor single message // TODO: Group by writer foreach (var message in messages) { if (message.WriterGroup?.MessageType .GetValueOrDefault(MessageEncoding.Json) == encoding) { var networkMessage = new NetworkMessage() { MessageContentMask = message.WriterGroup .MessageSettings.NetworkMessageContentMask .ToStackType(message.WriterGroup?.MessageType), PublisherId = message.PublisherId, DataSetClassId = message.Writer?.DataSet? .DataSetMetaData?.DataSetClassId.ToString(), MessageId = message.SequenceNumber.ToString() }; var notificationQueues = message.Notifications.GroupBy(m => m.NodeId) .Select(c => new Queue <MonitoredItemNotificationModel>(c.ToArray())).ToArray(); while (notificationQueues.Where(q => q.Any()).Any()) { var payload = notificationQueues .Select(q => q.Any() ? q.Dequeue() : null) .Where(s => s != null) .ToDictionary( s => s.NodeId.ToExpandedNodeId(message.ServiceMessageContext.NamespaceUris) .AsString(message.ServiceMessageContext), s => s.Value); var dataSetMessage = new DataSetMessage() { DataSetWriterId = message.Writer.DataSetWriterId, MetaDataVersion = new ConfigurationVersionDataType { MajorVersion = message.Writer?.DataSet?.DataSetMetaData? .ConfigurationVersion?.MajorVersion ?? 1, MinorVersion = message.Writer?.DataSet?.DataSetMetaData? .ConfigurationVersion?.MinorVersion ?? 0 }, MessageContentMask = (message.Writer?.MessageSettings?.DataSetMessageContentMask) .ToStackType(message.WriterGroup?.MessageType), Timestamp = message.TimeStamp ?? DateTime.UtcNow, SequenceNumber = message.SequenceNumber, Status = payload.Values.Any(s => StatusCode.IsNotGood(s.StatusCode)) ? StatusCodes.Bad : StatusCodes.Good, Payload = new DataSet(payload, (uint)message.Writer?.DataSetFieldContentMask.ToStackType()) }; networkMessage.Messages.Add(dataSetMessage); } yield return(networkMessage); } } }
/// <summary> /// Calculates the DurationInStateZero and DurationInStateNonZero aggregates for the timeslice. /// </summary> protected DataValue ComputeDurationInState(TimeSlice slice, bool isNonZero) { // get the values in the slice. List <DataValue> values = GetValuesWithSimpleBounds(slice); // check for empty slice. if (values == null) { return(GetNoDataValue(slice)); } // get the regions. List <SubRegion> regions = GetRegionsInValueSet(values, false, true); double duration = 0; for (int ii = 0; ii < regions.Count; ii++) { if (StatusCode.IsNotGood(regions[ii].StatusCode)) { continue; } if (isNonZero) { if (regions[ii].StartValue != 0) { duration += regions[ii].Duration; } } else { if (regions[ii].StartValue == 0) { duration += regions[ii].Duration; } } } // set the timestamp and status. DataValue value = new DataValue(); value.WrappedValue = new Variant(duration, TypeInfo.Scalars.Double); value.SourceTimestamp = GetTimestamp(slice); value.ServerTimestamp = GetTimestamp(slice); value.StatusCode = value.StatusCode.SetAggregateBits(AggregateBits.Calculated); value.StatusCode = GetTimeBasedStatusCode(regions, value.StatusCode); // return result. return(value); }
/// <summary> /// Unpack with a default value /// </summary> /// <typeparam name="T"></typeparam> /// <param name="dataValue"></param> /// <param name="defaultValue"></param> /// <returns></returns> public static T GetValueOrDefault <T>(this DataValue dataValue, T defaultValue = default) { if (dataValue == null) { return(defaultValue); } if (StatusCode.IsNotGood(dataValue.StatusCode)) { return(defaultValue); } var value = dataValue.Value; while (typeof(T).IsEnum) { try { return((T)Enum.ToObject(typeof(T), value)); } catch { break; } } while (!typeof(T).IsInstanceOfType(value)) { try { return(value.As <T>()); } catch { break; } } try { return((T)value); } catch { return(defaultValue); } }
/// <summary> /// Checks if the value is good according to the configuration rules. /// </summary> /// <param name="value">The value to test.</param> /// <returns>True if the value is good.</returns> public bool IsGood(DataValue value) { if (value == null) { return(false); } if (_configuration.TreatUncertainAsBad) { if (StatusCode.IsNotGood(value.StatusCode)) { return(false); } } else { if (StatusCode.IsBad(value.StatusCode)) { return(false); } } return(true); }
/// <summary> /// Calculates the StdDev, Variance, StdDev2 and Variance2 aggregates for the timeslice. /// </summary> protected DataValue ComputeTimeAverage(TimeSlice slice, bool useSimpleBounds, int valueType) { // get the values in the slice. List <DataValue> values = null; if (useSimpleBounds) { values = GetValuesWithSimpleBounds(slice); } else { values = GetValuesWithInterpolatedBounds(slice); } // check for empty slice. if (values == null || values.Count == 0) { return(GetNoDataValue(slice)); } // get the regions. List <SubRegion> regions = GetRegionsInValueSet(values, !useSimpleBounds, Stepped); double total = 0; double totalDuration = 0; bool nonGoodRegionsExists = false; for (int ii = 0; ii < regions.Count; ii++) { double duration = regions[ii].Duration / 1000.0; if (StatusCode.IsNotBad(regions[ii].StatusCode)) { total += (regions[ii].StartValue + regions[ii].EndValue) * duration / 2; totalDuration += duration; } if (StatusCode.IsNotGood(regions[ii].StatusCode)) { nonGoodRegionsExists = true; } } // check if no good data. if (totalDuration == 0) { return(GetNoDataValue(slice)); } // select the result. double result = 0; switch (valueType) { case 1: { result = total / totalDuration; break; } case 2: { result = total; break; } } // set the timestamp and status. DataValue value = new DataValue(); value.WrappedValue = new Variant(result, TypeInfo.Scalars.Double); value.SourceTimestamp = GetTimestamp(slice); value.ServerTimestamp = GetTimestamp(slice); if (useSimpleBounds) { value.StatusCode = GetTimeBasedStatusCode(regions, value.StatusCode); } else { value.StatusCode = StatusCodes.Good; if (nonGoodRegionsExists) { value.StatusCode = StatusCodes.UncertainDataSubNormal; } } value.StatusCode = value.StatusCode.SetAggregateBits(AggregateBits.Calculated); // return result. return(value); }
/// <summary> /// Calculates the Delta2 aggregate for the timeslice. /// </summary> protected DataValue ComputeDelta2(TimeSlice slice) { // get the values in the slice. List <DataValue> values = GetValuesWithSimpleBounds(slice); // check for empty slice. if (values == null || values.Count == 0) { return(GetNoDataValue(slice)); } DataValue start = values[0]; DataValue end = values[values.Count - 1]; // check for bad bounds. if (StatusCode.IsBad(start.StatusCode) || StatusCode.IsBad(end.StatusCode)) { return(GetNoDataValue(slice)); } // convert to doubles. double startValue = 0; TypeInfo originalType = null; try { startValue = CastToDouble(start); originalType = start.WrappedValue.TypeInfo; } catch (Exception) { startValue = Double.NaN; } double endValue = 0; try { endValue = CastToDouble(end); } catch (Exception) { endValue = Double.NaN; } // check for bad bounds. if (Double.IsNaN(startValue) || Double.IsNaN(endValue)) { return(GetNoDataValue(slice)); } DataValue value = new DataValue(); value.SourceTimestamp = GetTimestamp(slice); value.ServerTimestamp = GetTimestamp(slice); if (StatusCode.IsNotGood(start.StatusCode) || StatusCode.IsNotGood(end.StatusCode)) { value.StatusCode = StatusCodes.UncertainDataSubNormal; } value.StatusCode = value.StatusCode.SetAggregateBits(AggregateBits.Calculated); // calculate delta. double delta = endValue - startValue; if (originalType != null && originalType.BuiltInType != BuiltInType.Double) { object delta2 = TypeInfo.Cast(delta, TypeInfo.Scalars.Double, originalType.BuiltInType); value.WrappedValue = new Variant(delta2, originalType); } else { value.WrappedValue = new Variant(delta, TypeInfo.Scalars.Double); } // return result. return(value); }
/// <summary> /// Produce network messages from the data set message model /// </summary> /// <param name="messages"></param> /// <param name="encoding"></param> /// <param name="context"></param> /// <returns></returns> private IEnumerable <NetworkMessage> GetNetworkMessages( IEnumerable <DataSetMessageModel> messages, MessageEncoding encoding, IServiceMessageContext context) { if (context?.NamespaceUris == null) { // Declare all notifications in messages as dropped. int totalNotifications = messages.Sum(m => m?.Notifications?.Count() ?? 0); NotificationsDroppedCount += (uint)totalNotifications; _logger.Warning("Namespace is empty, dropped {totalNotifications} values", totalNotifications); yield break; } // TODO: Honor single message // TODO: Group by writer foreach (var message in messages) { if (message.WriterGroup?.MessageType .GetValueOrDefault(MessageEncoding.Json) == encoding) { var networkMessage = new NetworkMessage() { MessageContentMask = message.WriterGroup .MessageSettings.NetworkMessageContentMask .ToStackType(message.WriterGroup?.MessageType), PublisherId = message.PublisherId, DataSetClassId = message.Writer?.DataSet? .DataSetMetaData?.DataSetClassId.ToString(), DataSetWriterGroup = message.WriterGroup.WriterGroupId, MessageId = message.SequenceNumber.ToString() }; var notificationQueues = message.Notifications .GroupBy(m => !string.IsNullOrEmpty(m.Id) ? m.Id : !string.IsNullOrEmpty(m.DisplayName) ? m.DisplayName : m.NodeId) .Select(c => new Queue <MonitoredItemNotificationModel>(c.ToArray())) .ToArray(); while (notificationQueues.Any(q => q.Any())) { var payload = notificationQueues .Select(q => q.Any() ? q.Dequeue() : null) .Where(s => s != null) .ToDictionary( // Identifier to show for notification in payload of IoT Hub method // Prio 1: Id = DataSetFieldId - if already configured // Prio 2: Id = DisplayName - if already configured // Prio 3: NodeId as configured s => !string.IsNullOrEmpty(s.Id) ? s.Id : !string.IsNullOrEmpty(s.DisplayName) ? s.DisplayName : s.NodeId, s => s.Value); var dataSetMessage = new DataSetMessage() { DataSetWriterId = message.Writer.DataSetWriterId, MetaDataVersion = new ConfigurationVersionDataType { MajorVersion = message.Writer?.DataSet?.DataSetMetaData? .ConfigurationVersion?.MajorVersion ?? 1, MinorVersion = message.Writer?.DataSet?.DataSetMetaData? .ConfigurationVersion?.MinorVersion ?? 0 }, MessageContentMask = (message.Writer?.MessageSettings?.DataSetMessageContentMask) .ToStackType(message.WriterGroup?.MessageType), Timestamp = message.TimeStamp ?? DateTime.UtcNow, SequenceNumber = message.SequenceNumber, Status = payload.Values.Any(s => StatusCode.IsNotGood(s.StatusCode)) ? StatusCodes.Bad : StatusCodes.Good, Payload = new DataSet(payload, (uint)message.Writer?.DataSetFieldContentMask.ToStackType()) }; networkMessage.Messages.Add(dataSetMessage); } yield return(networkMessage); } } }