Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
SensorDataReadoutTaskNode.cs
1using System;
3using System.ComponentModel;
4using System.Text;
5using System.Threading;
6using System.Threading.Tasks;
7using Waher.Content;
15using Waher.Script;
17using Waher.Things;
22
24{
29 {
30 private const string TotalNodeCount = " TotalNodeCount ";
31 private const string NodeCount = " NodeCount ";
32
37 {
38 }
39
43 [Header(2, "Parallel readouts:", 10)]
44 [Page(66, "Job", 0)]
45 [ToolTip(3, "Maximum number of parallel readouts.")]
46 [Required]
47 [Range(1, 100)]
48 [DefaultValue(1)]
49 public int ParallelReadouts { get; set; } = 1;
50
54 [Header(68, "Timeout (s):", 20)]
55 [Page(66, "Job", 0)]
56 [ToolTip(69, "If a sensor does not respond within this time, the readout will be cancelled.")]
57 [Required]
58 [Range(1, 300)]
59 [DefaultValue(60)]
60 public int SensorTimeoutSeconds { get; set; } = 60;
61
65 [Header(4, "Momentary values.", 30)]
66 [Page(66, "Job", 0)]
67 [ToolTip(5, "Check, if momentary values should be read.")]
68 [DefaultValue(true)]
69 public bool Momentary { get; set; } = true;
70
74 [Header(6, "Identity values.", 40)]
75 [Page(66, "Job", 0)]
76 [ToolTip(7, "Check, if identity values should be read.")]
77 [DefaultValue(false)]
78 public bool Identity { get; set; } = false;
79
83 [Header(8, "Status values.", 50)]
84 [Page(66, "Job", 0)]
85 [ToolTip(9, "Check, if status values should be read.")]
86 [DefaultValue(false)]
87 public bool Status { get; set; } = false;
88
92 [Header(10, "Computed values.", 60)]
93 [Page(66, "Job", 0)]
94 [ToolTip(11, "Check, if computed values should be read.")]
95 [DefaultValue(false)]
96 public bool Computed { get; set; } = false;
97
101 [Header(12, "Peak values.", 70)]
102 [Page(66, "Job", 0)]
103 [ToolTip(13, "Check, if peak values should be read.")]
104 [DefaultValue(false)]
105 public bool Peak { get; set; } = false;
106
110 [Header(14, "Historical values.", 80)]
111 [Page(66, "Job", 0)]
112 [ToolTip(15, "Check, if historical values should be read.")]
113 [DefaultValue(false)]
114 public bool Historical { get; set; } = false;
115
120 {
121 get
122 {
123 FieldType Result = 0;
124
125 if (this.Momentary)
126 Result |= FieldType.Momentary;
127
128 if (this.Identity)
129 Result |= FieldType.Identity;
130
131 if (this.Status)
132 Result |= FieldType.Status;
133
134 if (this.Computed)
135 Result |= FieldType.Computed;
136
137 if (this.Peak)
138 Result |= FieldType.Peak;
139
140 if (this.Historical)
141 Result |= FieldType.Historical;
142
143 return Result;
144 }
145 }
146
150 [Header(16, "Field names to read:", 90)]
151 [Page(66, "Job", 0)]
152 [ToolTip(17, "Leave blank to read all fields.")]
153 [ContentType("text/plain")]
154 public string[] FieldNames { get; set; }
155
159 [Header(18, "From:", 100)]
160 [Page(66, "Job", 0)]
161 [ToolTip(19, "Read historical data from this point in time.")]
162 public Duration From { get; set; } = Duration.Zero;
163
167 [Header(20, "To:", 110)]
168 [Page(66, "Job", 0)]
169 [ToolTip(21, "Read historical data to this point in time.")]
170 public Duration To { get; set; } = Duration.Zero;
171
177 public override Task<string> GetTypeNameAsync(Language Language)
178 {
179 return Language.GetStringAsync(typeof(SensorDataReadoutTaskNode), 22, "Sensor Data Readout Task");
180 }
181
187 public override Task<bool> AcceptsChildAsync(INode Child)
188 {
189 return Task.FromResult(
190 Child is MeteringNodeReference ||
191 Child is GroupReference ||
192 Child is ProcessorReference ||
193 Child is OutputReference);
194 }
195
200 public override async Task ExecuteTask(JobExecutionStatus Status)
201 {
202 try
203 {
204 await this.ReportStart(Status);
205
206 if (Status.ReportDetail != JobReportDetail.None)
207 await Status.Query.BeginSection(await this.GetString(Status, 57, "Overview"));
208
209 ISensor[] Sensors = await this.FindNodes<ISensor>();
210 if (Sensors is null || Sensors.Length == 0)
211 {
212 await this.ReportMessage(Status, 33, "No readable sensors found to read.");
213 await this.ReportDone(Status);
214 return;
215 }
216
217 ChunkedList<ISensor> ReadableSensors = new ChunkedList<ISensor>();
218
219 foreach (ISensor Sensor in Sensors)
220 {
221 if (Sensor.IsReadable)
222 ReadableSensors.Add(Sensor);
223 }
224
225 Sensors = ReadableSensors.ToArray();
226 if (Sensors.Length == 0)
227 {
228 await this.ReportMessage(Status, 33, "No readable sensors found to read.");
229 await this.ReportDone(Status);
230 return;
231 }
232
233 Status.Variables[TotalNodeCount] = Sensors.Length;
234 Status.Variables[NodeCount] = 0.0;
235
236 if (Sensors.Length == 1)
237 await this.ReportMessage(Status, 52, "**1** readable sensor found to read.");
238 else
239 await this.ReportMessage(Status, 34, "**%0%** readable sensors found to read.", Sensors.Length);
240
241 ISensorDataProcessor[] SensorDataProcessors = await this.FindNodes<ISensorDataProcessor>();
242
243 if (SensorDataProcessors.Length == 1)
244 await this.ReportMessage(Status, 53, "**1** sensor data processor will be used.");
245 else
246 await this.ReportMessage(Status, 35, "**%0%** sensor data processors will be used.", SensorDataProcessors.Length);
247
248 IThingErrorProcessor[] ErrorProcessors = await this.FindNodes<IThingErrorProcessor>();
249
250 if (ErrorProcessors.Length == 1)
251 await this.ReportMessage(Status, 70, "**1** thing error processor will be used.");
252 else
253 await this.ReportMessage(Status, 71, "**%0%** thing error processors will be used.", SensorDataProcessors.Length);
254
255 ISensorDataOutput[] Outputs = await this.FindNodes<ISensorDataOutput>();
256
257 if (Outputs.Length == 1)
258 await this.ReportMessage(Status, 54, "Sensor Data will be output to **1** output.");
259 else
260 await this.ReportMessage(Status, 36, "Sensor Data will be output to **%0%** outputs.", Outputs.Length);
261
262 if (Status.ReportDetail != JobReportDetail.None)
263 {
264 await Status.Query.EndSection();
265 await Status.Query.BeginSection(await this.GetString(Status, 58, "Readout"));
266 await this.ReportStatus(Status, 37, "Starting readout.");
267 }
268
269 if (Status.ReportDetail == JobReportDetail.Summary)
270 {
271 await Status.Query.NewTable("Summary",
272 await Status.Language.GetStringAsync(typeof(SensorDataReadoutTaskNode), 38, "Sensor Data Readout Summary"),
273 new Column("NodeId", await this.GetString(Status, 39, "Node ID"),
274 MeteringTopology.SourceID, null, null, null, ColumnAlignment.Left, null),
275 new Column("NrFields", await this.GetString(Status, 40, "#Fields"),
276 null, null, null, null, ColumnAlignment.Right, 0),
277 new Column("NrErrors", await this.GetString(Status, 41, "#Errors"),
278 null, null, null, null, ColumnAlignment.Right, 0));
279 }
280
281 using AsyncProcessor<ReadoutWorkItem> Processor = new AsyncProcessor<ReadoutWorkItem>(this.ParallelReadouts, "Job Task: " + this.NodeId);
282
283 foreach (ISensor Sensor in Sensors)
284 Processor.Queue(new ReadoutWorkItem(Sensor, this, Status,
285 SensorDataProcessors, ErrorProcessors, Outputs));
286
287 await Processor.WaitUntilIdle();
288
289 if (Status.ReportDetail == JobReportDetail.Summary)
290 await Status.Query.TableDone("Summary");
291
292 if (Status.ReportDetail != JobReportDetail.None)
293 {
294 await Status.Query.EndSection();
295 await this.ReportStatus(Status, 55, "Readout completed.");
296 }
297
298 if (Status.Variables.TryGetVariable("Errors", out Variable v) &&
299 v.ValueObject is ChunkedList<ThingError> JobErrors &&
300 JobErrors.Count > 0)
301 {
302 await Status.Job.LogErrorAsync("ReadoutErrors", JobErrors.Count.ToString() + " errors reported during readout.");
303 }
304 else
305 await Status.Job.RemoveErrorAsync("ReadoutErrors");
306 }
307 catch (Exception ex)
308 {
309 if (Status.ReportDetail != JobReportDetail.None)
310 await Status.Query.LogMessage(ex);
311
312 await Status.Job.LogErrorAsync("ReadoutErrors", ex.Message);
313 }
314 finally
315 {
316 await this.ReportDone(Status);
317 }
318 }
319
320 private async Task ReportStart(JobExecutionStatus Status)
321 {
322 if (Status.ReportDetail != JobReportDetail.None)
323 {
324 await Status.Query.Start();
325 await this.ReportTitle(Status, this.NodeId);
326 await this.ReportStatus(Status, 32, "Starting sensor data readout job task.");
327 }
328 }
329
330 private async Task ReportDone(JobExecutionStatus Status)
331 {
332 if (Status.ReportDetail != JobReportDetail.None)
333 await Status.Query.Done();
334 }
335
336 private async Task ReportTitle(JobExecutionStatus Status, string Title)
337 {
338 if (Status.ReportDetail != JobReportDetail.None)
339 await Status.Query.SetTitle(Title);
340 }
341
342 private Task ReportMessage(JobExecutionStatus Status, int StringId,
343 string Message)
344 {
345 return this.ReportMessage(Status, StringId, Message, (string[])null);
346 }
347
348 private Task ReportMessage(JobExecutionStatus Status, int StringId,
349 string Message, params object[] Parameters)
350 {
351 return this.ReportMessage(Status, StringId, Message, ToString(Parameters));
352 }
353
354 private async Task ReportMessage(JobExecutionStatus Status, int StringId,
355 string Message, params string[] Parameters)
356 {
357 if (Status.ReportDetail != JobReportDetail.None)
358 {
359 await Status.Query.NewObject(new MarkdownContent(
360 await this.GetString(Status, StringId, Message, Parameters)));
361 }
362 }
363
364 private Task ReportStatus(JobExecutionStatus Status, int StringId,
365 string Message)
366 {
367 return this.ReportStatus(Status, StringId, Message, (string[])null);
368 }
369
370 private Task ReportStatus(JobExecutionStatus Status, int StringId,
371 string Message, params object[] Parameters)
372 {
373 return this.ReportStatus(Status, StringId, Message, ToString(Parameters));
374 }
375
376 private async Task ReportStatus(JobExecutionStatus Status, int StringId,
377 string Message, params string[] Parameters)
378 {
379 if (Status.ReportDetail != JobReportDetail.None)
380 await Status.Query.SetStatus(await this.GetString(Status, StringId, Message, Parameters));
381 }
382
383 private Task<string> GetString(JobExecutionStatus Status, int StringId, string Message)
384 {
385 return this.GetString(Status, StringId, Message, (string[])null);
386 }
387
388 private static string[] ToString(object[] Parameters)
389 {
390 if (Parameters is null)
391 return null;
392
393 int i, c = Parameters.Length;
394 string[] Result = new string[c];
395
396 for (i = 0; i < c; i++)
397 Result[i] = Parameters[i]?.ToString();
398
399 return Result;
400 }
401
402 private async Task<string> GetString(JobExecutionStatus Status, int StringId, string Message,
403 params string[] Parameters)
404 {
405 Message = await Status.Language.GetStringAsync(typeof(SensorDataReadoutTaskNode), StringId, Message);
406
407 if (!(Parameters is null))
408 {
409 int i, c = Parameters.Length;
410
411 for (i = 0; i < c; i++)
412 Message = Message.Replace("%" + i.ToString() + "%", Parameters[i]);
413 }
414
415 return Message;
416 }
417
418 private async Task SensorReadoutCompleted(ISensor Sensor, Field[] Fields,
420 ISensorDataProcessor[] SensorDataProcessors, IThingErrorProcessor[] ErrorProcessors,
421 ISensorDataOutput[] Outputs)
422 {
423 if (!(Fields is null))
424 {
425 if ((SensorDataProcessors?.Length ?? 0) > 0)
426 {
427 foreach (ISensorDataProcessor Processor in SensorDataProcessors)
428 {
429 try
430 {
431 Fields = await Processor.ProcessFields(Sensor, Fields);
432 if ((Fields?.Length ?? 0) == 0)
433 break;
434 }
435 catch (Exception ex)
436 {
437 await Processor.LogErrorAsync("ProcessingError", ex.Message);
438 }
439 }
440 }
441
442 if ((Outputs?.Length ?? 0) > 0 && (Fields?.Length ?? 0) > 0)
443 {
444 foreach (ISensorDataOutput Output in Outputs)
445 {
446 try
447 {
448 await Output.OutputFields(Sensor, Fields);
449 }
450 catch (Exception ex)
451 {
452 await Output.LogErrorAsync("OutputError", ex.Message);
453 }
454 }
455 }
456 }
457
458 if ((Errors?.Length ?? 0) > 0)
459 {
460 if ((ErrorProcessors?.Length ?? 0) > 0)
461 {
462 foreach (IThingErrorProcessor Processor in ErrorProcessors)
463 {
464 try
465 {
466 Errors = await Processor.ProcessErrors(Sensor, Errors);
467 if ((Errors?.Length ?? 0) == 0)
468 break;
469 }
470 catch (Exception ex)
471 {
472 await Processor.LogErrorAsync("ProcessingError", ex.Message);
473 }
474 }
475 }
476
477 if ((Errors?.Length ?? 0) > 0)
478 {
479 if (!Status.Variables.TryGetVariable("Errors", out Variable v))
480 Status.Variables["Errors"] = new ChunkedList<ThingError>(Errors);
481 else if (v.ValueObject is ChunkedList<ThingError> JobErrors)
482 JobErrors.AddRange(Errors);
483 }
484 }
485
486 await Status.Lock();
487 try
488 {
489 switch (Status.ReportDetail)
490 {
491 case JobReportDetail.Summary:
492 await Status.Query.NewRecords("Summary", new Record(
493 Sensor.NodeId, Fields?.Length ?? 0, Errors?.Length ?? 0));
494 break;
495
496 case JobReportDetail.Details:
497 await Status.Query.BeginSection(Sensor.NodeId);
498
499 if ((Fields?.Length ?? 0) > 0)
500 {
501 string TableId = "Fields: " + Sensor.NodeId;
502 await Status.Query.NewTable(TableId,
503 await this.GetString(Status, 50, "Reported Sensor Data"),
504 new Column("Timestamp", await this.GetString(Status, 44, "Timestamp"),
505 null, null, null, null, ColumnAlignment.Left, null),
506 new Column("FieldName", await this.GetString(Status, 45, "Field Name"),
507 null, null, null, null, ColumnAlignment.Left, null),
508 new Column("FieldType", await this.GetString(Status, 46, "Field Type"),
509 null, null, null, null, ColumnAlignment.Left, null),
510 new Column("Value", await this.GetString(Status, 47, "Value"),
511 null, null, null, null, ColumnAlignment.Right, null),
512 new Column("QoS", await this.GetString(Status, 48, "QoS"),
513 null, null, null, null, ColumnAlignment.Left, null));
514
516 int i = 0;
517
518 foreach (Field Field in Fields)
519 {
520 Records.Add(new Record(Field.Timestamp, Field.Name,
522
523 if (++i == 100)
524 {
525 await Status.Query.NewRecords(TableId, Records.ToArray());
526 Records.Clear();
527 i = 0;
528 }
529 }
530
531 if (i > 0)
532 await Status.Query.NewRecords(TableId, Records.ToArray());
533
534 await Status.Query.TableDone(TableId);
535 }
536 else
537 await this.ReportMessage(Status, 42, "No sensor data reported.");
538
539 if ((Errors?.Length ?? 0) > 0)
540 {
541 string TableId = "Errors: " + Sensor.NodeId;
542 await Status.Query.NewTable(TableId,
543 await this.GetString(Status, 51, "Reported Errors"),
544 new Column("Timestamp", await this.GetString(Status, 44, "Timestamp"),
545 null, null, null, null, ColumnAlignment.Left, null),
546 new Column("Error", await this.GetString(Status, 49, "Error Message"),
547 null, null, null, null, ColumnAlignment.Left, null));
548
550 int i = 0;
551
552 foreach (ThingError Error in Errors)
553 {
554 Records.Add(new Record(Error.Timestamp, Error.ErrorMessage));
555
556 if (++i == 100)
557 {
558 await Status.Query.NewRecords(TableId, Records.ToArray());
559 Records.Clear();
560 i = 0;
561 }
562 }
563
564 if (i > 0)
565 await Status.Query.NewRecords(TableId, Records.ToArray());
566
567 await Status.Query.TableDone(TableId);
568 }
569 else
570 await this.ReportMessage(Status, 43, "No errors reported.");
571
572 await Status.Query.EndSection();
573 break;
574 }
575
576 if (Status.Variables.TryGetVariable(TotalNodeCount, out Variable v) &&
577 v.ValueObject is double TotalNrNodes &&
578 Status.Variables.TryGetVariable(NodeCount, out v) &&
579 v.ValueObject is double NrNodes)
580 {
581 NrNodes++;
582 Status.Variables[NodeCount] = NrNodes;
583
584 await this.ReportStatus(Status, 56, "%0% of %1% nodes processed.",
585 (int)NrNodes, (int)TotalNrNodes);
586 }
587 }
588 finally
589 {
590 Status.Unlock();
591 }
592 }
593
594 private class ReadoutWorkItem : WorkItem
595 {
596 private readonly ISensor sensor;
597 private readonly SensorDataReadoutTaskNode task;
598 private readonly JobExecutionStatus status;
599 private readonly ISensorDataProcessor[] sensorDataProcessors;
600 private readonly IThingErrorProcessor[] errorProcessors;
601 private readonly ISensorDataOutput[] outputs;
602 private ChunkedList<Field> fields = null;
603 private ChunkedList<ThingError> errors = null;
604
605 public ReadoutWorkItem(ISensor Sensor, SensorDataReadoutTaskNode TaskNode,
606 JobExecutionStatus Status, ISensorDataProcessor[] SensorDataProcessors,
607 IThingErrorProcessor[] ErrorProcessors, ISensorDataOutput[] Outputs)
608 {
609 this.sensor = Sensor;
610 this.task = TaskNode;
611 this.status = Status;
612 this.sensorDataProcessors = SensorDataProcessors;
613 this.errorProcessors = ErrorProcessors;
614 this.outputs = Outputs;
615 }
616
617 public override async Task Execute(CancellationToken Cancel)
618 {
619 TaskCompletionSource<bool> Completed = new TaskCompletionSource<bool>();
620 JobReadout Readout = new JobReadout(this, Completed);
621 try
622 {
623 await this.sensor.StartReadout(Readout);
624
625 _ = Task.Delay(this.task.SensorTimeoutSeconds * 1000).ContinueWith(
626 (_) => Completed.TrySetResult(false));
627
628 if (!await Completed.Task)
629 await Readout.ReportErrors(true, new ThingError(this.sensor, "Sensor did not respond."));
630 }
631 catch (Exception ex)
632 {
633 await Readout.ReportErrors(true, new ThingError(this.sensor, ex.Message));
634 }
635
636 if (this.sensor is MeteringNode MeteringNode)
637 {
638 if (this.errors is null)
639 await MeteringNode.RemoveErrorAsync("ReadoutErrors");
640 else
641 {
642 StringBuilder sb = new StringBuilder();
643 bool First = true;
644
645 foreach (ThingError Error in this.errors)
646 {
647 if (First)
648 First = false;
649 else
650 sb.AppendLine();
651
652 sb.Append(Error.ErrorMessage);
653 }
654
655 await MeteringNode.LogErrorAsync("ReadoutErrors", sb.ToString());
656 }
657 }
658
659 await this.task.SensorReadoutCompleted(this.sensor, this.fields?.ToArray(),
660 this.errors?.ToArray(), this.status, this.sensorDataProcessors,
661 this.errorProcessors, this.outputs);
662 }
663
664 private class JobReadout : ISensorReadout
665 {
666 private readonly TaskCompletionSource<bool> completed;
667 private readonly ReadoutWorkItem item;
668 private readonly DateTime from;
669 private readonly DateTime to;
670
671 public JobReadout(ReadoutWorkItem Item, TaskCompletionSource<bool> Completed)
672 {
673 this.item = Item;
674 this.from = Item.status.StartTime - this.item.task.From;
675 this.to = Item.status.StartTime - this.item.task.To;
676 this.completed = Completed;
677 }
678
679 public IThingReference[] Nodes => new IThingReference[] { this.item.sensor };
680 public FieldType Types => this.item.task.FieldTypes;
681 public string[] FieldNames => this.item.task.FieldNames;
682 public DateTime From => this.from;
683 public DateTime To => this.to;
684 public DateTime When => this.item.status.StartTime;
685 public string Actor => this.item.task.NodeId;
686 public string ServiceToken => string.Empty;
687 public string DeviceToken => string.Empty;
688 public string UserToken => string.Empty;
689
690 public bool IsIncluded(string FieldName)
691 {
692 if ((this.item.task.FieldNames?.Length ?? 0) == 0)
693 return true;
694 else
695 return Array.IndexOf(this.item.task.FieldNames, FieldName) >= 0;
696 }
697
698 public bool IsIncluded(DateTime Timestamp)
699 {
700 return Timestamp.ToUniversalTime() >= this.from && Timestamp <= this.to;
701 }
702
703 public bool IsIncluded(FieldType Type)
704 {
705 return (this.item.task.FieldTypes & Type) != 0;
706 }
707
708 public bool IsIncluded(string FieldName, FieldType Type)
709 {
710 return this.IsIncluded(FieldName) && this.IsIncluded(Type);
711 }
712
713 public bool IsIncluded(string FieldName, DateTime Timestamp, FieldType Type)
714 {
715 return this.IsIncluded(FieldName) && this.IsIncluded(Type) && this.IsIncluded(Timestamp);
716 }
717
718 public Task ReportErrors(bool Done, params ThingError[] Errors)
719 {
720 this.item.errors ??= new ChunkedList<ThingError>();
721 this.item.errors.AddRange(Errors);
722
723 if (Done)
724 this.completed.TrySetResult(true);
725
726 return Task.CompletedTask;
727 }
728
729 public Task ReportErrors(bool Done, IEnumerable<ThingError> Errors)
730 {
731 this.item.errors ??= new ChunkedList<ThingError>();
732 this.item.errors.AddRange(Errors);
733
734 if (Done)
735 this.completed.TrySetResult(true);
736
737 return Task.CompletedTask;
738 }
739
740 public Task ReportFields(bool Done, params Field[] Fields)
741 {
742 this.item.fields ??= new ChunkedList<Field>();
743 this.item.fields.AddRange(Fields);
744
745 if (Done)
746 this.completed.TrySetResult(true);
747
748 return Task.CompletedTask;
749 }
750
751 public Task ReportFields(bool Done, IEnumerable<Field> Fields)
752 {
753 this.item.fields ??= new ChunkedList<Field>();
754 this.item.fields.AddRange(Fields);
755
756 if (Done)
757 this.completed.TrySetResult(true);
758
759 return Task.CompletedTask;
760 }
761
762 public Task Start()
763 {
764 return Task.CompletedTask;
765 }
766 }
767 }
768
769 }
770}
Class that can be used to encapsulate Markdown to be returned from a Web Service, bypassing any encod...
Contains information about the execution of a job.
override string ToString()
Definition: JobNode.cs:168
string NodeId
ID of node.
Definition: JobNode.cs:143
A reference to a metering group.
override Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
override 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 ...
int SensorTimeoutSeconds
Maximum number of parallel readouts.
override async Task ExecuteTask(JobExecutionStatus Status)
Executes the task.
Abstract bast class for job tasks.
Definition: JobTaskNode.cs:13
A chunked list is a linked list of chunks of objects of type T .
Definition: ChunkedList.cs:54
void Clear()
Clears the collection.
Definition: ChunkedList.cs:306
int Count
Number of elements in collection.
Definition: ChunkedList.cs:68
void Add(T Item)
Adds an item to the collection.
Definition: ChunkedList.cs:272
T[] ToArray()
Returns an array containing all elements of the collection.
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
Processes work tasks, in an asynchronous manner.
Represents an asynchronous operation to be performed.
Definition: WorkItem.cs:10
Task Execute()
Executes the operation.
Definition: WorkItem.cs:16
Throws an exception.
Definition: Error.cs:11
Extract the fields of a type or an object.
Definition: Fields.cs:17
Makes sure an expression is defined. Otherwise, an exception is thrown.
Definition: Required.cs:13
int Length
Length of expression covered by node.
Definition: ScriptNode.cs:101
Contains information about a variable.
Definition: Variable.cs:10
Base class for all metering nodes.
Definition: MeteringNode.cs:30
virtual Task LogErrorAsync(string Body)
Logs an error message on the node.
virtual Task< bool > RemoveErrorAsync()
Removes error messages with an empty event ID from the node.
Defines the Metering Topology data source. This data source contains a tree structure of persistent r...
const string SourceID
Source ID for the metering topology data source.
Defines a column in a table.
Definition: Column.cs:30
Defines a record in a table.
Definition: Record.cs:9
Base class for all sensor data fields.
Definition: Field.cs:20
FieldQoS QoS
Field Quality of Service flags.
Definition: Field.cs:269
FieldType Type
Field Type flags.
Definition: Field.cs:259
abstract object ObjectValue
Field value, boxed as an object reference.
Definition: Field.cs:416
string Name
Unlocalized field name.
Definition: Field.cs:279
DateTime Timestamp
Timestamp of field value.
Definition: Field.cs:202
Contains information about an error on a thing
Definition: ThingError.cs:10
Task LogErrorAsync(string Body)
Logs an error message on the node.
Base Interface for all sensor-data output nodes.
Task OutputFields(ISensor Sensor, Field[] Fields)
Outputs a collection of sensor data fields.
Task LogErrorAsync(string Body)
Logs an error message on the node.
Base Interface for all sensor-data processor nodes.
Task< Field[]> ProcessFields(ISensor Sensor, Field[] Fields)
Process a collection of sensor data fields.
Base Interface for all thing error processor nodes.
Task< ThingError[]> ProcessErrors(INode Device, ThingError[] Errors)
Process a collection of thing errors.
Interface for nodes that are published through the concentrator interface.
Definition: INode.cs:49
bool IsReadable
If the node can be read.
Definition: INode.cs:92
Interface for sensor nodes.
Definition: ISensor.cs:9
Interface for classes managing sensor data readouts.
Interface for thing references.
Definition: ImplTypes.g.cs:58
JobReportDetail
How much detail to include in job reports.
ColumnAlignment
Column alignment.
Definition: Column.cs:9
FieldType
Field Type flags
Definition: FieldType.cs:10
Represents a duration value, as defined by the xsd:duration data type: http://www....
Definition: Duration.cs:14
static readonly Duration Zero
Zero value
Definition: Duration.cs:577