Exemple #1
0
        public async Task <GlucoseResult> GetLatestReading()
        {
            var fetchResult = new GlucoseResult();

            try
            {
                if (_options.FetchMethod == FetchMethod.DexcomShare)
                {
                    await GetFetchResultFromDexcom(fetchResult).ConfigureAwait(false);
                }
                else if (_options.FetchMethod == FetchMethod.NightscoutApi)
                {
                    await GetFetchResultFromNightscout(fetchResult).ConfigureAwait(false);
                }
                else
                {
                    _logger.LogError("Invalid fetch method specified.");
                    throw new InvalidOperationException("Fetch Method either not specified or invalid specification.");
                }

                fetchResult.IsCriticalLow = IsCriticalLow(fetchResult);
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to get data. {0}", ex);
                fetchResult = GetDefaultFetchResult();
            }

            return(fetchResult);
        }
Exemple #2
0
        private async void BeginCycle()
        {
            while (true)
            {
                try
                {
                    Application.DoEvents();

                    var results = await _fetchService.GetLatestReadings(GlucoseResult?.DateTimeUTC).ConfigureAwait(false);

                    if (results.Any())
                    {
                        GlucoseResult = results.Last();
                    }

                    CreateIcon();
                    AlertNotification();

                    await Task.Delay(_options.CurrentValue.PollingThresholdTimeSpan);
                }
                catch (Exception e)
                {
                    MessageBox.Show($"ERROR: {e}", "ERROR", MessageBoxButtons.OK, MessageBoxIcon.Error);
                    _logger.LogError(e.ToString());
                    trayIcon.Visible = false;
                    trayIcon?.Dispose();
                    Environment.Exit(0);
                }
            }
        }
Exemple #3
0
        public async Task <List <GlucoseResult> > GetLatestReadings(DateTime?timeOflastGoodResult)
        {
            var fetchResult = new GlucoseResult();

            var results = new List <GlucoseResult>();

            try
            {
                if (_options.CurrentValue.FetchMethod == FetchMethod.DexcomShare)
                {
                    await GetFetchResultFromDexcom(fetchResult).ConfigureAwait(false);

                    results.Add(fetchResult);
                }
                else if (_options.CurrentValue.FetchMethod == FetchMethod.NightscoutApi)
                {
                    results = await GetResultsFromNightscout(timeOflastGoodResult).ConfigureAwait(false);
                }
                else
                {
                    _logger.LogError("Invalid fetch method specified.");
                    throw new InvalidOperationException("Fetch Method either not specified or invalid specification.");
                }
            }
            catch (Exception ex)
            {
                _logger.LogError("Failed to get data. {0}", ex);
            }

            return(results);
        }
Exemple #4
0
        private async Task <List <GlucoseResult> > GetResultsFromNightscout(DateTime?timeOflastGoodResult)
        {
            var url   = $"{_options.CurrentValue.NightscoutUrl?.TrimEnd('/')}/api/v1/entries/sgv?";
            var count = 1;

            if (timeOflastGoodResult.HasValue)
            {
                count = 1000000; // Without sending a maximum count, Nightscout will only return 10 results.
                var fromDate = timeOflastGoodResult.Value.AddSeconds(1).ToString("s") + "Z";
                var toDate   = DateTime.UtcNow.ToString("s") + "Z";
                url += $"find[dateString][$gte]={fromDate}&find[dateString][$lte]={toDate}&";
            }

            url += $"count={count}";
            url += !string.IsNullOrWhiteSpace(_options.CurrentValue.AccessToken) ? $"&token={_options.CurrentValue.AccessToken}" : string.Empty;

            var request = new HttpRequestMessage(HttpMethod.Get, new Uri(url));

            request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

            var results = new List <GlucoseResult>();
            var client  = _httpClientFactory.CreateClient();

            try
            {
                var response = await client.SendAsync(request).ConfigureAwait(false);

                var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                var content = JsonSerializer.Deserialize <List <NightScoutResult> >(result).ToList();
                foreach (var record in content)
                {
                    var fetchResult = new GlucoseResult
                    {
                        Source      = FetchMethod.NightscoutApi,
                        DateTimeUTC = DateTime.Parse(record.dateString).ToUniversalTime(),
                        Trend       = record.direction.GetTrend()
                    };
                    CalculateValues(fetchResult, record.sgv);
                    if (fetchResult.Trend == TrendResult.Unknown)
                    {
                        _logger.LogWarning($"Un-expected value for direction/Trend {record.direction}");
                    }
                    results.Add(fetchResult);
                }

                response.Dispose();
            }
            catch (Exception ex)
            {
                _logger.LogError("Nightscout fetching failed or received incorrect format. {0}", ex);
            }
            finally
            {
                request.Dispose();
            }

            return(results.OrderBy(a => a.DateTimeUTC).ToList());
        }
