2using System.Collections.Generic;
3using System.Threading.Tasks;
29 private static Scheduler scheduler =
null;
31 private readonly Dictionary<string, SensorData.Field> fields =
new Dictionary<string, SensorData.Field>();
32 private List<SensorData.Field> toReport =
null;
33 private DateTime nextReport = DateTime.MinValue;
34 private bool hasReport =
false;
85 await base.AnnotatePropertyForm(Form);
87 if ((this.
MetaData?.Length ?? 0) > 0)
92 string ExternalDescription = await
Namespace.
GetStringAsync(3,
"Meta-data value is defined by external source.");
99 Form.
Pages.Add(MetaDataPage);
104 if (Tag.
Value is
string s)
107 new string[] { s },
null, ExternalDescription,
new StringDataType(),
108 null,
null,
false,
false,
false);
110 else if (Tag.
Value is
int i)
113 new string[] { i.ToString() },
null, ExternalDescription,
new IntegerDataType(),
114 null,
null,
false,
false,
false);
116 else if (Tag.
Value is
long l)
119 new string[] { l.ToString() },
null, ExternalDescription,
new LongDataType(),
120 null,
null,
false,
false,
false);
122 else if (Tag.
Value is
short sh)
125 new string[] { sh.ToString() },
null, ExternalDescription,
new ShortDataType(),
126 null,
null,
false,
false,
false);
128 else if (Tag.
Value is
byte b2)
131 new string[] { b2.ToString() },
null, ExternalDescription,
new ByteDataType(),
132 null,
null,
false,
false,
false);
134 else if (Tag.
Value is
double d)
137 new string[] { CommonTypes.Encode(d) },
null, ExternalDescription,
new DoubleDataType(),
138 null,
null,
false,
false,
false);
140 else if (Tag.
Value is decimal d2)
143 new string[] { CommonTypes.Encode(d2) },
null, ExternalDescription,
new DecimalDataType(),
144 null,
null,
false,
false,
false);
146 else if (Tag.
Value is
bool b)
149 new string[] { CommonTypes.Encode(b) },
null, ExternalDescription,
new BooleanDataType(),
150 null,
null,
false,
false,
false);
152 else if (Tag.
Value is TimeSpan TS)
155 new string[] { TS.ToString() },
null, ExternalDescription,
new TimeDataType(),
156 null,
null,
false,
false,
false);
158 else if (Tag.
Value is DateTime TP)
161 new string[] { XML.Encode(TP) },
null, ExternalDescription,
new DateTimeDataType(),
162 null,
null,
false,
false,
false);
164 else if (Tag.
Value is Uri Uri)
167 new string[] { Uri.ToString() },
null, ExternalDescription,
new AnyUriDataType(),
168 null,
null,
false,
false,
false);
170 else if (Tag.
Value is
string[] Rows)
173 Rows,
null, ExternalDescription,
null,
null,
null,
false,
false,
false);
178 new string[] { Tag.Value?.ToString() ?? string.Empty },
null, ExternalDescription,
null,
179 null,
null,
false,
false,
false);
197 if (this.metaDataByName is
null)
198 this.BuildDictionary();
212 private void BuildDictionary()
214 SortedDictionary<string, MetaDataValue> ByName =
new SortedDictionary<string, MetaDataValue>();
222 this.metaDataByName = ByName;
225 private SortedDictionary<string, MetaDataValue> metaDataByName =
null;
238 return Task.CompletedTask;
239 else if (Prev is
int)
242 Field.Error =
"Value must be a valid integer.";
244 else if (Prev is
long)
247 Field.Error =
"Value must be a valid long integer.";
249 else if (Prev is
short)
252 Field.Error =
"Value must be a valid short integer.";
254 else if (Prev is
byte)
257 Field.Error =
"Value must be a valid byte.";
259 else if (Prev is
double)
262 Field.Error =
"Value must be a valid double-precision floating-point value.";
264 else if (Prev is decimal)
267 Field.Error =
"Value must be a valid decimal-precision floating-point value.";
269 else if (Prev is
bool)
272 Field.Error =
"Value must be a valid boolean value.";
274 else if (Prev is TimeSpan)
277 Field.Error =
"Value must be a valid TimeSpan value.";
279 else if (Prev is DateTime)
282 Field.Error =
"Value must be a valid DateTime value.";
284 else if (Prev is Uri)
287 Field.Error =
"Value must be a valid URI value.";
289 else if (Prev is
string[])
291 return Task.CompletedTask;
295 return Task.CompletedTask;
301 Field.Error = ex.Message;
305 return Task.CompletedTask;
314 if (this.metaDataByName is
null)
315 this.BuildDictionary();
321 if (Prev.Value is
string)
323 else if (Prev.Value is
int)
328 else if (Prev.Value is
long)
333 else if (Prev.Value is
short)
336 Field.Error =
"Value must be a valid short integer.";
338 else if (Prev.Value is
byte)
343 else if (Prev.Value is
double)
348 else if (Prev.Value is decimal)
353 else if (Prev.Value is
bool)
358 else if (Prev.Value is TimeSpan)
363 else if (Prev.Value is DateTime)
368 else if (Prev.Value is Uri)
373 else if (Prev.Value is
string[])
381 Field.Error = ex.Message;
387 return Task.CompletedTask;
410 if (this.metaDataByName is
null)
411 this.BuildDictionary();
416 this.SetMetaDataPriv(
Name, Value);
421 private void SetMetaDataPriv(
string Name,
object Value)
430 this.metaDataByName.Values.CopyTo(Values, 0);
431 this.MetaData = Values;
442 LinkedList<Parameter> Result = await base.GetDisplayableParametersAsync(
Language, Caller) as LinkedList<Parameter>;
448 if (Tag.
Value is
string s)
450 else if (Tag.
Value is
int i)
452 else if (Tag.
Value is
long l)
454 else if (Tag.
Value is
short sh)
456 else if (Tag.
Value is
byte b)
458 else if (Tag.
Value is
double d)
460 else if (Tag.
Value is decimal d2)
462 else if (Tag.
Value is
bool b2)
464 else if (Tag.
Value is TimeSpan TS)
466 else if (Tag.
Value is DateTime TP)
468 else if (Tag.
Value is Uri Uri)
496 foreach (SensorData.Field
Field in Fields)
500 if (
Field.Type.HasFlag(SensorData.FieldType.Momentary))
502 if (this.toReport is
null)
503 this.toReport =
new List<SensorData.
Field>();
505 this.toReport.Add(
Field);
506 this.hasReport =
true;
512 if (scheduler is
null)
515 this.toReport.Clear();
516 this.hasReport =
false;
520 if (this.nextReport != DateTime.MinValue)
521 scheduler.
Remove(this.nextReport);
523 this.nextReport = scheduler.
Add(DateTime.Now.AddMilliseconds(250),
this.DoReport,
null);
529 private void DoReport(
object _)
534 this.toReport.Clear();
535 this.hasReport =
false;
557 return this.fields.Count > 0;
570 List<SensorData.Field> ToReport =
new List<SensorData.Field>();
574 foreach (SensorData.Field
Field in
this.fields.Values)
581 if (DoneAfter || ToReport.Count > 0)
584 return Task.CompletedTask;
600 FieldValue is
double ||
601 FieldValue is
string ||
602 FieldValue is
bool ||
603 FieldValue is Enum ||
604 FieldValue is DateTime ||
605 FieldValue is TimeSpan ||
607 FieldValue is sbyte ||
608 FieldValue is
short ||
610 FieldValue is
long ||
611 FieldValue is
byte ||
612 FieldValue is ushort ||
613 FieldValue is uint ||
627 List<ControlParameter> Parameters =
new List<ControlParameter>();
634 if (FieldValue is
double d)
637 _ => Task.FromResult<
double?>(d),
641 await this.DoCallback(CallbackUrl, PayloadScript, d);
644 else if (FieldValue is
string s)
647 _ => Task.FromResult<
string>(s),
651 await this.DoCallback(CallbackUrl, PayloadScript, s);
654 else if (FieldValue is
bool b)
657 _ => Task.FromResult<
bool?>(b),
661 await this.DoCallback(CallbackUrl, PayloadScript, b);
664 else if (FieldValue is Enum e)
666 Parameters.Add(
new EnumControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.", e.GetType(),
667 _ => Task.FromResult<Enum>(e),
671 await this.DoCallback(CallbackUrl, PayloadScript, e);
674 else if (FieldValue is DateTime DT)
677 _ => Task.FromResult<DateTime?>(DT),
681 await this.DoCallback(CallbackUrl, PayloadScript, DT);
684 else if (FieldValue is TimeSpan TS)
687 _ => Task.FromResult<TimeSpan?>(TS),
691 await this.DoCallback(CallbackUrl, PayloadScript, TS);
701 await this.DoCallback(CallbackUrl, PayloadScript, D);
704 else if (FieldValue is sbyte i8)
706 Parameters.Add(
new Int32ControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.", sbyte.MinValue, sbyte.MaxValue,
707 _ => Task.FromResult<
int?>(i8),
711 await this.DoCallback<int>(CallbackUrl, PayloadScript, i8);
714 else if (FieldValue is
short i16)
716 Parameters.Add(
new Int32ControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.",
short.MinValue,
short.MaxValue,
717 _ => Task.FromResult<
int?>(i16),
721 await this.DoCallback<int>(CallbackUrl, PayloadScript, i16);
724 else if (FieldValue is
int i32)
726 Parameters.Add(
new Int32ControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.",
null,
null,
727 _ => Task.FromResult<
int?>(i32),
731 await this.DoCallback<int>(CallbackUrl, PayloadScript, i32);
734 else if (FieldValue is
long i64)
736 Parameters.Add(
new Int64ControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.",
null,
null,
737 _ => Task.FromResult<
long?>(i64),
741 await this.DoCallback<long>(CallbackUrl, PayloadScript, i64);
744 else if (FieldValue is
byte ui8)
746 Parameters.Add(
new Int32ControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.",
byte.MinValue,
byte.MaxValue,
747 _ => Task.FromResult<
int?>(ui8),
751 await this.DoCallback<int>(CallbackUrl, PayloadScript, ui8);
754 else if (FieldValue is ushort ui16)
756 Parameters.Add(
new Int32ControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.", ushort.MinValue, ushort.MaxValue,
757 _ => Task.FromResult<
int?>(ui16),
760 ui16 = (ushort)Value;
761 await this.DoCallback<int>(CallbackUrl, PayloadScript, ui16);
764 else if (FieldValue is uint ui32)
766 Parameters.Add(
new Int64ControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.", uint.MinValue, uint.MaxValue,
767 _ => Task.FromResult<
long?>(ui32),
771 await this.DoCallback<long>(CallbackUrl, PayloadScript, ui32);
774 else if (FieldValue is ulong ui64)
776 Parameters.Add(
new DoubleControlParameter(FieldName,
"Control", FieldName +
":",
"Value to set.", ulong.MinValue, ulong.MaxValue,
777 _ => Task.FromResult<
double?>(ui64),
781 await this.DoCallback<double>(CallbackUrl, PayloadScript, ui64);
786 return Task.FromResult(Parameters.ToArray());
789 private async Task DoCallback<T>(
string CallbackUrl,
string PayloadScript, T Value)
803 public override Task<IEnumerable<ICommand>>
Commands => this.GetCommands();
805 private async Task<IEnumerable<ICommand>> GetCommands()
807 List<ICommand>
Commands =
new List<ICommand>();
808 Commands.AddRange(await base.Commands);
810 Commands.Add(
new AddMetaDataString(
this));
811 Commands.Add(
new AddMetaDataInt32(
this));
812 Commands.Add(
new AddMetaDataInt64(
this));
813 Commands.Add(
new AddMetaDataDouble(
this));
814 Commands.Add(
new AddMetaDataBoolean(
this));
815 Commands.Add(
new AddMetaDataDateTime(
this));
816 Commands.Add(
new AddMetaDataTimeSpan(
this));
817 Commands.Add(
new AddMetaDataDuration(
this));
Helps with parsing of commong data types.
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Static class managing encoding and decoding of internet content.
static Task< object > PostAsync(Uri Uri, object Data, params KeyValuePair< string, string >[] Headers)
Posts to a resource, using a Uniform Resource Identifier (or Locator).
Helps with common XML-related tasks.
static bool TryParse(string s, out DateTime Value)
Tries to decode a string encoded DateTime.
Static class managing the application event log. Applications and services log events on this static ...
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Class managing a page in a data form layout.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static async Task Update(object Object)
Updates an object in the database.
Static class that dynamically manages types and interfaces available in the runtime environment.
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
Contains information about a language.
Task< string > GetStringAsync(Type Type, int Id, string Default)
Gets the string value of a string ID. If no such string exists, a string is created with the default ...
async Task< Namespace > GetNamespaceAsync(string Name)
Gets the namespace object, given its name, if available.
Contains information about a namespace in a language.
Task< LanguageString > GetStringAsync(int Id)
Gets the string object, given its ID, if available.
Basic access point for runtime language localization.
static async Task< Language > GetLanguageAsync(string Code)
Gets the languge object, given its language code, if available.
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
bool Remove(DateTime When)
Removes an event scheduled for a given point in time.
DateTime Add(DateTime When, ScheduledEventCallback Callback, object State)
Adds an event.
Class managing a script expression.
static Task< object > EvalAsync(string Script)
Evaluates script, in string format.
Boolean control parameter.
DateTime control parameter.
Double control parameter.
Duration control parameter.
Enumeration control parameter.
String control parameter.
Boolean-valued parameter.
DateTime-valued parameter.
TimeSpan-valued parameter.
void NewMomentaryValues(params Field[] Values)
Reports newly measured values.
Class for the root node of the Metering topology.
Base class for all provisioned metering nodes.
Tokens available in request.
Virtual node, that can be used as a placeholder for services.
void ReportSensorData(SensorData.Field Field)
Reports sensor data on the node.
object GetMetaData(string Name)
Gets a meta-data value, if available.
virtual Task StartReadout(ISensorReadout Request, bool DoneAfter)
Starts the readout of the sensor.
override async Task< IEnumerable< Parameter > > GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
override async Task AnnotatePropertyForm(FormState Form)
Annotates the property form.
VirtualNode()
Virtual node, that can be used as a placeholder for services.
Task StartReadout(ISensorReadout Request)
Starts the readout of the sensor.
virtual Task< ControlParameter[]> GetControlParameters()
Get control parameters for the actuator.
override Task< bool > AcceptsParentAsync(INode Parent)
If the node accepts a presumptive parent, i.e. can be added to that parent (if that parent accepts th...
override bool IsControllable
If the node can be controlled.
override Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
override bool IsReadable
If the node can be read.
override Task< IEnumerable< ICommand > > Commands
Available command objects. If no commands are available, null is returned.
void ReportSensorData(params SensorData.Field[] Fields)
Reports sensor data on the node.
Task ValidateCustomProperty(Field Field)
Performs custom validation of a property.
MetaDataValue[] MetaData
Meta-data attached to virtual node.
Task SetCustomProperty(Field Field)
Sets the custom parameter to the value(s) provided in the field.
bool TryGetMetaDataValue(string Name, out object Value)
Tries to get a meta-data value
async Task SetMetaData(string Name, object Value)
Sets a meta-data value.
override async Task< bool > AcceptsChildAsync(INode Child)
If the node accepts a presumptive child, i.e. can receive as a child (if that child accepts the node ...
Interface for actuator nodes.
Interface for nodes that are published through the concentrator interface.
INode Parent
Parent Node, or null if a root node.
Task< bool > AcceptsParentAsync(INode Parent)
If the node accepts a presumptive parent, i.e. can be added to that parent (if that parent accepts th...
Interface for sensor nodes.
Interface for classes managing sensor data readouts.
bool IsIncluded(string FieldName)
Checks if a field with the given parameters is included in the readout.
Task ReportFields(bool Done, params Field[] Fields)
Report read fields to the client.
Represents a duration value, as defined by the xsd:duration data type: http://www....