/// <summary> /// Write this sensor out to a configuration file /// </summary> /// <param name="r"></param> /// <returns></returns> public void Serialize(string filename) { try { var settings = new JsonSerializerSettings(); settings.TypeNameHandling = TypeNameHandling.Objects; settings.Formatting = Newtonsoft.Json.Formatting.Indented; var s = JsonConvert.SerializeObject(SensorProject.Current, settings); File.WriteAllText(filename, s); } catch (Exception ex) { SensorProject.LogException("Error saving sensor project", ex); } }
/// <summary> /// Collect data for this sensor (with parameter - not used!) /// </summary> public async Task OuterCollect() { DateTime collectStartTime = DateTime.MinValue; DateTime collectFinishTime = DateTime.MinValue; bool success = false; TimeSpan ts = new TimeSpan(); SensorData sd = null; SensorCollectEventArgs args = new SensorCollectEventArgs(); // Collect data and clock how long it took try { collectStartTime = DateTime.UtcNow; args.Raw = await Collect(); collectFinishTime = DateTime.UtcNow; ts = collectFinishTime - collectStartTime; // Record what was collected LastCollectTime = collectFinishTime; sd = AddValue(args.Raw.Value, collectStartTime, (int)ts.TotalMilliseconds); success = true; // If something blew up, keep track of it } catch (Exception ex) { args.Exception = new SensorException() { Cleared = false, Description = ex.Message, ExceptionTime = DateTime.UtcNow, StackTrace = ex.StackTrace }; LastException = ex.ToString(); InError = true; if (PauseOnError) { Enabled = false; SensorProject.LogException("Sensor error & pause: (#" + this.Identity + ") " + this.Name, ex); } else { SensorProject.LogException("Sensor error: (#" + this.Identity + ") " + this.Name, ex); } // Release the inflight status so that this sensor can collect again } finally { // Move forward to next collection time period - skip any number of intermediate time periods if (NextCollectTime < DateTime.UtcNow) { NextCollectTime = DateTime.UtcNow.AddSeconds((int)Frequency); } // Allow this to be recollected again InFlight = false; } // Now, all elements that can safely be moved after the inflight flag is turned off if (success) { args.Data = new Common.SensorData() { CollectionTimeMs = (int)ts.TotalMilliseconds, Time = collectFinishTime, Value = args.Raw.Value }; // Is anyone listening? if (this.SensorCollect != null) { SensorCollect(this, args); } } // Notify everyone of what happened if (Children != null) { foreach (ICondition c in Children) { c.TestCondition(args); } } }
/// <summary> /// Read a sensor back from a node from an XML file /// </summary> /// <param name="r"></param> /// <returns></returns> public static SensorProject Deserialize(string filename) { SensorProject sp = null; // Read in the text try { var settings = new JsonSerializerSettings(); settings.TypeNameHandling = TypeNameHandling.Objects; settings.Formatting = Newtonsoft.Json.Formatting.Indented; string s = File.ReadAllText(filename); sp = JsonConvert.DeserializeObject <SensorProject>(s, settings); // Failed to load } catch (Exception ex) { SensorProject.LogException("Error loading sensor file", ex); sp = new SensorProject(); } // Now make all the sensors read their data Current = sp; List <int> sensor_id_list = new List <int>(); foreach (IDevice dc in sp.Children) { dc.Parent = SensorProject.Current; // Go through all sensors for this device foreach (ISensor bs in dc.Children) { // Make sure each sensor is uniquely identified! If any have duplicate IDs, uniqueify them if (sensor_id_list.Contains(bs.Identity)) { bs.Identity = sp.NextSensorNum++; } sensor_id_list.Add(bs.Identity); bs.Parent = (IDevice)dc; // Read in each sensor's data, and write it back out to disk // (this ensures that all files have the same fields in the same order - permits appending via AppendText later bs.DataRead(); // Loop through all conditions / actions foreach (ICondition c in bs.Children) { c.Parent = bs; foreach (IAction a in c.Children) { a.Parent = c; } } } } // Ensure that the log folder exists if (!Directory.Exists("logs")) { Directory.CreateDirectory("Logs"); } // Save this as the current project return(sp); }
/// <summary> /// This is the background thread for collecting data /// </summary> public async void CollectionThread() { // Okay, let's enter the loop while (_keep_running) { int collect_count = 0; DateTime next_collect_time = DateTime.MaxValue; // Be safe about this - we don't want this thread to blow up! It's the only one we've got try { // Loop through sensors, and spawn a work item for them for (int i = 0; i < Children.Count; i++) { IDevice dc = Children[i] as IDevice; for (int j = 0; j < dc.Children.Count; j++) { // Allow us to kick out if (!_keep_running) { return; } // Okay, let's work on this sensor ISensor s = dc.Children[j] as ISensor; if ((s.Enabled) && (!s.InFlight) && (s.Frequency != Interval.Never)) { // Spawn a work item in the thread pool to do this collection task if (s.NextCollectTime <= DateTime.UtcNow) { s.InFlight = true; Task.Run(() => s.OuterCollect()); collect_count++; // If it's not time yet, use this to factor when next to wake up } else { if (s.NextCollectTime < next_collect_time) { next_collect_time = s.NextCollectTime; } } } } } // Failsafe } catch (Exception ex) { SensorProject.LogException("Collect", ex); } // Sleep until next collection time, but allow ourselves to kick out if (!_keep_running) { return; } TimeSpan time_to_sleep = next_collect_time - DateTime.UtcNow; int clean_sleep_time = Math.Max(1, Math.Min((int)time_to_sleep.TotalMilliseconds, 1000)); await Task.Delay(clean_sleep_time); } }