//TODO register this with an event in messenger class
        /// <summary>Loads device and sensor info from the DB.</summary>
        /// <remarks>Don't make publish or call directly! always push onto the task!</remarks>
        /// <returns>True if it loaded something, false otherwise.</returns>
        private void LoadData()
        {
            LoggingService.LogInfo("DatapointsSaver refreshing cache", Windows.Foundation.Diagnostics.LoggingLevel.Information);
            using (var db = new MainDbContext())
            {
                _dbDevices = db.Devices.Include(dv => dv.Sensors).Include(dv => dv.Relays).AsNoTracking().ToList();
                var sensorsHistory = db.SensorsHistory.Where(sh => sh.TimeStamp > Today).ToList(); // we will edit this
                _sensorTypes = db.SensorTypes.Include(st => st.Param).Include(st => st.Place).AsNoTracking().ToList();

                //Add missing sensors and relays
                foreach (var sensor in _dbDevices.SelectMany(dv => dv.Sensors))
                {
                    if (_sensorBuffer.Any(sb => sb.Sensor.ID == sensor.ID) == false)
                    {
                        _sensorBuffer.Add(new SensorBuffer(sensor));
                    }
                } //TODO merge the datapoints!
                foreach (var sHistory in sensorsHistory)
                {
                    sHistory.DeserialiseData();
                    var mIndex = _sensorBuffer.FindIndex(sb => sb.Sensor.ID == sHistory.SensorID);
                    if (_sensorBuffer[mIndex].DataDay == null ||
                        _sensorBuffer[mIndex].DataDay.TimeStamp < sHistory.TimeStamp)
                    {
                        _sensorBuffer[mIndex] = new SensorBuffer(_sensorBuffer[mIndex].Sensor, sHistory);
                    }
                    else if (_sensorBuffer[mIndex].DataDay.Data != null && sHistory.Data != null)
                    {
                        var sHistMerged = SensorHistory.Merge(_sensorBuffer[mIndex].DataDay, sHistory);
                        _sensorBuffer[mIndex] = new SensorBuffer(_sensorBuffer[mIndex].Sensor, sHistMerged);
                    }
                }
            }
        }
        public void BufferAndSendReadings(KeyValuePair <Guid, SensorMessage[]> values, string deviceName)
        {
            //Purposefull fire and forget
            _localTask = _localTask.ContinueWith(previous =>
            {
                var device = _dbDevices.FirstOrDefault(dv => dv.SerialNumber == values.Key);

                if (device == null)
                {
                    CreateDevice(values, deviceName);
                }
                else
                {
                    var sensorReadings = new List <BroadcasterService.SensorReading>();

                    foreach (var message in values.Value)
                    {
                        try
                        {
                            var SensorObject          = device.Sensors.FirstOrDefault(sen => sen.SensorTypeID == message.SensorTypeID);
                            SensorBuffer sensorBuffer = _sensorBuffer.FirstOrDefault(sb => sb.Sensor.ID == SensorObject.ID);
                            if (SensorObject == null || sensorBuffer == null)
                            {
                                Util.LoggingService.LogInfo($"Device has a new sensor with typeID {message.SensorTypeID}, however adding sensors is not supported yet.", Windows.Foundation.Diagnostics.LoggingLevel.Error);
                                break;
                            }

                            var duration  = TimeSpan.FromMilliseconds((double)message.duration / 1000);
                            var timeStamp = DateTimeOffset.Now;
                            var datapoint = new SensorDatapoint(message.value, timeStamp, duration);
                            sensorBuffer.FreshBuffer.Add(datapoint);
                            var sensorReading = new BroadcasterService.SensorReading(sensorBuffer.Sensor.ID, datapoint.Value,
                                                                                     datapoint.TimeStamp, datapoint.Duration);
                            sensorReadings.Add(sensorReading);
                        }
                        catch (ArgumentNullException)
                        {
                            //TODO add a new sensor to the device!
                        }
                    }


                    //this is meant to be fire-forget, that's cool
#pragma warning disable CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                    WebSocketConnection.Instance.SendAsync(sensorReadings);
                    BroadcasterService.Instance.NewSensorDataPoint.Invoke(sensorReadings);
#pragma warning restore CS4014 // Because this call is not awaited, execution of the current method continues before the call is completed
                }
            });
        }
        //Closes sensor Histories that are no longer usefull
        private void SaveBufferedReadings(object sender, object e)
        {
            LoggingService.LogInfo($"Saved Buffered Readings: {DateTimeOffset.Now.DateTime} Datapointsaver", Windows.Foundation.Diagnostics.LoggingLevel.Information);
            _localTask = _localTask.ContinueWith(previous =>
            {
                //if (Settings.Instance.LastSuccessfulGeneralDbGet > DateTimeOffset.Now - TimeSpan.FromMinutes(5))
                //{
                LoggingService.LogInfo("Datasaver started, did not bother detecting a recent update.", Windows.Foundation.Diagnostics.LoggingLevel.Verbose);

                using (var db = new MainDbContext())
                {
                    for (var i = 0; i < _sensorBuffer.Count; i++)
                    {
                        var sbuffer = _sensorBuffer[i];

                        SensorDatapoint sensorDatapoint = null;

                        if (sbuffer.FreshBuffer.Count > 0)
                        {
                            var startTime = sbuffer.FreshBuffer[0].TimeStamp;
                            var endTime   = sbuffer.FreshBuffer.Last().TimeStamp;
                            var duration  = (endTime - startTime).Subtract(sbuffer.FreshBuffer[0].Duration);

                            var cumulativeDuration = TimeSpan.Zero;
                            double cumulativeValue = 0;

                            for (var b = 0; b < sbuffer.FreshBuffer.Count; b++)
                            {
                                cumulativeDuration += sbuffer.FreshBuffer[b].Duration;
                                cumulativeValue    += sbuffer.FreshBuffer[b].Value;
                            }

                            var sensorType = _sensorTypes.First(st => st.ID == sbuffer.Sensor.SensorTypeID);
                            var value      = cumulativeValue / sbuffer.FreshBuffer.Count;

                            if (sensorType.ParamID == 5) // Level
                            {
                                sensorDatapoint = new SensorDatapoint(Math.Round(value), endTime, duration);
                            }
                            else if (sensorType.ParamID == 9) //water flow
                            {
                                sensorDatapoint = new SensorDatapoint(value, endTime, cumulativeDuration);
                            }
                            else
                            {
                                sensorDatapoint = new SensorDatapoint(value, endTime, duration);
                            }

                            sbuffer.FreshBuffer.RemoveRange(0, sbuffer.FreshBuffer.Count);
                        }

                        //only if new data is present
                        if (sensorDatapoint != null)
                        {
                            //check if corresponding dataDay is too old or none exists at all
                            if (sbuffer.DataDay?.TimeStamp < sensorDatapoint.TimeStamp || sbuffer.DataDay == null)
                            {
                                var dataDay = new SensorHistory
                                {
                                    LocationID = sbuffer.Sensor.Device.LocationID,
                                    SensorID   = sbuffer.Sensor.ID,
                                    Sensor     = sbuffer.Sensor,
                                    TimeStamp  = Tomorrow,
                                    Data       = new List <SensorDatapoint>()
                                };
                                _sensorBuffer[i] = new SensorBuffer(sbuffer.Sensor, dataDay);
                                //Only uses this entity, and does not follow the references to stick related references in the DB
                                db.Entry(dataDay).State = EntityState.Added;
                            }
                            else
                            {
                                //this will not attach related entities, which is good
                                db.Entry(sbuffer.DataDay).State = EntityState.Unchanged;
                            }

                            _sensorBuffer[i].DataDay.Data.Add(sensorDatapoint);
                            _sensorBuffer[i].DataDay.SerialiseData();
                        }
                    } //for loop ends
                    //Once we are done here, mark changes to the db
                    db.SaveChanges();
                    LoggingService.LogInfo("Saved Sensor Data", Windows.Foundation.Diagnostics.LoggingLevel.Verbose);
                }
                //}
                //else
                //{
                //    Debug.WriteLine("Skipped datasaver due to lack of recent update.");
                //}
            });
        }