Exemple #5
0
        private async Task CreateIcon()
        {
            GlucoseResult = await _fetchService.GetLatestReading().ConfigureAwait(false);

            LogResultToDb(GlucoseResult);
            trayIcon.Text = GetGlucoseMessage(GlucoseResult);
            _iconService.CreateTextIcon(GlucoseResult, trayIcon);
        }
Exemple #6
0
        private void LogResultToDb(GlucoseResult result)
        {
            if (_context.GlucoseResults.Any(g => g.DateTimeUTC == result.DateTimeUTC && !result.WasError && g.MgValue == result.MgValue))
            {
                return;
            }

            _context.GlucoseResults.Add(result);
            _context.SaveChanges();
        }
Exemple #7
0
        private async Task CheckForMissingReadings()
        {
            if (_options.FetchMethod != FetchMethod.NightscoutApi)
            {
                return;
            }

            var newestExistingRecord = _context.GlucoseResults.OrderByDescending(a => a.DateTimeUTC).FirstOrDefault();

            if (newestExistingRecord == null)
            {
                if (MessageBox.Show("Do you want to import readings from NightScout?\r\n\r\n(Warning this may take some time.)", "GlucoseTrayCore : No Readings found in local database.", MessageBoxButtons.YesNo) == DialogResult.No)
                {
                    return;
                }

                newestExistingRecord = new GlucoseResult()
                {
                    DateTimeUTC = DateTime.UtcNow.AddYears(-100)
                };
            }

            Stopwatch sw = new Stopwatch();

            sw.Start();
            var missingResults = await _fetchService.FetchMissingReadings(newestExistingRecord.DateTimeUTC);

            sw.Stop();
            int count = missingResults.Count();

            if (count > 0)
            {
                if (count == 1)
                {
                    _logger.LogWarning($"Found 1 reading recorded at {missingResults[0].DateTimeUTC} UTC since last database record at {newestExistingRecord.DateTimeUTC} UTC ");
                }
                else
                {
                    _logger.LogWarning($"Found {count} readings between {missingResults[0].DateTimeUTC} and {missingResults[count-1].DateTimeUTC} UTC since last database record at {newestExistingRecord.DateTimeUTC} UTC. Retrieving them took {sw.Elapsed.TotalSeconds:#,##0.##} seconds");
                }

                sw.Restart();
                _context.GlucoseResults.AddRange(missingResults);   // None of these records will be in the database, so just add them all now.
                _context.SaveChanges();
                sw.Stop();
                if (sw.Elapsed.TotalSeconds > 5)
                {
                    _logger.LogWarning($"Saving {missingResults.Count()} records took {sw.Elapsed.TotalSeconds:#,##0.##} seconds");
                }
            }
        }
