diff --git a/data/blood/glucose/glucose.go b/data/blood/glucose/glucose.go index f91f0d671..e1536ff32 100644 --- a/data/blood/glucose/glucose.go +++ b/data/blood/glucose/glucose.go @@ -2,6 +2,7 @@ package glucose import ( "math" + "strings" "github.com/tidepool-org/platform/pointer" ) @@ -82,6 +83,24 @@ func NormalizeValueForUnits(value *float64, units *string) *float64 { return value } +func MmolLRounded(value float64, units string) float64 { + mmolLValue := 0.0 + if strings.EqualFold(units, MmolL) { + mmolLValue = value + } else { + normalized := NormalizeValueForUnits(&value, &units) + mmolLValue = *normalized + } + return math.Round(mmolLValue*10) / 10 +} + +func MgdLRounded(value float64, units string) int { + if strings.EqualFold(units, MmolL) { + value *= MmolLToMgdLConversionFactor + } + return int(math.Round(value)) +} + func ValueRangeForRateUnits(rateUnits *string) (float64, float64) { if rateUnits != nil { switch *rateUnits { diff --git a/data/blood/glucose/glucose_test.go b/data/blood/glucose/glucose_test.go index 319940730..f770b32e0 100644 --- a/data/blood/glucose/glucose_test.go +++ b/data/blood/glucose/glucose_test.go @@ -218,4 +218,39 @@ var _ = Describe("Glucose", func() { } }) }) + + Describe("MgdLRounded", func() { + It("rounds to 0 decimal places", func() { + got := glucose.MgdLRounded(3.0, "mmol/L") + Expect(got).To(Equal(54)) + got = glucose.MgdLRounded(3.9, "mmol/L") + Expect(got).To(Equal(70)) + got = glucose.MgdLRounded(10, "mmol/L") + Expect(got).To(Equal(180)) + got = glucose.MgdLRounded(13.9, "mmol/L") + Expect(got).To(Equal(250)) + got = glucose.MgdLRounded(19.4, "mmol/L") + Expect(got).To(Equal(350)) + + got = glucose.MgdLRounded(54.49999999999999, "mg/dL") + Expect(got).To(Equal(54)) + got = glucose.MgdLRounded(54.5, "mg/dL") + Expect(got).To(Equal(55)) + }) + }) + + Describe("MmolLRounded", func() { + It("rounds to 1 decimal place", func() { + got := glucose.MmolLRounded(54, "mg/dL") + Expect(got).To(Equal(3.0)) + got = glucose.MmolLRounded(70, "mg/dL") + Expect(got).To(Equal(3.9)) + got = glucose.MmolLRounded(180, "mg/dL") + Expect(got).To(Equal(10.0)) + got = glucose.MmolLRounded(250, "mg/dL") + Expect(got).To(Equal(13.9)) + got = glucose.MmolLRounded(350, "mg/dL") + Expect(got).To(Equal(19.4)) + }) + }) }) diff --git a/summary/types/glucose.go b/summary/types/glucose.go index 06e9fd1c0..bceee7a1c 100644 --- a/summary/types/glucose.go +++ b/summary/types/glucose.go @@ -2,7 +2,6 @@ package types import ( "context" - "errors" "fmt" "math" "strconv" @@ -15,6 +14,7 @@ import ( "github.com/tidepool-org/platform/data/blood/glucose" "github.com/tidepool-org/platform/data/types/blood/glucose/continuous" "github.com/tidepool-org/platform/data/types/blood/glucose/selfmonitored" + "github.com/tidepool-org/platform/errors" ) const ( @@ -24,6 +24,8 @@ const ( type Glucose interface { NormalizedValue() float64 + Value() float64 + Units() string Type() string Time() *time.Time CreatedTime() *time.Time @@ -53,6 +55,20 @@ func (s SelfMonitoredGlucoseAdapter) NormalizedValue() float64 { return *glucose.NormalizeValueForUnits(s.datum.Value, s.datum.Units) } +func (s SelfMonitoredGlucoseAdapter) Units() string { + if s.datum == nil || s.datum.Units == nil { + return "" + } + return *s.datum.Units +} + +func (s SelfMonitoredGlucoseAdapter) Value() float64 { + if s.datum == nil || s.datum.Value == nil { + return 0 + } + return *s.datum.Value +} + func (s SelfMonitoredGlucoseAdapter) Type() string { return s.datum.GetType() } @@ -79,6 +95,20 @@ func (c ContinuousGlucoseAdapter) NormalizedValue() float64 { return *glucose.NormalizeValueForUnits(c.datum.Value, c.datum.Units) } +func (c ContinuousGlucoseAdapter) Units() string { + if c.datum == nil || c.datum.Units == nil { + return "" + } + return *c.datum.Units +} + +func (c ContinuousGlucoseAdapter) Value() float64 { + if c.datum == nil || c.datum.Value == nil { + return 0 + } + return *c.datum.Value +} + func (c ContinuousGlucoseAdapter) Type() string { return c.datum.GetType() } @@ -262,24 +292,38 @@ func (rs *GlucoseRanges) Finalize(days int) { } } -func (rs *GlucoseRanges) Update(record Glucose) { - normalizedValue := record.NormalizedValue() +const ( + veryLowBloodGlucoseMgdL int = 54 + lowBloodGlucoseMgdL int = 70 + highBloodGlucoseMgdL int = 180 + veryHighBloodGlucoseMgdL int = 250 + extremeHighBloodGlucoseMgdL int = 350 +) - if normalizedValue < veryLowBloodGlucose { +var ( + veryLowBloodGlucose = glucose.MmolLRounded(float64(veryLowBloodGlucoseMgdL), glucose.MmolL) + lowBloodGlucose = glucose.MmolLRounded(float64(lowBloodGlucoseMgdL), glucose.MmolL) + highBloodGlucose = glucose.MmolLRounded(float64(highBloodGlucoseMgdL), glucose.MmolL) + veryHighBloodGlucose = glucose.MmolLRounded(float64(veryHighBloodGlucoseMgdL), glucose.MmolL) +) + +func (rs *GlucoseRanges) Update(record Glucose) { + mgdLRounded := glucose.MgdLRounded(record.Value(), record.Units()) + if mgdLRounded < veryLowBloodGlucoseMgdL { rs.VeryLow.Update(record) rs.AnyLow.Update(record) - } else if normalizedValue > veryHighBloodGlucose { + } else if mgdLRounded > veryHighBloodGlucoseMgdL { rs.VeryHigh.Update(record) rs.AnyHigh.Update(record) // VeryHigh is inclusive of extreme high, this is intentional - if normalizedValue >= extremeHighBloodGlucose { + if mgdLRounded >= extremeHighBloodGlucoseMgdL { rs.ExtremeHigh.Update(record) } - } else if normalizedValue < lowBloodGlucose { + } else if mgdLRounded < lowBloodGlucoseMgdL { rs.Low.Update(record) rs.AnyLow.Update(record) - } else if normalizedValue > highBloodGlucose { + } else if mgdLRounded > highBloodGlucoseMgdL { rs.AnyHigh.Update(record) rs.High.Update(record) } else { diff --git a/summary/types/summary.go b/summary/types/summary.go index 4e4f3bd39..f99486447 100644 --- a/summary/types/summary.go +++ b/summary/types/summary.go @@ -20,12 +20,7 @@ const ( SummaryTypeContinuous = "con" SchemaVersion = 6 - lowBloodGlucose = 3.9 - veryLowBloodGlucose = 3.0 - highBloodGlucose = 10.0 - veryHighBloodGlucose = 13.9 - extremeHighBloodGlucose = 19.4 - HoursAgoToKeep = 60 * 24 + HoursAgoToKeep = 60 * 24 OutdatedReasonUploadCompleted = "UPLOAD_COMPLETED" OutdatedReasonDataAdded = "DATA_ADDED"