/// <summary>Gets all histories between and including the datetime given.</summary> /// <param name="fromDateTimeUnixSeconds">The earliest time to include datapoints.</param> /// <param name="toUtcDateTimeUnixSeconds">The latest time to include dataopints.</param> /// <returns>All the histories between the specified times.</returns> public async Task <IActionResult> GetUserHistories(long fromDateTimeUnixSeconds, long toUtcDateTimeUnixSeconds) { // Filter by the UTC Date (time 00:00:00 (==12:00am)). // All times are converted to the starting time of the day. var fromDateTime = DateTimeOffset.FromUnixTimeSeconds(fromDateTimeUnixSeconds); var fromDate = fromDateTime.Date; var toDateTime = DateTimeOffset.FromUnixTimeSeconds(toUtcDateTimeUnixSeconds); var toDate = toDateTime.Date; // Prepare to filter by locations owned by the user. var user = await _userManager.GetUserAsync(User); var userId = new Guid(user.Id); var locationIds = await _db.Locations.Where(l => l.PersonId == userId).Select(l => l.Id).ToListAsync(); var data = await _db.SensorHistories.Where( h => locationIds.Contains(h.LocationId) && (h.UtcDate >= fromDate) && (h.UtcDate <= toDate)) .ToListAsync(); var needsSlicing = data.Where(h => (h.UtcDate == fromDate) || (h.UtcDate == toDate)); foreach (var history in needsSlicing) { var sliced = SensorDatapoint.Slice(history.RawData, fromDateTime, toDateTime); history.RawData = sliced; } return(new JsonResult(data)); }
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 } }); }
public async Task <IActionResult> SetUserHistories([FromBody] List <SensorHistory> histories) { var user = await _userManager.GetUserAsync(User); var userId = new Guid(user.Id); var locationIds = await _db.Locations.Where(l => l.PersonId == userId).Select(l => l.Id).ToListAsync(); if (histories.Any(h => !locationIds.Contains(h.LocationId))) { var message = "Cant save histories at locations not owned by user."; _logger.LogError(message); return(BadRequest(message)); } // Composite keys aren't easy to turn into a query. var historyIds = histories.Select(h => $"{h.SensorId},{h.UtcDate.Ticks}"); var existsInDb = await _db.SensorHistories .Where(h => historyIds.Contains($"{h.SensorId},{h.UtcDate.Ticks}")) .ToListAsync(); var itemsToUpdate = new List <SensorHistory>(); foreach (var dbHistory in existsInDb) { // Removed the already existing item from the histories recieved from the API. var recievedHist = histories.First(h => (h.UtcDate == dbHistory.UtcDate) && (h.SensorId == dbHistory.SensorId)); histories.Remove(recievedHist); var mergedData = SensorDatapoint.Merge(dbHistory.RawData, recievedHist.RawData); // Merge the data in the newly recieved data which should have an updated UploadedAt. recievedHist.RawData = mergedData; if (recievedHist.UploadedAt < DateTimeOffset.Now - TimeSpan.FromMinutes(5)) { return(BadRequest("UploadedAt time was not set or significant lag has occured.")); } itemsToUpdate.Add(recievedHist); } // The remaining items left in histories must all be new. _db.SensorHistories.AddRange(histories); _db.SensorHistories.UpdateRange(itemsToUpdate); await _db.SaveChangesAsync(); return(Ok()); }
public void BufferAndSendReadings(KeyValuePair <Guid, Manager.SensorMessage[]> values) { //Purposefull fire and forget _localTask = _localTask.ContinueWith(previous => { var device = _dbDevices.FirstOrDefault(dv => dv.SerialNumber == values.Key); if (device == null) { CreateDevice(values); } else { var sensorReadings = new List <Messenger.SensorReading>(); foreach (var message in values.Value) { try { var sensorBuffer = _sensorBuffer.First(sb => sb.Sensor.SensorTypeID == message.SensorTypeID); 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 Messenger.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); Messenger.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."); //} }); }
public BindableDatapoint(SensorDatapoint datapoint) { timestamp = datapoint.TimeStamp.LocalDateTime; value = datapoint.Value; }