4using System.Threading.Tasks;
23 private string collection =
string.Empty;
24 private string[] fieldIndices =
null;
25 private bool checkCollection =
false;
26 private bool checkIndices =
false;
39 [Header(2,
"Collection:", 10)]
40 [Page(3,
"Output", 0)]
41 [ToolTip(4,
"Name of collection in internal database that will house the sensor data.")]
45 get => this.collection;
48 if (this.collection != value)
50 this.collection = value;
51 this.checkCollection =
true;
52 this.checkIndices =
true;
60 [Header(5,
"Index field names:", 20)]
61 [Page(3,
"Output", 0)]
62 [ToolTip(6,
"Indices will be added on these field names for quicker access to records.")]
65 get => this.fieldIndices;
68 if (!this.fieldIndices.ElementEquals(value))
70 this.fieldIndices = value;
71 this.checkIndices =
true;
79 [Header(7,
"Store physical units.", 30)]
80 [Page(3,
"Output", 0)]
81 [ToolTip(8,
"If physical units should be stored in a separate property.")]
87 [Header(9,
"Store field type.", 40)]
88 [Page(3,
"Output", 0)]
89 [ToolTip(10,
"If field type should be stored in a separate property.")]
95 [Header(11,
"Store quality of service.", 50)]
96 [Page(3,
"Output", 0)]
97 [ToolTip(12,
"If quality of service should be stored in a separate property.")]
117 return Task.FromResult(
false);
139 if (this.checkCollection)
141 if (
string.IsNullOrEmpty(this.collection))
143 await this.
LogErrorAsync(
"CollectionError",
"Collection name cannot be empty.");
151 if (Array.IndexOf(Collections,
this.collection) < 0)
152 this.checkIndices =
true;
154 this.checkCollection =
false;
157 if (this.checkIndices)
159 Dictionary<string, string[]> Indices =
new Dictionary<string, string[]>();
162 Indices[IndexKey(Index)] = Index;
164 await this.AddIndexIfNotDefined(Indices,
new string[]
170 await this.AddIndexIfNotDefined(Indices,
new string[]
176 foreach (
string FieldName
in this.fieldIndices ?? Array.Empty<
string>())
178 string s = FieldName.Trim();
179 if (
string.IsNullOrEmpty(s))
182 await this.AddIndexIfNotDefined(Indices,
new string[]
189 await this.AddIndexIfNotDefined(Indices,
new string[]
197 foreach (KeyValuePair<
string,
string[]> IndexLeft
in Indices)
200 this.checkIndices =
false;
203 Dictionary<DateTime, GenericObject> PerTime =
new Dictionary<DateTime, GenericObject>();
205 DateTime LastTime = DateTime.MinValue;
215 Obj =
new GenericObject(this.collection,
string.Empty, Guid.Empty,
216 new KeyValuePair<string, object>(
"NodeId", Sensor.NodeId),
217 new KeyValuePair<string, object>(
"Timestamp", LastTime));
218 PerTime[LastTime] = Obj;
229 Obj[Field.Name +
", Unit"] = Q.Unit;
238 Obj[Field.Name +
", QoS"] =
Field.
QoS;
244 private async Task AddIndexIfNotDefined(Dictionary<
string,
string[]> Indices,
string[] Index)
246 string Key = IndexKey(Index);
247 if (!Indices.Remove(Key))
251 private static string IndexKey(
string[] Fields)
253 StringBuilder sb =
new StringBuilder();
256 foreach (
string Field in Fields)
266 return sb.ToString();
Stores sensor data in the internal database.
string Collection
Collection to store data in.
bool StoreQoS
If field type should be stored.
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 ...
string[] FieldIndices
Fields to index in collection.
override Task< string > GetTypeNameAsync(Language Language)
Gets the type name of the node.
async Task OutputFields(ISensor Sensor, Field[] Fields)
Outputs a collection of sensor data fields.
bool StoreUnits
If physical quantity units should be stored.
InternalDatabaseOutput()
Stores sensor data in the internal database.
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...
bool StoreFieldType
If field type should be stored.
Class for the root node of the Output data source.
Base class for all output nodes.
INode Parent
Parent Node, or null if a root node.
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.
Static interface for database persistence. In order to work, a database provider has to be assigned t...
static Task RemoveIndex(string CollectionName, string[] FieldNames)
Removes an index from a collection, if one exist.
static Task AddIndex(string CollectionName, string[] FieldNames)
Adds an index to a collection, if one does not already exist.
static Task< string[]> GetCollections()
Gets an array of available collections.
static Task< string[][]> GetIndices(string CollectionName)
Removes an index from a collection, if one exist.
static async Task Insert(object Object)
Inserts an object into the default collection of the database.
Generic object. Contains a sequence of properties.
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 ...
Represents a named semaphore, i.e. an object, identified by a name, that allows single concurrent wri...
Static class of application-wide semaphores that can be used to order access to editable objects.
static async Task< Semaphore > BeginWrite(string Key)
Waits until the semaphore identified by Key is ready for writing. Each call to BeginWrite must be fo...
Base class for all sensor data fields.
FieldQoS QoS
Field Quality of Service flags.
FieldType Type
Field Type flags.
abstract object ObjectValue
Field value, boxed as an object reference.
string Name
Unlocalized field name.
DateTime Timestamp
Timestamp of field value.
Base Interface for all sensor-data output nodes.
Interface for nodes that are published through the concentrator interface.
Interface for sensor nodes.