Exemple #8
0
        private async Task CheckForMissingReadings()
        {
            if (_options.CurrentValue.FetchMethod != FetchMethod.NightscoutApi)
            {
                return;
            }

            GlucoseResult = _context.GlucoseResults.OrderByDescending(a => a.DateTimeUTC).FirstOrDefault();

            if (GlucoseResult == null && MessageBox.Show("Do you want to import readings from NightScout?\r\n\r\n(Warning this may take some time.)", "GlucoseTrayCore : No Readings found in local database.", MessageBoxButtons.YesNo) == DialogResult.No)
            {
                return;
            }

            DateTime startDate = GlucoseResult?.DateTimeUTC ?? DateTime.UtcNow.AddYears(-100);

            var sw = new Stopwatch();

            sw.Start();
            var missingResults = await _fetchService.GetLatestReadings(startDate).ConfigureAwait(false);

            sw.Stop();
            int count = missingResults.Count;

            if (count > 0)
            {
                var sinceMessage = (GlucoseResult != null) ? $" since last database record at {GlucoseResult.DateTimeUTC} UTC" : "";

                if (count == 1)
                {
                    _logger.LogWarning($"Starting Up : Found 1 reading recorded at {missingResults[0].DateTimeUTC} UTC{sinceMessage}.");
                }
                else
                {
                    _logger.LogWarning($"Found {count} readings between {missingResults[0].DateTimeUTC} and {missingResults[count - 1].DateTimeUTC} UTC{sinceMessage}. Retrieving them took {sw.Elapsed.TotalSeconds:#,##0.##} seconds");
                }

                sw.Restart();
                _context.GlucoseResults.AddRange(missingResults);   // None of these records will be in the database, so just add them all now.
                _context.SaveChanges();
                sw.Stop();
                if (sw.Elapsed.TotalSeconds > 5)
                {
                    _logger.LogWarning($"Saving {missingResults.Count()} records took {sw.Elapsed.TotalSeconds:#,##0.##} seconds");
                }

                GlucoseResult = missingResults.Last();
            }
        }
Exemple #9
0
        private async Task <GlucoseResult> GetFetchResultFromDexcom(GlucoseResult fetchResult)
        {
            var host = _options.DexcomServer switch
            {
                DexcomServerLocation.DexcomShare1 => "share1.dexcom.com",
                DexcomServerLocation.DexcomShare2 => "share2.dexcom.com",
                DexcomServerLocation.DexcomInternational => "shareous1.dexcom.com",
                _ => "share1.dexcom.com",
            };

            // Get Session Id
            var request = new HttpRequestMessage(HttpMethod.Post, new Uri($"https://{host}/ShareWebServices/Services/General/LoginPublisherAccountByName"))
            {
                Content = new StringContent("{\"accountName\":\"" + _options.DexcomUsername + "\"," +
                                            "\"applicationId\":\"d8665ade-9673-4e27-9ff6-92db4ce13d13\"," +
                                            "\"password\":\"" + _options.DexcomPassword + "\"}", Encoding.UTF8, "application/json")
            };

            var client = _httpClientFactory.CreateClient();

            try
            {
                var response = await client.SendAsync(request).ConfigureAwait(false);

                var sessionId = (await response.Content.ReadAsStringAsync().ConfigureAwait(false)).Replace("\"", "");
                request = new HttpRequestMessage(HttpMethod.Post, new Uri($"https://{host}/ShareWebServices/Services/Publisher/ReadPublisherLatestGlucoseValues?sessionId={sessionId}&minutes=1440&maxCount=1"));
                var result = JsonSerializer.Deserialize <List <DexcomResult> >(await(await client.SendAsync(request).ConfigureAwait(false)).Content.ReadAsStringAsync().ConfigureAwait(false)).First();

                var unixTime = string.Join("", result.ST.Where(char.IsDigit));
                var trend    = result.Trend;

                CalculateValues(fetchResult, result.Value);
                fetchResult.DateTimeUTC = !string.IsNullOrWhiteSpace(unixTime) ? DateTimeOffset.FromUnixTimeMilliseconds(long.Parse(unixTime)).UtcDateTime : DateTime.MinValue;
                fetchResult.Trend       = (TrendResult)trend;
                response.Dispose();
            }
            catch (Exception ex)
            {
                _logger.LogError("Dexcom fetching failed or received incorrect format. {0}", ex);
                fetchResult = GetDefaultFetchResult();
            }
            finally
            {
                request.Dispose();
            }

            fetchResult.Source = FetchMethod.DexcomShare;
            return(fetchResult);
        }
Exemple #10
0
 private void CalculateValues(GlucoseResult result, double value)
 {
     // 25 MMOL is > 540 MG, most readers wont go below 40 or above 400.
     // Catch any full value MMOL readings that may be perfect integers that are delivered without a '.', i.e., 7.0 coming in as just 7
     if (value.ToString().Contains(".") || value <= 30)
     {
         result.MmolValue = value;
         result.MgValue   = Convert.ToInt32(value *= 18);
     }
     else
     {
         result.MgValue   = Convert.ToInt32(value);
         result.MmolValue = value /= 18;
     }
 }
