Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
ReadSensor.cs
1using System;
2using System.Collections.Generic;
3using System.IO;
4using System.Text;
5using System.Threading.Tasks;
6using System.Xml;
10using Waher.Script;
13using Waher.Things;
15
17{
22 {
26 Array,
27
31 Object
32 }
33
38 {
39 private ThingReference[] nodeReferences;
40 private string[] fields;
41 private Waher.Things.SensorData.FieldType fieldTypes;
42 private StringAttribute actor;
43 private StringAttribute to;
44 private string responseVariable;
45 private SensorDataResponseType responseType;
46
53 : base(Parent, Model)
54 {
55 }
56
60 public override string LocalName => nameof(ReadSensor);
61
69 {
70 return new ReadSensor(Parent, Model);
71 }
72
77 public override async Task FromXml(XmlElement Definition)
78 {
79 this.actor = new StringAttribute(XML.Attribute(Definition, "actor"));
80 this.to = new StringAttribute(XML.Attribute(Definition, "to"));
81 this.responseVariable = XML.Attribute(Definition, "responseVariable");
82 this.responseType = (SensorDataResponseType)XML.Attribute(Definition, "responseType", SensorDataResponseType.Object);
83 this.fieldTypes = 0;
84
85 await base.FromXml(Definition);
86
87 List<ThingReference> Nodes = null;
88 List<string> Fields = null;
89
90 foreach (ISimulationNode Node in this.Children)
91 {
92 if (Node is NodeReference NodeRef)
93 {
94 if (Nodes is null)
95 Nodes = new List<ThingReference>();
96
97 Nodes.Add(NodeRef.ThingReference);
98 }
99 else if (Node is FieldReference FieldRef)
100 {
101 if (Fields is null)
102 Fields = new List<string>();
103
104 Fields.Add(FieldRef.Name);
105 }
106 else if (Node is FieldType FieldType)
107 this.fieldTypes |= FieldType.Type;
108 }
109
110 this.nodeReferences = Nodes?.ToArray();
111 this.fields = Fields?.ToArray();
112 }
113
119 public override async Task<LinkedListNode<IActivityNode>> Execute(Variables Variables)
120 {
121 string To = await this.to.GetValueAsync(Variables);
122
123 if (!(await this.GetActorObjectAsync(this.actor, Variables) is SensorClient SensorClient))
124 throw new Exception("Actor not an XMPP Sensor Client.");
125
126 if (XmppClient.BareJidRegEx.IsMatch(To))
127 {
129 ?? throw new Exception("No connection in roster with Bare JID: " + To);
130
131 if (!Item.HasLastPresence || !Item.LastPresence.IsOnline)
132 throw new Exception("Contact not online: " + To);
133
134 To = Item.LastPresenceFullJid;
135 }
136
137 TaskCompletionSource<bool> T = new TaskCompletionSource<bool>();
138 Dictionary<string, Field> FieldsAsObject = this.responseType == SensorDataResponseType.Object ? new Dictionary<string, Field>() : null;
139 List<Field> FieldsAsArray = this.responseType == SensorDataResponseType.Array ? new List<Field>() : null;
140 List<ThingError> Errors = new List<ThingError>();
141 SensorDataClientRequest Request = await SensorClient.RequestReadout(To, this.nodeReferences, this.fields, this.fieldTypes);
142
143 Request.OnErrorsReceived += (Sender, NewErrors) =>
144 {
145 lock (Errors)
146 {
147 Errors.AddRange(NewErrors);
148 }
149
150 return Task.CompletedTask;
151 };
152
153 Request.OnFieldsReceived += (Sender, NewFields) =>
154 {
155 if (this.responseType == SensorDataResponseType.Object)
156 {
157 lock (FieldsAsObject)
158 {
159 foreach (Field F in NewFields)
160 FieldsAsObject[F.Name] = F;
161 }
162 }
163 else
164 {
165 lock (FieldsAsArray)
166 {
167 FieldsAsArray.AddRange(NewFields);
168 }
169 }
170
171 return Task.CompletedTask;
172 };
173
174 Request.OnStateChanged += (Sender, NewState) =>
175 {
176 switch (NewState)
177 {
178 case SensorDataReadoutState.Done:
179 T.TrySetResult(true);
180 break;
181
182 case SensorDataReadoutState.Failure:
183 case SensorDataReadoutState.Cancelled:
184 T.TrySetResult(false);
185 break;
186 }
187
188 return Task.CompletedTask;
189 };
190
191 if (!await T.Task)
192 {
193 StringBuilder sb = new StringBuilder();
194
195 sb.AppendLine("Sensor Data readout failed. Errors reported: ");
196 sb.AppendLine();
197
198 foreach (ThingError Error in Errors)
199 sb.AppendLine(Error.ErrorMessage); // TODO: Node reference, if available.
200
201 throw new Exception(sb.ToString());
202 }
203
204 Variables[this.responseVariable] = (object)FieldsAsObject ?? FieldsAsArray.ToArray();
205
206 return null;
207 }
208
215 public override void ExportPlantUml(StreamWriter Output, int Indentation, char QuoteChar)
216 {
217 base.ExportPlantUml(Output, Indentation, QuoteChar);
218
219 Indent(Output, Indentation);
220 Output.Write(':');
221 Output.Write(this.actor.Value);
222 Output.Write(".ReadSensorData");
223 Output.Write("(");
224
225 Indentation++;
226
227 XMPP.Activities.SendMessage.AppendArgument(Output, Indentation, "To", this.to.Value, true, QuoteChar);
228
229 Output.WriteLine(");");
230 }
231
232 }
233}
Root node of a simulation model
Definition: Model.cs:49
async Task< object > GetActorObjectAsync(StringAttribute Actor, Variables Variables)
Gets an actor object, given a string representation, possibly containing script, of the actor.
static void Indent(StreamWriter Output, int Indentation)
Adds indentation to the current row.
Contains the value of a string attribute, possibly with embedded script.
async Task< string > GetValueAsync(Variables Variables)
Gets the value of the attribute.
string Value
String value, from definition
Waher.Things.SensorData.FieldType Type
Field Type
Definition: FieldType.cs:43
Sends a custom IQ request to a recipient
Definition: ReadSensor.cs:38
override string LocalName
Local name of XML element defining contents of class.
Definition: ReadSensor.cs:60
override async Task< LinkedListNode< IActivityNode > > Execute(Variables Variables)
Executes a node.
Definition: ReadSensor.cs:119
ReadSensor(ISimulationNode Parent, Model Model)
Sends a custom IQ request to a recipient
Definition: ReadSensor.cs:52
override ISimulationNode Create(ISimulationNode Parent, Model Model)
Creates a new instance of the node.
Definition: ReadSensor.cs:68
override async Task FromXml(XmlElement Definition)
Sets properties and attributes of class in accordance with XML definition.
Definition: ReadSensor.cs:77
override void ExportPlantUml(StreamWriter Output, int Indentation, char QuoteChar)
Exports PlantUML
Definition: ReadSensor.cs:215
Abstract base class for IoT XMPP activity nodes.
Helps with common XML-related tasks.
Definition: XML.cs:19
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:914
Maintains information about an item in the roster.
Definition: RosterItem.cs:75
bool HasLastPresence
If the roster item has received presence from an online resource having the given bare JID.
Definition: RosterItem.cs:425
string LastPresenceFullJid
Full JID of last resource sending online presence.
Definition: RosterItem.cs:343
PresenceEventArgs LastPresence
Last presence received from a resource having this bare JID.
Definition: RosterItem.cs:356
Implements an XMPP sensor client interface.
Definition: SensorClient.cs:21
Task< SensorDataClientRequest > RequestReadout(string Destination, FieldType Types)
Requests a sensor data readout.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:59
static readonly Regex BareJidRegEx
Regular expression for Bare JIDs
Definition: XmppClient.cs:188
XmppClient Client
XMPP Client.
Collection of variables.
Definition: Variables.cs:25
Base class for all sensor data fields.
Definition: Field.cs:20
Contains information about an error on a thing
Definition: ThingError.cs:10
string ErrorMessage
Error message.
Definition: ThingError.cs:70
Contains a reference to a thing
Basic interface for simulator nodes. Implementing this interface allows classes with default contruct...
ISimulationNode Parent
Parent node in the simulation model.
SensorDataResponseType
How sensor data is to be returned.
Definition: ReadSensor.cs:22
SensorDataReadoutState
Sensor Data Readout States.
FieldType
Field Type flags
Definition: FieldType.cs:10