Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
VirtualNode.cs
1using System;
2using System.Collections.Generic;
3using System.Threading.Tasks;
4using Waher.Content;
6using Waher.Events;
15using Waher.Script;
21
23{
28 {
29 private static Scheduler scheduler = null;
30
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;
35
39 public VirtualNode()
40 : base()
41 {
42 }
43
47 public MetaDataValue[] MetaData { get; set; }
48
54 public override Task<string> GetTypeNameAsync(Language Language)
55 {
56 return Language.GetStringAsync(typeof(VirtualNode), 1, "Virtual Node");
57 }
58
64 public override async Task<bool> AcceptsChildAsync(INode Child)
65 {
66 return Child is VirtualNode || await Child.AcceptsParentAsync(this);
67 }
68
74 public override Task<bool> AcceptsParentAsync(INode Parent)
75 {
76 return Task.FromResult(Parent is Root || Parent is VirtualNode);
77 }
78
83 public override async Task AnnotatePropertyForm(FormState Form)
84 {
85 await base.AnnotatePropertyForm(Form);
86
87 if ((this.MetaData?.Length ?? 0) > 0)
88 {
91 string PageLabel = await Namespace.GetStringAsync(2, "Meta-data");
92 string ExternalDescription = await Namespace.GetStringAsync(3, "Meta-data value is defined by external source.");
93 Page MetaDataPage = new Page(Form.Form, PageLabel)
94 {
95 Ordinal = Form.PageOrdinal++
96 };
98
99 Form.Pages.Add(MetaDataPage);
100 Form.PageByLabel[PageLabel] = MetaDataPage;
101
102 foreach (MetaDataValue Tag in this.MetaData)
103 {
104 if (Tag.Value is string s)
105 {
106 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
107 new string[] { s }, null, ExternalDescription, new StringDataType(),
108 null, null, false, false, false);
109 }
110 else if (Tag.Value is int i)
111 {
112 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
113 new string[] { i.ToString() }, null, ExternalDescription, new IntegerDataType(),
114 null, null, false, false, false);
115 }
116 else if (Tag.Value is long l)
117 {
118 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
119 new string[] { l.ToString() }, null, ExternalDescription, new LongDataType(),
120 null, null, false, false, false);
121 }
122 else if (Tag.Value is short sh)
123 {
124 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
125 new string[] { sh.ToString() }, null, ExternalDescription, new ShortDataType(),
126 null, null, false, false, false);
127 }
128 else if (Tag.Value is byte b2)
129 {
130 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
131 new string[] { b2.ToString() }, null, ExternalDescription, new ByteDataType(),
132 null, null, false, false, false);
133 }
134 else if (Tag.Value is double d)
135 {
136 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
137 new string[] { CommonTypes.Encode(d) }, null, ExternalDescription, new DoubleDataType(),
138 null, null, false, false, false);
139 }
140 else if (Tag.Value is decimal d2)
141 {
142 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
143 new string[] { CommonTypes.Encode(d2) }, null, ExternalDescription, new DecimalDataType(),
144 null, null, false, false, false);
145 }
146 else if (Tag.Value is bool b)
147 {
148 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
149 new string[] { CommonTypes.Encode(b) }, null, ExternalDescription, new BooleanDataType(),
150 null, null, false, false, false);
151 }
152 else if (Tag.Value is TimeSpan TS)
153 {
154 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
155 new string[] { TS.ToString() }, null, ExternalDescription, new TimeDataType(),
156 null, null, false, false, false);
157 }
158 else if (Tag.Value is DateTime TP)
159 {
160 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
161 new string[] { XML.Encode(TP) }, null, ExternalDescription, new DateTimeDataType(),
162 null, null, false, false, false);
163 }
164 else if (Tag.Value is Uri Uri)
165 {
166 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
167 new string[] { Uri.ToString() }, null, ExternalDescription, new AnyUriDataType(),
168 null, null, false, false, false);
169 }
170 else if (Tag.Value is string[] Rows)
171 {
172 Field = new TextMultiField(Form.Form, Tag.Name, Tag.Name, false,
173 Rows, null, ExternalDescription, null, null, null, false, false, false);
174 }
175 else
176 {
177 Field = new TextSingleField(Form.Form, Tag.Name, Tag.Name, false,
178 new string[] { Tag.Value?.ToString() ?? string.Empty }, null, ExternalDescription, null,
179 null, null, false, false, false);
180 }
181
182 Field.Ordinal = Form.FieldOrdinal++;
183 Form.Fields.Add(Field);
184 MetaDataPage.Add(new FieldReference(Form.Form, Field.Var));
185 }
186 }
187 }
188
195 public bool TryGetMetaDataValue(string Name, out object Value)
196 {
197 if (this.metaDataByName is null)
198 this.BuildDictionary();
199
200 if (this.metaDataByName.TryGetValue(Name, out MetaDataValue Tag))
201 {
202 Value = Tag.Value;
203 return true;
204 }
205 else
206 {
207 Value = null;
208 return false;
209 }
210 }
211
212 private void BuildDictionary()
213 {
214 SortedDictionary<string, MetaDataValue> ByName = new SortedDictionary<string, MetaDataValue>();
215
216 if (!(this.MetaData is null))
217 {
218 foreach (MetaDataValue P in this.MetaData)
219 ByName[P.Name] = P;
220 }
221
222 this.metaDataByName = ByName;
223 }
224
225 private SortedDictionary<string, MetaDataValue> metaDataByName = null;
226
232 {
233 if (this.TryGetMetaDataValue(Field.Var, out object Prev))
234 {
235 try
236 {
237 if (Prev is string)
238 return Task.CompletedTask;
239 else if (Prev is int)
240 {
241 if (!int.TryParse(Field.ValueString, out _))
242 Field.Error = "Value must be a valid integer.";
243 }
244 else if (Prev is long)
245 {
246 if (!long.TryParse(Field.ValueString, out _))
247 Field.Error = "Value must be a valid long integer.";
248 }
249 else if (Prev is short)
250 {
251 if (!short.TryParse(Field.ValueString, out _))
252 Field.Error = "Value must be a valid short integer.";
253 }
254 else if (Prev is byte)
255 {
256 if (!byte.TryParse(Field.ValueString, out _))
257 Field.Error = "Value must be a valid byte.";
258 }
259 else if (Prev is double)
260 {
261 if (!CommonTypes.TryParse(Field.ValueString, out double _))
262 Field.Error = "Value must be a valid double-precision floating-point value.";
263 }
264 else if (Prev is decimal)
265 {
266 if (!CommonTypes.TryParse(Field.ValueString, out decimal _))
267 Field.Error = "Value must be a valid decimal-precision floating-point value.";
268 }
269 else if (Prev is bool)
270 {
271 if (!CommonTypes.TryParse(Field.ValueString, out bool _))
272 Field.Error = "Value must be a valid boolean value.";
273 }
274 else if (Prev is TimeSpan)
275 {
276 if (!TimeSpan.TryParse(Field.ValueString, out _))
277 Field.Error = "Value must be a valid TimeSpan value.";
278 }
279 else if (Prev is DateTime)
280 {
281 if (!XML.TryParse(Field.ValueString, out DateTime _))
282 Field.Error = "Value must be a valid DateTime value.";
283 }
284 else if (Prev is Uri)
285 {
286 if (!Uri.TryCreate(Field.ValueString, UriKind.Absolute, out _))
287 Field.Error = "Value must be a valid URI value.";
288 }
289 else if (Prev is string[])
290 {
291 return Task.CompletedTask;
292 }
293 else
294 {
295 return Task.CompletedTask;
296 }
297 }
298 catch (Exception ex)
299 {
300 ex = Log.UnnestException(ex);
301 Field.Error = ex.Message;
302 }
303 }
304
305 return Task.CompletedTask;
306 }
307
313 {
314 if (this.metaDataByName is null)
315 this.BuildDictionary();
316
317 if (this.metaDataByName.TryGetValue(Field.Var, out MetaDataValue Prev))
318 {
319 try
320 {
321 if (Prev.Value is string)
322 Prev.Value = Field.ValueString;
323 else if (Prev.Value is int)
324 {
325 if (int.TryParse(Field.ValueString, out int i))
326 Prev.Value = i;
327 }
328 else if (Prev.Value is long)
329 {
330 if (long.TryParse(Field.ValueString, out long l))
331 Prev.Value = l;
332 }
333 else if (Prev.Value is short)
334 {
335 if (short.TryParse(Field.ValueString, out short sh))
336 Field.Error = "Value must be a valid short integer.";
337 }
338 else if (Prev.Value is byte)
339 {
340 if (byte.TryParse(Field.ValueString, out byte b))
341 Prev.Value = b;
342 }
343 else if (Prev.Value is double)
344 {
345 if (CommonTypes.TryParse(Field.ValueString, out double d))
346 Prev.Value = d;
347 }
348 else if (Prev.Value is decimal)
349 {
350 if (CommonTypes.TryParse(Field.ValueString, out decimal d))
351 Prev.Value = d;
352 }
353 else if (Prev.Value is bool)
354 {
355 if (CommonTypes.TryParse(Field.ValueString, out bool b))
356 Prev.Value = b;
357 }
358 else if (Prev.Value is TimeSpan)
359 {
360 if (TimeSpan.TryParse(Field.ValueString, out TimeSpan TS))
361 Prev.Value = TS;
362 }
363 else if (Prev.Value is DateTime)
364 {
365 if (XML.TryParse(Field.ValueString, out DateTime TP))
366 Prev.Value = TP;
367 }
368 else if (Prev.Value is Uri)
369 {
370 if (Uri.TryCreate(Field.ValueString, UriKind.Absolute, out Uri Url))
371 Prev.Value = Url;
372 }
373 else if (Prev.Value is string[])
374 Prev.Value = Field.ValueStrings;
375 else
376 Prev.Value = Field.ValueString;
377 }
378 catch (Exception ex)
379 {
380 ex = Log.UnnestException(ex);
381 Field.Error = ex.Message;
382 }
383 }
384 else
385 this.SetMetaDataPriv(Field.Var, Field.ValueString);
386
387 return Task.CompletedTask;
388 }
389
395 public object GetMetaData(string Name)
396 {
397 if (this.TryGetMetaDataValue(Name, out object Value))
398 return Value;
399 else
400 return null;
401 }
402
408 public async Task SetMetaData(string Name, object Value)
409 {
410 if (this.metaDataByName is null)
411 this.BuildDictionary();
412
413 if (this.metaDataByName.TryGetValue(Name, out MetaDataValue Tag))
414 Tag.Value = Value;
415 else
416 this.SetMetaDataPriv(Name, Value);
417
418 await Database.Update(this);
419 }
420
421 private void SetMetaDataPriv(string Name, object Value)
422 {
423 this.metaDataByName[Name] = new MetaDataValue()
424 {
425 Name = Name,
426 Value = Value
427 };
428
429 MetaDataValue[] Values = new MetaDataValue[this.metaDataByName.Count];
430 this.metaDataByName.Values.CopyTo(Values, 0);
431 this.MetaData = Values;
432 }
433
440 public override async Task<IEnumerable<Parameter>> GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
441 {
442 LinkedList<Parameter> Result = await base.GetDisplayableParametersAsync(Language, Caller) as LinkedList<Parameter>;
443
444 if (!(this.MetaData is null))
445 {
446 foreach (MetaDataValue Tag in this.MetaData)
447 {
448 if (Tag.Value is string s)
449 Result.AddLast(new StringParameter(Tag.Name, Tag.Name, s));
450 else if (Tag.Value is int i)
451 Result.AddLast(new Int32Parameter(Tag.Name, Tag.Name, i));
452 else if (Tag.Value is long l)
453 Result.AddLast(new Int64Parameter(Tag.Name, Tag.Name, l));
454 else if (Tag.Value is short sh)
455 Result.AddLast(new Int32Parameter(Tag.Name, Tag.Name, sh));
456 else if (Tag.Value is byte b)
457 Result.AddLast(new Int32Parameter(Tag.Name, Tag.Name, b));
458 else if (Tag.Value is double d)
459 Result.AddLast(new DoubleParameter(Tag.Name, Tag.Name, d));
460 else if (Tag.Value is decimal d2)
461 Result.AddLast(new DoubleParameter(Tag.Name, Tag.Name, (double)d2));
462 else if (Tag.Value is bool b2)
463 Result.AddLast(new BooleanParameter(Tag.Name, Tag.Name, b2));
464 else if (Tag.Value is TimeSpan TS)
465 Result.AddLast(new TimeSpanParameter(Tag.Name, Tag.Name, TS));
466 else if (Tag.Value is DateTime TP)
467 Result.AddLast(new DateTimeParameter(Tag.Name, Tag.Name, TP));
468 else if (Tag.Value is Uri Uri)
469 Result.AddLast(new StringParameter(Tag.Name, Tag.Name, Uri.ToString()));
470 }
471 }
472
473 return Result;
474 }
475
480 public void ReportSensorData(SensorData.Field Field)
481 {
482 this.ReportSensorData(new SensorData.Field[] { Field });
483 }
484
489 public void ReportSensorData(params SensorData.Field[] Fields)
490 {
491 if (scheduler is null && Types.TryGetModuleParameter("Scheduler", out object Obj) && Obj is Scheduler Scheduler)
492 scheduler = Scheduler;
493
494 lock (this.fields)
495 {
496 foreach (SensorData.Field Field in Fields)
497 {
498 this.fields[Field.Name] = Field;
499
500 if (Field.Type.HasFlag(SensorData.FieldType.Momentary))
501 {
502 if (this.toReport is null)
503 this.toReport = new List<SensorData.Field>();
504
505 this.toReport.Add(Field);
506 this.hasReport = true;
507 }
508 }
509
510 if (this.hasReport)
511 {
512 if (scheduler is null)
513 {
514 this.NewMomentaryValues(this.toReport.ToArray());
515 this.toReport.Clear();
516 this.hasReport = false;
517 }
518 else
519 {
520 if (this.nextReport != DateTime.MinValue)
521 scheduler.Remove(this.nextReport);
522
523 this.nextReport = scheduler.Add(DateTime.Now.AddMilliseconds(250), this.DoReport, null);
524 }
525 }
526 }
527 }
528
529 private void DoReport(object _)
530 {
531 lock (this.fields)
532 {
533 this.NewMomentaryValues(this.toReport.ToArray());
534 this.toReport.Clear();
535 this.hasReport = false;
536 }
537 }
538
543 public Task StartReadout(ISensorReadout Request)
544 {
545 return this.StartReadout(Request, true);
546 }
547
551 public override bool IsReadable
552 {
553 get
554 {
555 lock (this.fields)
556 {
557 return this.fields.Count > 0;
558 }
559 }
560 }
561
568 public virtual Task StartReadout(ISensorReadout Request, bool DoneAfter)
569 {
570 List<SensorData.Field> ToReport = new List<SensorData.Field>();
571
572 lock (this.fields)
573 {
574 foreach (SensorData.Field Field in this.fields.Values)
575 {
576 if (Request.IsIncluded(Field.Name, Field.Timestamp, Field.Type))
577 ToReport.Add(Field);
578 }
579 }
580
581 if (DoneAfter || ToReport.Count > 0)
582 Request.ReportFields(DoneAfter, ToReport.ToArray());
583
584 return Task.CompletedTask;
585 }
586
590 public override bool IsControllable
591 {
592 get
593 {
594 if (this.TryGetMetaDataValue("Callback", out object Obj) && Obj is string &&
595 this.TryGetMetaDataValue("Payload", out Obj) && Obj is string &&
596 this.TryGetMetaDataValue("FieldName", out Obj) && Obj is string &&
597 this.TryGetMetaDataValue("FieldValue", out object FieldValue))
598 {
599 return
600 FieldValue is double ||
601 FieldValue is string ||
602 FieldValue is bool ||
603 FieldValue is Enum ||
604 FieldValue is DateTime ||
605 FieldValue is TimeSpan ||
606 FieldValue is Duration ||
607 FieldValue is sbyte ||
608 FieldValue is short ||
609 FieldValue is int ||
610 FieldValue is long ||
611 FieldValue is byte ||
612 FieldValue is ushort ||
613 FieldValue is uint ||
614 FieldValue is ulong;
615 }
616 else
617 return false;
618 }
619 }
620
625 public virtual Task<ControlParameter[]> GetControlParameters()
626 {
627 List<ControlParameter> Parameters = new List<ControlParameter>();
628
629 if (this.TryGetMetaDataValue("Callback", out object Obj) && Obj is string CallbackUrl &&
630 this.TryGetMetaDataValue("Payload", out Obj) && Obj is string PayloadScript &&
631 this.TryGetMetaDataValue("FieldName", out Obj) && Obj is string FieldName &&
632 this.TryGetMetaDataValue("FieldValue", out object FieldValue))
633 {
634 if (FieldValue is double d)
635 {
636 Parameters.Add(new DoubleControlParameter(FieldName, "Control", FieldName + ":", "Value to set.",
637 _ => Task.FromResult<double?>(d),
638 async (_, Value) =>
639 {
640 d = Value;
641 await this.DoCallback(CallbackUrl, PayloadScript, d);
642 }));
643 }
644 else if (FieldValue is string s)
645 {
646 Parameters.Add(new StringControlParameter(FieldName, "Control", FieldName + ":", "Value to set.",
647 _ => Task.FromResult<string>(s),
648 async (_, Value) =>
649 {
650 s = Value;
651 await this.DoCallback(CallbackUrl, PayloadScript, s);
652 }));
653 }
654 else if (FieldValue is bool b)
655 {
656 Parameters.Add(new BooleanControlParameter(FieldName, "Control", FieldName + ":", "Value to set.",
657 _ => Task.FromResult<bool?>(b),
658 async (_, Value) =>
659 {
660 b = Value;
661 await this.DoCallback(CallbackUrl, PayloadScript, b);
662 }));
663 }
664 else if (FieldValue is Enum e)
665 {
666 Parameters.Add(new EnumControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", e.GetType(),
667 _ => Task.FromResult<Enum>(e),
668 async (_, Value) =>
669 {
670 e = Value;
671 await this.DoCallback(CallbackUrl, PayloadScript, e);
672 }));
673 }
674 else if (FieldValue is DateTime DT)
675 {
676 Parameters.Add(new DateTimeControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", null, null,
677 _ => Task.FromResult<DateTime?>(DT),
678 async (_, Value) =>
679 {
680 DT = Value;
681 await this.DoCallback(CallbackUrl, PayloadScript, DT);
682 }));
683 }
684 else if (FieldValue is TimeSpan TS)
685 {
686 Parameters.Add(new TimeControlParameter(FieldName, "Control", FieldName + ":", "Value to set.",
687 _ => Task.FromResult<TimeSpan?>(TS),
688 async (_, Value) =>
689 {
690 TS = Value;
691 await this.DoCallback(CallbackUrl, PayloadScript, TS);
692 }));
693 }
694 else if (FieldValue is Duration D)
695 {
696 Parameters.Add(new DurationControlParameter(FieldName, "Control", FieldName + ":", "Value to set.",
697 _ => Task.FromResult<Duration>(D),
698 async (_, Value) =>
699 {
700 D = Value;
701 await this.DoCallback(CallbackUrl, PayloadScript, D);
702 }));
703 }
704 else if (FieldValue is sbyte i8)
705 {
706 Parameters.Add(new Int32ControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", sbyte.MinValue, sbyte.MaxValue,
707 _ => Task.FromResult<int?>(i8),
708 async (_, Value) =>
709 {
710 i8 = (sbyte)Value;
711 await this.DoCallback<int>(CallbackUrl, PayloadScript, i8);
712 }));
713 }
714 else if (FieldValue is short i16)
715 {
716 Parameters.Add(new Int32ControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", short.MinValue, short.MaxValue,
717 _ => Task.FromResult<int?>(i16),
718 async (_, Value) =>
719 {
720 i16 = (short)Value;
721 await this.DoCallback<int>(CallbackUrl, PayloadScript, i16);
722 }));
723 }
724 else if (FieldValue is int i32)
725 {
726 Parameters.Add(new Int32ControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", null, null,
727 _ => Task.FromResult<int?>(i32),
728 async (_, Value) =>
729 {
730 i32 = Value;
731 await this.DoCallback<int>(CallbackUrl, PayloadScript, i32);
732 }));
733 }
734 else if (FieldValue is long i64)
735 {
736 Parameters.Add(new Int64ControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", null, null,
737 _ => Task.FromResult<long?>(i64),
738 async (_, Value) =>
739 {
740 i64 = Value;
741 await this.DoCallback<long>(CallbackUrl, PayloadScript, i64);
742 }));
743 }
744 else if (FieldValue is byte ui8)
745 {
746 Parameters.Add(new Int32ControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", byte.MinValue, byte.MaxValue,
747 _ => Task.FromResult<int?>(ui8),
748 async (_, Value) =>
749 {
750 ui8 = (byte)Value;
751 await this.DoCallback<int>(CallbackUrl, PayloadScript, ui8);
752 }));
753 }
754 else if (FieldValue is ushort ui16)
755 {
756 Parameters.Add(new Int32ControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", ushort.MinValue, ushort.MaxValue,
757 _ => Task.FromResult<int?>(ui16),
758 async (_, Value) =>
759 {
760 ui16 = (ushort)Value;
761 await this.DoCallback<int>(CallbackUrl, PayloadScript, ui16);
762 }));
763 }
764 else if (FieldValue is uint ui32)
765 {
766 Parameters.Add(new Int64ControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", uint.MinValue, uint.MaxValue,
767 _ => Task.FromResult<long?>(ui32),
768 async (_, Value) =>
769 {
770 ui32 = (uint)Value;
771 await this.DoCallback<long>(CallbackUrl, PayloadScript, ui32);
772 }));
773 }
774 else if (FieldValue is ulong ui64)
775 {
776 Parameters.Add(new DoubleControlParameter(FieldName, "Control", FieldName + ":", "Value to set.", ulong.MinValue, ulong.MaxValue,
777 _ => Task.FromResult<double?>(ui64),
778 async (_, Value) =>
779 {
780 ui64 = (ulong)Value;
781 await this.DoCallback<double>(CallbackUrl, PayloadScript, ui64);
782 }));
783 }
784 }
785
786 return Task.FromResult(Parameters.ToArray());
787 }
788
789 private async Task DoCallback<T>(string CallbackUrl, string PayloadScript, T Value)
790 {
791 Variables v = new Variables
792 {
793 { "Value", Value }
794 };
795
796 object Payload = await Expression.EvalAsync(PayloadScript, v);
797 await InternetContent.PostAsync(new Uri(CallbackUrl), Payload);
798 }
799
803 public override Task<IEnumerable<ICommand>> Commands => this.GetCommands();
804
805 private async Task<IEnumerable<ICommand>> GetCommands()
806 {
807 List<ICommand> Commands = new List<ICommand>();
808 Commands.AddRange(await base.Commands);
809
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));
818
819 return Commands.ToArray();
820 }
821
822 }
823}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:13
static bool TryParse(string s, out double Value)
Tries to decode a string encoded double.
Definition: CommonTypes.cs:46
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.
Definition: XML.cs:19
static bool TryParse(string s, out DateTime Value)
Tries to decode a string encoded DateTime.
Definition: XML.cs:744
Static class managing the application event log. Applications and services log events on this static ...
Definition: Log.cs:13
static Exception UnnestException(Exception Exception)
Unnests an exception, to extract the relevant inner exception.
Definition: Log.cs:818
Base class for form fields
Definition: Field.cs:16
string Var
Variable name
Definition: Field.cs:81
string ValueString
Value as a single string. If field contains multiple values, they will be concatenated into a single ...
Definition: Field.cs:101
string[] ValueStrings
Values for the field (string representations).
Definition: Field.cs:96
Field(DataForm Form, string Var, string Label, bool Required, string[] ValueStrings, KeyValuePair< string, string >[] Options, string Description, DataType DataType, ValidationMethod ValidationMethod, string Error, bool PostBack, bool ReadOnly, bool NotSame)
Base class for form fields
Definition: Field.cs:51
Current state of a property form being built.
Dictionary< string, Page > PageByLabel
Pages by page label.
Class managing a page in a data form layout.
Definition: Page.cs:11
Static interface for database persistence. In order to work, a database provider has to be assigned t...
Definition: Database.cs:19
static async Task Update(object Object)
Updates an object in the database.
Definition: Database.cs:626
Static class that dynamically manages types and interfaces available in the runtime environment.
Definition: Types.cs:14
static bool TryGetModuleParameter(string Name, out object Value)
Tries to get a module parameter value.
Definition: Types.cs:583
Contains information about a language.
Definition: Language.cs:17
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 ...
Definition: Language.cs:209
async Task< Namespace > GetNamespaceAsync(string Name)
Gets the namespace object, given its name, if available.
Definition: Language.cs:99
Contains information about a namespace in a language.
Definition: Namespace.cs:17
Task< LanguageString > GetStringAsync(int Id)
Gets the string object, given its ID, if available.
Definition: Namespace.cs:65
Basic access point for runtime language localization.
Definition: Translator.cs:16
static async Task< Language > GetLanguageAsync(string Code)
Gets the languge object, given its language code, if available.
Definition: Translator.cs:42
Class that can be used to schedule events in time. It uses a timer to execute tasks at the appointed ...
Definition: Scheduler.cs:26
bool Remove(DateTime When)
Removes an event scheduled for a given point in time.
Definition: Scheduler.cs:182
DateTime Add(DateTime When, ScheduledEventCallback Callback, object State)
Adds an event.
Definition: Scheduler.cs:66
Class managing a script expression.
Definition: Expression.cs:39
static Task< object > EvalAsync(string Script)
Evaluates script, in string format.
Definition: Expression.cs:5488
Collection of variables.
Definition: Variables.cs:25
string Name
If the node is provisioned is not. Property is editable.
void NewMomentaryValues(params Field[] Values)
Reports newly measured values.
Class for the root node of the Metering topology.
Definition: Root.cs:11
Base class for all provisioned metering nodes.
Tokens available in request.
Definition: RequestOrigin.cs:9
Class representing a meta-data value.
Virtual node, that can be used as a placeholder for services.
Definition: VirtualNode.cs:28
void ReportSensorData(SensorData.Field Field)
Reports sensor data on the node.
Definition: VirtualNode.cs:480
object GetMetaData(string Name)
Gets a meta-data value, if available.
Definition: VirtualNode.cs:395
virtual Task StartReadout(ISensorReadout Request, bool DoneAfter)
Starts the readout of the sensor.
Definition: VirtualNode.cs:568
override async Task< IEnumerable< Parameter > > GetDisplayableParametersAsync(Language Language, RequestOrigin Caller)
Gets displayable parameters.
Definition: VirtualNode.cs:440
override async Task AnnotatePropertyForm(FormState Form)
Annotates the property form.
Definition: VirtualNode.cs:83
VirtualNode()
Virtual node, that can be used as a placeholder for services.
Definition: VirtualNode.cs:39
Task StartReadout(ISensorReadout Request)
Starts the readout of the sensor.
Definition: VirtualNode.cs:543
virtual Task< ControlParameter[]> GetControlParameters()
Get control parameters for the actuator.
Definition: VirtualNode.cs:625
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...
Definition: VirtualNode.cs:74
override bool IsControllable
If the node can be controlled.
Definition: VirtualNode.cs:591
override Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
Definition: VirtualNode.cs:54
override bool IsReadable
If the node can be read.
Definition: VirtualNode.cs:552
override Task< IEnumerable< ICommand > > Commands
Available command objects. If no commands are available, null is returned.
Definition: VirtualNode.cs:803
void ReportSensorData(params SensorData.Field[] Fields)
Reports sensor data on the node.
Definition: VirtualNode.cs:489
Task ValidateCustomProperty(Field Field)
Performs custom validation of a property.
Definition: VirtualNode.cs:231
MetaDataValue[] MetaData
Meta-data attached to virtual node.
Definition: VirtualNode.cs:47
Task SetCustomProperty(Field Field)
Sets the custom parameter to the value(s) provided in the field.
Definition: VirtualNode.cs:312
bool TryGetMetaDataValue(string Name, out object Value)
Tries to get a meta-data value
Definition: VirtualNode.cs:195
async Task SetMetaData(string Name, object Value)
Sets a meta-data value.
Definition: VirtualNode.cs:408
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 ...
Definition: VirtualNode.cs:64
Interface for objects that want to handle custom properties in property forms.
Interface for actuator nodes.
Definition: IActuator.cs:10
Interface for nodes that are published through the concentrator interface.
Definition: INode.cs:49
INode Parent
Parent Node, or null if a root node.
Definition: INode.cs:116
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.
Definition: ISensor.cs:9
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....
Definition: Duration.cs:13