Exemple #11
0
 private void CalculateValues(GlucoseResult result, double value)
 {
     if (value == 0)
     {
         result.MmolValue = value;
         result.MgValue   = Convert.ToInt32(value);
     }
     else if (_options.CurrentValue.IsServerDataUnitTypeMmol)
     {
         result.MmolValue = value;
         result.MgValue   = Convert.ToInt32(value * 18);
     }
     else
     {
         result.MmolValue = value / 18;
         result.MgValue   = Convert.ToInt32(value);
     }
     result.IsCriticalLow = IsCriticalLow(result);
 }
Exemple #12
0
        private async Task <GlucoseResult> GetFetchResultFromNightscout(GlucoseResult fetchResult)
        {
            var request = new HttpRequestMessage(HttpMethod.Get, new Uri($"{_options.NightscoutUrl}/api/v1/entries/sgv?count=1" + (!string.IsNullOrWhiteSpace(_options.AccessToken) ? $"&token={_options.AccessToken}" : "")));

            request.Headers.Accept.Add(new System.Net.Http.Headers.MediaTypeWithQualityHeaderValue("application/json"));

            var client = _httpClientFactory.CreateClient();

            try
            {
                var response = await client.SendAsync(request).ConfigureAwait(false);

                var result = await response.Content.ReadAsStringAsync().ConfigureAwait(false);

                var content = JsonSerializer.Deserialize <List <NightScoutResult> >(result).FirstOrDefault();
                CalculateValues(fetchResult, content.sgv);
                fetchResult.DateTimeUTC = DateTime.Parse(content.dateString).ToUniversalTime();
                fetchResult.Trend       = content.direction.GetTrend();
                if (fetchResult.Trend == TrendResult.Unknown)
                {
                    _logger.LogWarning($"Un-expected value for direction/Trend {content.direction}");
                }

                response.Dispose();
            }
            catch (Exception ex)
            {
                _logger.LogError("Nightscout fetching failed or received incorrect format. {0}", ex);
                fetchResult = GetDefaultFetchResult();
            }
            finally
            {
                request.Dispose();
            }

            fetchResult.Source = FetchMethod.NightscoutApi;
            return(fetchResult);
        }
 public static bool IsStale(this GlucoseResult fetchResult, int minutes) => (System.DateTime.Now.ToUniversalTime() - fetchResult.DateTimeUTC).TotalMinutes > minutes;
Exemple #14
0
 private bool IsCriticalLow(GlucoseResult result) =>
 (_options.CurrentValue.GlucoseUnit == GlucoseUnitType.MMOL && result.MmolValue <= _options.CurrentValue.CriticalLowBg) ||
 (_options.CurrentValue.GlucoseUnit == GlucoseUnitType.MG && result.MgValue <= _options.CurrentValue.CriticalLowBg);
        public static bool IsStale(this GlucoseResult fetchResult, int minutes)
        {
            var ts = System.DateTime.Now.ToUniversalTime() - fetchResult.DateTimeUTC;

            return(ts.TotalMinutes > minutes);
        }
Exemple #16
0
 private string GetGlucoseMessage(GlucoseResult result) => $"{result.GetFormattedStringValue(_options.CurrentValue.GlucoseUnit)}   {result.DateTimeUTC.ToLocalTime().ToLongTimeString()}  {result.Trend.GetTrendArrow()}{result.StaleMessage(_options.CurrentValue.StaleResultsThreshold)}";
        public static string StaleMessage(this GlucoseResult fetchResult, int minutes)
        {
            var ts = System.DateTime.Now.ToUniversalTime() - fetchResult.DateTimeUTC;

            return(ts.TotalMinutes > minutes ? $"\r\n{ts.TotalMinutes:#} minutes ago" : string.Empty);
        }
 public static string GetFormattedStringValue(this GlucoseResult fetchResult, GlucoseUnitType type) => type == GlucoseUnitType.MG ? fetchResult.MgValue.ToString() : fetchResult.MmolValue.ToString("0.0");