//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);
                    }
                }
            }
        }
Exemple #2
0
        public int AddSmokeSensorHistory(SmokeSensor sensor)
        {
            if (sensor == null)
            {
                throw new Exception("Sensore object cannot be null");
            }

            sensorHistory = new SensorHistory
            {
                HouseId  = sensor.HouseId,
                SensorId = sensor.SensorId,
                Type     = sensor.Type,
                Name     = sensor.Name,
                Smoke    = sensor.Smoke,
                IsOn     = sensor.IsOn
            };

            try
            {
                _databaseContext.SensorHistories.Add(sensorHistory);
                _databaseContext.SaveChanges();
            }

            catch (Exception exp)
            {
                Console.WriteLine(exp.Message);
            }

            return(sensorHistory.SensorHistoryId);
        }
Exemple #3
0
        public JsonResult UpdateSensor([FromBody] SensorUpdate s)
        {
            var sensor = _ctx.Find("{\"SensorId\" : \"" + s.SensorId + "\"}").FirstOrDefault();

            sensor.SensorValue   = s.Value;
            sensor.SensorBattery = s.Battery;

            var historyItem = new SensorHistory()
            {
                SensorId      = sensor.SensorId,
                SensorValue   = sensor.SensorValue,
                SensorBattery = sensor.SensorBattery,
                Timestamp     = DateTime.Now
            };

            _ctx.ReplaceOne("{\"SensorId\" : \"" + s.SensorId + "\"}", sensor);
            _history.InsertOne(historyItem);

            return(new JsonResult(sensor));
        }
        public int AddTemperatureSensorHistory(TemperatureSensor sensor)
        {
            if (sensor == null)
            {
                throw new Exception("Sensore object cannot be null");
            }

            sensorHistory = new SensorHistory
            {
                HouseId     = sensor.HouseId,
                SensorId    = sensor.SensorId,
                Type        = sensor.Type,
                Name        = sensor.Name,
                Temperature = sensor.Temperature,
                IsOn        = sensor.IsOn
            };

            _databaseContext.SensorHistories.Add(sensorHistory);
            _databaseContext.SaveChanges();

            return(sensorHistory.SensorHistoryId);
        }
        public async Task <HttpResponseMessage> PostSensorsHistory(List <SensorHistory> shRecievedList)
        {
            if (!ModelState.IsValid)
            {
                return(Request.CreateResponse(HttpStatusCode.BadRequest, ModelState));
            }

            List <Guid> sensorIDs = shRecievedList.Select(chR => chR.SensorID).ToList();

            //Get all relevant sensors, they must both exist and belong to this user!
            List <Sensor> userSensors =
                await _db.Sensors.Where(rel => sensorIDs.Contains(rel.ID) && rel.Device.Location.PersonId == _UserID)
                .ToListAsync();

            //If one of the submitted items reffers to a sensor that doesn't exist/belong to user, return error
            foreach (SensorHistory sHistory in shRecievedList)
            {
                if (userSensors.Any(rel => rel.ID == sHistory.SensorID) == false)
                {
                    return(Request.CreateResponse(HttpStatusCode.BadRequest,
                                                  new ErrorResponse <SensorHistory>("One of the SensorIDs does not exist", sHistory)));
                }
            }

            //Get all the control histories that are being edited
            List <DateTimeOffset> timestamps        = shRecievedList.Select(sensHist => sensHist.TimeStamp).ToList();
            List <SensorHistory>  sensHistDbRawList = await _db.SensorHistories.Where(sensHist => timestamps.Contains(sensHist.TimeStamp) &&
                                                                                      sensorIDs.Contains(sensHist.SensorID)).ToListAsync();

            List <Location> userLocations = await _db.Location.Where(loc => loc.PersonId == _UserID).ToListAsync();

            foreach (var sensHistRecieved in shRecievedList)
            {
                SensorHistory SensHistoryDB = sensHistDbRawList.FirstOrDefault(rHist => rHist.SensorID == sensHistRecieved.SensorID &&
                                                                               rHist.TimeStamp == sensHistRecieved.TimeStamp);

                if (SensHistoryDB == null) //create new
                {
                    if (false == userLocations.Any(loc => loc.ID == sensHistRecieved.LocationID))
                    {
                        return(Request.CreateResponse(HttpStatusCode.BadRequest,
                                                      new ErrorResponse <SensorHistory>("Referenced location doesn't exist", sensHistRecieved)));
                    }

                    sensHistRecieved.SerialiseData();
                    sensHistRecieved.UploadedAt       = DateTimeOffset.Now;
                    _db.Entry(sensHistRecieved).State = EntityState.Added;
                }
                else
                {
                    if (SensHistoryDB.LocationID != sensHistRecieved.LocationID)
                    {
                        return(Request.CreateResponse(HttpStatusCode.Forbidden,
                                                      new ErrorResponse <SensorHistory>("You are not allowed to change location of SensorHistory", sensHistRecieved)));
                    }



                    //Check if changed were made by comparing raw bytes data
                    sensHistRecieved.SerialiseData();


                    if (Compare(sensHistRecieved.RawData, SensHistoryDB.RawData) == false)
                    {
                        SensHistoryDB.DeserialiseData();
                        SensorHistory chMerged = SensorHistory.Merge(SensHistoryDB, sensHistRecieved);
                        SensHistoryDB.Data = chMerged.Data;
                        SensHistoryDB.SerialiseData();
                        SensHistoryDB.UploadedAt = DateTimeOffset.Now;
                    }
                }
            }

            await _db.SaveChangesAsync();

            return(Request.CreateResponse(HttpStatusCode.OK));
        }
 public SensorBuffer(Sensor assignSensor, SensorHistory inDataDay = null)
 {
     Sensor      = assignSensor;
     FreshBuffer = new List <SensorDatapoint>();
     DataDay     = inDataDay;
 }
        //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.");
                //}
            });
        }
        /// <summary>Updates sensor history from server.</summary>
        /// <returns>Errors, null on succes. Some data may have been successfully saved alongside errors.</returns>
        private static async Task <string> GetRequestSensorHistoryAsync(MainDbContext db)
        {
            var devices = db.Devices.AsNoTracking().Include(d => d.Sensors).ToList();
            var table   = nameof(db.SensorsHistory);
            var errors  = "";

            // Download all the data for each device in turn.
            foreach (var device in devices)
            {
                // Find the newest received item so dowloading can resume after it.
                // There will be items for multiple sensors with the same time, it diesn't matter which one is used.
                // It will be updated after each item is added, much cheaper than re-querying.
                var mostRecentDayDownloaded =
                    db.SensorsHistory.AsNoTracking()
                    .Include(sh => sh.Sensor)
                    .Where(sh => sh.Sensor.DeviceID == device.ID)
                    // Never uploaded days may be much newer than items that have not yet been downloaded.
                    .Where(sh => sh.UploadedAt != default(DateTimeOffset))     //Ignore never uploaded days.
                    .OrderByDescending(sh => sh.TimeStamp).FirstOrDefault();   //Don't use MaxBy, it wont EF query.

                DateTimeOffset mostRecentDownloadedTimestamp;
                if (null == mostRecentDayDownloaded)
                {
                    // Data has never been downloaded for this device, so start downloading for time 0.
                    mostRecentDownloadedTimestamp = default(DateTimeOffset);
                }
                else
                {
                    //The timestamp is always the end of the day so look inside to see what time the data actually ends.

                    // Its pulled out of the database as raw so deserialise to access the data.
                    mostRecentDayDownloaded.DeserialiseData();
                    if (mostRecentDayDownloaded.Data.Any())
                    {
                        mostRecentDownloadedTimestamp = mostRecentDayDownloaded.Data.Max(entry => entry.TimeStamp);
                    }
                    else
                    {
                        Log.ShouldNeverHappen(
                            $"Found a history with no entries: {device.Name}, {mostRecentDayDownloaded.TimeStamp}");

                        // This is a broken situation, but it should be  fine if we continue from the start of the day.
                        mostRecentDownloadedTimestamp = mostRecentDayDownloaded.TimeStamp - TimeSpan.FromDays(1);
                    }
                }

                // This loop will keep requesting data untill the server gives no more.
                bool itemsReceived;
                var  added = new List <SensorHistory>();
                do
                {
                    var cred = Creds.FromUserIdAndToken(Settings.Instance.CredUserId, Settings.Instance.CredToken);
                    // Although any time far in the past should work, using 0 makes intent clear in debugging.
                    var unixTimeSeconds = mostRecentDownloadedTimestamp == default(DateTimeOffset)
                        ? 0
                        : mostRecentDownloadedTimestamp.ToUnixTimeSeconds();

                    List <SensorHistory> histories;
                    try
                    {
                        // Download with get request.
                        var raw =
                            await
                            GetRequestTableThrowOnErrorAsync($"{table}/{device.ID}/{unixTimeSeconds}/{MaxDaysDl}",
                                                             cred).ConfigureAwait(false);

                        // Deserialise download to POCO object.
                        histories =
                            await DeserializeTableThrowOnErrrorAsync <SensorHistory>(table, raw).ConfigureAwait(false);
                    }
                    catch (Exception ex)
                    {
                        // Something went wrong, try moving onto next device.
                        var message = $"GetRequest or deserialise failed for {device.Name}: {ex}";
                        errors += message + Environment.NewLine;
                        Debug.WriteLine(message);
                        break;
                    }

                    Debug.WriteLine($"{histories.Count} dl for {device.Name}");

                    if (histories.Any())
                    {
                        var lastDayOfThisDownloadSet = DateTimeOffset.MinValue;
                        foreach (var hist in histories)
                        {
                            Debug.WriteLine(
                                $"[{mostRecentDownloadedTimestamp}]{hist.TimeStamp}#{hist.UploadedAt}#{device.Name}#{hist.SensorID}");

                            // See if this is a new object.
                            var existing =
                                db.SensorsHistory.AsNoTracking()
                                .FirstOrDefault(
                                    sh => sh.SensorID == hist.SensorID && sh.TimeStamp.Date == hist.TimeStamp.Date);
                            // Make sure that its not an object tracked from a previous loop.
                            // This can happen because the end of the previous day will always get sliced with no data.
                            // That end slice isn't perfect but is makes sure all the data was taken.
                            if (existing == null)
                            {
                                existing =
                                    added.FirstOrDefault(
                                        sh => sh.SensorID == hist.SensorID && sh.TimeStamp.Date == hist.TimeStamp.Date);
                                if (existing != null)
                                {
                                    // Detach the existing object because it will be merged and replaced.
                                    var entityEntry = db.Entry(existing);
                                    entityEntry.State = EntityState.Detached;
                                    added.Remove(existing);
                                }
                            }
                            if (existing == null)
                            {
                                // The json deserialiser deserialises json to the .Data property.
                                // The data has to be serialised into raw-data-blobs before saving to the databse.
                                hist.SerialiseData();
                                added.Add(db.Add(hist).Entity);
                            }
                            else
                            {
                                // The data is pulled from the database as serialised raw data blobs.
                                existing.DeserialiseData();
                                // The merged object merges using the deserialised Data property.
                                var merged = SensorHistory.Merge(existing, hist);
                                // Data has to be serialised again into raw data blobs for the database.
                                merged.SerialiseData();

                                added.Add(db.Update(merged).Entity);
                            }

                            // This day was just downloaded so it must be completed
                            if (hist.TimeStamp > lastDayOfThisDownloadSet)
                            {
                                lastDayOfThisDownloadSet = hist.TimeStamp;
                            }
                        }
                        // The GET request allways gets days completed to the end (start may be missing but not the end)
                        mostRecentDownloadedTimestamp = lastDayOfThisDownloadSet;
                        itemsReceived = true;
                    }
                    else
                    {
                        itemsReceived = false;
                    }
                } while (itemsReceived);

                // Save the data for this device.
                await Task.Run(() => db.SaveChanges()).ConfigureAwait(false);

                foreach (var entity in added)
                {
                    var entry = db.Entry(entity);
                    if (entry.State != EntityState.Detached)
                    {
                        entry.State = EntityState.Detached;
                    }
                }

                // Move onto next device.
            }

            return(string.IsNullOrWhiteSpace(errors) ? null : errors);
        }