private async void LoadHistoricalData()
        {
            var endDate          = _selectedCropCycle.EndDate?.AddDays(1) ?? DateTimeOffset.Now.AddDays(1);
            var sensorsHistories =
                await
                _db.SensorsHistory.Where(
                    sh =>
                    sh.LocationID == _selectedCropCycle.LocationID &&
                    sh.TimeStamp > _selectedCropCycle.StartDate && sh.TimeStamp < endDate).ToListAsync();


            Parallel.ForEach(SensorsToGraph, tuple =>
            {
                var shCollection        = sensorsHistories.Where(sh => sh.SensorID == tuple.sensor.ID);
                var datapointCollection = new List <BindableDatapoint>();
                foreach (var sh in shCollection)
                {
                    sh.DeserialiseData();
                    foreach (var dp in sh.Data)
                    {
                        if (dp.TimeStamp > _selectedCropCycle.StartDate)
                        // becuase datapoints are packed into days, we must avoid datapoitns that astarted before the cropRun
                        {
                            var bindable = new BindableDatapoint(dp);
                            datapointCollection.Add(bindable);
                        }
                    }
                }
                var ordered = datapointCollection.OrderBy(dp => dp.timestamp);


                tuple.historicalDatapoints = new ObservableCollection <BindableDatapoint>(ordered);
            });
        }
        public void ReceiveDatapoint(IEnumerable <Messenger.SensorReading> readings)
        {
            if (SensorsToGraph != null)
            {
                _pauseChart.Invoke();

                var Added = false;
                foreach (var reading in readings)
                {
                    var tuple = SensorsToGraph.FirstOrDefault(stup => stup.sensor.ID == reading.SensorId);
                    if (tuple != null)
                    {
                        if (tuple.hourlyDatapoints.Count == 0 ||
                            tuple.hourlyDatapoints.LastOrDefault().timestamp < reading.Timestamp.LocalDateTime)
                        {
                            Added = true;
                            var datapoint = new BindableDatapoint(reading.Timestamp, reading.Value);
                            tuple.hourlyDatapoints.Add(datapoint);

                            //Remove datapoints if we are storing more than an hour of them
                            if (tuple.hourlyDatapoints.Count > 3000)
                            {
                                tuple.hourlyDatapoints.RemoveAt(0);
                            }
                        }
                    }
                }
                if (Added)
                {
                    var tupleForChartUpdate = SensorsToGraph.FirstOrDefault();
                    if (tupleForChartUpdate?.RealtimeMode ?? false)
                    {
                        tupleForChartUpdate.Axis.Minimum =
                            tupleForChartUpdate.hourlyDatapoints.FirstOrDefault()?.timestamp ??
                            DateTime.Now.AddHours(-1);
                        tupleForChartUpdate.Axis.Maximum =
                            tupleForChartUpdate.hourlyDatapoints.LastOrDefault()?.timestamp ?? DateTime.Now;
                    }
                }

                _resumeChart.Invoke();
            }
        }