From 1da7291ece76b7b7e8b38e17f6cdea558529d4de Mon Sep 17 00:00:00 2001 From: Peter Ina Date: Tue, 25 Aug 2015 20:19:50 -0400 Subject: [PATCH 1/6] Mmol support Adding mmol support. App detects units from the server and updates all relevant items with the correct units. --- Nightscouter/Localizable.strings | 4 +- Nightscouter/SiteDetailViewController.swift | 15 +++-- Nightscouter/SiteTableViewCell.swift | 19 ++++-- .../TestHarnessForCompassViewController.swift | 2 +- .../Extensions/CompassControl+Convience.swift | 11 +++- .../Extensions/Double+Extension.swift | 60 +++++++++++++++++++ .../Extensions/Int+Extensions.swift | 24 -------- .../Extensions/String+Extensions.swift | 16 ++++- NightscouterKit/Models/Entry.swift | 60 ++++++++++--------- .../Models/ServerConfiguration.swift | 49 ++++++++------- NightscouterKit/Models/WatchEntry.swift | 23 ++++--- .../SiteNSNowTableViewCell.swift | 17 +++++- 12 files changed, 201 insertions(+), 99 deletions(-) delete mode 100644 NightscouterKit/Extensions/Int+Extensions.swift diff --git a/Nightscouter/Localizable.strings b/Nightscouter/Localizable.strings index e580a66..603a90f 100644 --- a/Nightscouter/Localizable.strings +++ b/Nightscouter/Localizable.strings @@ -25,4 +25,6 @@ "uiAlertScreenOverrideTitle" = "Prevent Screen from Locking?"; "uiAlertScreenOverrideMessage" = "Selecting Yes will prevent the application from going to sleep and locking while viewing this site."; -"sgvLowString" = "Low"; \ No newline at end of file +"sgvLowString" = "Low"; + +"nightscoutTitleString" = "Nightscouter"; \ No newline at end of file diff --git a/Nightscouter/SiteDetailViewController.swift b/Nightscouter/SiteDetailViewController.swift index a25a4cf..34fd1b2 100644 --- a/Nightscouter/SiteDetailViewController.swift +++ b/Nightscouter/SiteDetailViewController.swift @@ -86,7 +86,8 @@ extension SiteDetailViewController { let updateData = "updateData(\(self.data))" if let configuration = site?.configuration { - let updateUnits = "updateUnits(\(configuration.displayUnits.rawValue))" + + let updateUnits = "updateUnits(\(configuration.displayUnits.hashValue))" webView.stringByEvaluatingJavaScriptFromString(updateUnits) } webView.stringByEvaluatingJavaScriptFromString(updateData) @@ -167,9 +168,15 @@ extension SiteDetailViewController { // Raw label if let rawValue = watchEntry.raw { - let color = colorForDesiredColorState(configuration.boundedColorForGlucoseValue(Int(rawValue))) + let color = colorForDesiredColorState(configuration.boundedColorForGlucoseValue(rawValue)) + + var raw = "\(rawValue.formattedForMgdl)" + if configuration.displayUnits == .Mmol { + raw = rawValue.formattedForMmol + } + self.siteRawLabel?.textColor = color - self.siteRawLabel?.text = "\(NSNumberFormatter.localizedStringFromNumber(rawValue, numberStyle: NSNumberFormatterStyle.DecimalStyle)) : \(sgv.noise)" + self.siteRawLabel?.text = "\(raw) : \(sgv.noise)" } let timeAgo = watchEntry.date.timeIntervalSinceNow @@ -195,7 +202,7 @@ extension SiteDetailViewController { if let entries = entries { for entry in entries { if let sgv = entry.sgv { - if (sgv.sgv > Constants.EntryCount.LowerLimitForValidSGV) { + if (sgv.sgv > Double(Constants.EntryCount.LowerLimitForValidSGV)) { self.data.append(entry.jsonForChart) } } diff --git a/Nightscouter/SiteTableViewCell.swift b/Nightscouter/SiteTableViewCell.swift index eb4611c..b7012ff 100644 --- a/Nightscouter/SiteTableViewCell.swift +++ b/Nightscouter/SiteTableViewCell.swift @@ -63,16 +63,27 @@ class SiteTableViewCell: UITableViewCell { if let sgvValue = watchEntry.sgv { - let color = colorForDesiredColorState(site.configuration!.boundedColorForGlucoseValue(sgvValue.sgv)) + var boundedColor = configuration.boundedColorForGlucoseValue(sgvValue.sgv) + if configuration.displayUnits == .Mmol { + boundedColor = configuration.boundedColorForGlucoseValue(sgvValue.sgv.toMgdl) + } + let color = colorForDesiredColorState(boundedColor) + siteColorBlockView.backgroundColor = color if let enabledOptions = configuration.enabledOptions { let rawEnabled = contains(enabledOptions, EnabledOptions.rawbg) if rawEnabled { if let rawValue = watchEntry.raw { - let color = colorForDesiredColorState(configuration.boundedColorForGlucoseValue(Int(rawValue))) + let color = colorForDesiredColorState(configuration.boundedColorForGlucoseValue(rawValue)) + + var raw = "\(rawValue.formattedForMgdl)" + if configuration.displayUnits == .Mmol { + raw = rawValue.formattedForMmol + } + siteRawLabel?.textColor = color - siteRawLabel.text = "\(NSNumberFormatter.localizedStringFromNumber(rawValue, numberStyle: .DecimalStyle)) : \(sgvValue.noise)" + siteRawLabel.text = "\(raw) : \(sgvValue.noise)" } } else { siteRawHeader.hidden = true @@ -132,7 +143,7 @@ class SiteTableViewCell: UITableViewCell { siteColorBlockView.backgroundColor = siteCompassControl.color siteLastReadingLabel.text = Constants.LocalizedString.tableViewCellLoading.localized siteLastReadingLabel.textColor = Theme.Color.labelTextColor - + siteRawHeader.hidden = false siteRawLabel.hidden = false siteRawLabel.textColor = Theme.Color.labelTextColor diff --git a/Nightscouter/TestHarnessForCompassViewController.swift b/Nightscouter/TestHarnessForCompassViewController.swift index 9f5eedb..3002701 100644 --- a/Nightscouter/TestHarnessForCompassViewController.swift +++ b/Nightscouter/TestHarnessForCompassViewController.swift @@ -98,7 +98,7 @@ extension TestHarnessForCompassViewController { func updateDelta(){ print("newValue: \(newValue); oldValue: \(oldValue); delta: \(newValue - oldValue)") - let deltaValue = newValue - oldValue + let deltaValue = Double(newValue - oldValue) compassControlView.delta = "\(deltaValue.formattedForBGDelta) " + bgUnits } diff --git a/NightscouterKit/Extensions/CompassControl+Convience.swift b/NightscouterKit/Extensions/CompassControl+Convience.swift index 0571bbd..fc6130b 100644 --- a/NightscouterKit/Extensions/CompassControl+Convience.swift +++ b/NightscouterKit/Extensions/CompassControl+Convience.swift @@ -10,7 +10,7 @@ import UIKit public extension CompassControl { - func configure(sgvText: String, color: UIColor, direction: Direction, bgdelta: Int, units: String) -> Void { + func configure(sgvText: String, color: UIColor, direction: Direction, bgdelta: Double, units: String) -> Void { self.sgvText = sgvText self.color = color self.direction = direction @@ -20,11 +20,16 @@ public extension CompassControl { public func configureWith(site: Site){ if let configuration: ServerConfiguration = site.configuration, watch: WatchEntry = site.watchEntry, sgv: SensorGlucoseValue = watch.sgv { - let color = colorForDesiredColorState(configuration.boundedColorForGlucoseValue(sgv.sgv)) + var boundedColor = configuration.boundedColorForGlucoseValue(sgv.sgv) var units: Units = configuration.displayUnits + if units == .Mmol { + boundedColor = configuration.boundedColorForGlucoseValue(sgv.sgv.toMgdl) + } - configure(sgv.sgvString, color: color, direction: sgv.direction, bgdelta: watch.bgdelta, units: units.rawValue) + let color = colorForDesiredColorState(boundedColor) + + configure(sgv.sgvString, color: color, direction: sgv.direction, bgdelta: watch.bgdelta, units: units.description) } } diff --git a/NightscouterKit/Extensions/Double+Extension.swift b/NightscouterKit/Extensions/Double+Extension.swift index 4c74456..4e1d1cd 100644 --- a/NightscouterKit/Extensions/Double+Extension.swift +++ b/NightscouterKit/Extensions/Double+Extension.swift @@ -21,5 +21,65 @@ public extension Double { let date = NSDate(timeIntervalSince1970:millisecondsToSecondsTimeInterval()) return date } + +} + +public extension Double { + public var toMmol: Double { + get{ + return (self / 18) + } + } + + public var toMgdl: Double { + get{ + return self * 18 + } + } + + internal var mgdlFormatter: NSNumberFormatter { + let numberFormat = NSNumberFormatter() + numberFormat.numberStyle = .NoStyle + + return numberFormat + } + + public var formattedForMgdl: String { + return self.mgdlFormatter.stringFromNumber(self)! + } + + internal var mmolFormatter: NSNumberFormatter { + let numberFormat = NSNumberFormatter() + numberFormat.numberStyle = .DecimalStyle + numberFormat.minimumFractionDigits = 1 + numberFormat.maximumFractionDigits = 1 + numberFormat.secondaryGroupingSize = 1 + + return numberFormat + } + + public var formattedForMmol: String { + return self.mmolFormatter.stringFromNumber(self.toMmol)! + } +} + +public extension Double { + internal var bgDeltaFormatter: NSNumberFormatter { + let numberFormat = NSNumberFormatter() + numberFormat.numberStyle = .DecimalStyle + numberFormat.positivePrefix = numberFormat.plusSign + numberFormat.negativePrefix = numberFormat.minusSign + + return numberFormat + } + + public var formattedForBGDelta: String { + return self.bgDeltaFormatter.stringFromNumber(self)! + } } +public extension Double { + var isInteger: Bool { + return rint(self) == self + } +} \ No newline at end of file diff --git a/NightscouterKit/Extensions/Int+Extensions.swift b/NightscouterKit/Extensions/Int+Extensions.swift deleted file mode 100644 index fada3cd..0000000 --- a/NightscouterKit/Extensions/Int+Extensions.swift +++ /dev/null @@ -1,24 +0,0 @@ -// -// Int+Extensions.swift -// Nightscouter -// -// Created by Peter Ina on 7/15/15. -// Copyright (c) 2015 Peter Ina. All rights reserved. -// - -import Foundation - -public extension Int { - internal var bgDeltaFormatter: NSNumberFormatter { - let numberFormat = NSNumberFormatter() - numberFormat.numberStyle = .NoStyle - numberFormat.positivePrefix = numberFormat.plusSign - numberFormat.negativePrefix = numberFormat.minusSign - - return numberFormat - } - - public var formattedForBGDelta: String { - return self.bgDeltaFormatter.stringFromNumber(self)! - } -} \ No newline at end of file diff --git a/NightscouterKit/Extensions/String+Extensions.swift b/NightscouterKit/Extensions/String+Extensions.swift index 8a7bd54..5e106a9 100644 --- a/NightscouterKit/Extensions/String+Extensions.swift +++ b/NightscouterKit/Extensions/String+Extensions.swift @@ -8,18 +8,19 @@ import Foundation -extension String { +public extension String { public var localized: String { return NSLocalizedString(self, tableName: nil, bundle: NSBundle.mainBundle(), value: "", comment: "") } public func localizedWithComment(comment:String) -> String { return NSLocalizedString(self, tableName: nil, bundle: NSBundle.mainBundle(), value: "", comment: comment) } - +} + +public extension String { public var versions: [String] { return self.componentsSeparatedByString(".") } - public var majorVersion: Int { return versions.first!.toInt()! } @@ -29,4 +30,13 @@ extension String { public var buildVersion: Int { return versions.last!.toInt()! } +} + +public extension String { + public var floatValue: Float? { + return NSNumberFormatter().numberFromString(self)?.floatValue //(self as NSString).floatValue + } + public var toDouble: Double? { + return NSNumberFormatter().numberFromString(self)?.doubleValue + } } \ No newline at end of file diff --git a/NightscouterKit/Models/Entry.swift b/NightscouterKit/Models/Entry.swift index 8e8eeaf..155c4a7 100644 --- a/NightscouterKit/Models/Entry.swift +++ b/NightscouterKit/Models/Entry.swift @@ -112,21 +112,23 @@ public struct Calibration { // type = sgv public struct SensorGlucoseValue { - public let sgv: Int + public let sgv: Double public let direction: Direction public let filtered: Int public let unfiltered: Int public let rssi: Int public let noise: Noise - enum ReservedValues: Int { + enum ReservedValues: Double { case NoGlucose=0, SensoreNotActive=1, MinimalDeviation=2, NoAntenna=3, SensorNotCalibrated=5, CountsDeviation=6, AbsoluteDeviation=9, PowerDeviation=10, BadRF=12, HupHolland=17 } public var sgvString: String { // Consider moving this to a Printable or similar protocal? get { - if sgv <= 29 { - let special:ReservedValues = ReservedValues(rawValue: sgv)! + + let mgdlSgvValue: Double = sgv.isInteger ? sgv : sgv.toMgdl + + if let special:ReservedValues = ReservedValues(rawValue: mgdlSgvValue) { switch (special) { case .NoGlucose: return "?NG" @@ -151,11 +153,11 @@ public struct SensorGlucoseValue { default: return "✖" } - } else if sgv >= 30 && sgv < 40 { + } + if sgv >= 30 && sgv < 40 { return NSLocalizedString("sgvLowString", tableName: nil, bundle: NSBundle.mainBundle(), value: "", comment: "Label used to indicate a very low blood sugar.") - } else { - return NSNumberFormatter.localizedStringFromNumber(self.sgv, numberStyle: NSNumberFormatterStyle.NoStyle) } + return NSNumberFormatter.localizedStringFromNumber(self.sgv, numberStyle: NSNumberFormatterStyle.DecimalStyle) } } } @@ -187,8 +189,8 @@ public class Entry: NSObject { var color: String = "white" let typeString: Type = entry.type! - switch(typeString) - { + + switch(typeString) { case .sgv: color = "grey" case .mbg: @@ -200,6 +202,7 @@ public class Entry: NSObject { default: color = "grey" } + let nsDateFormatter = NSDateFormatter() // nsDateFormatter.dateFormat = "EEE MMM d yyy HH:mm:ss OOOO (zzz)" nsDateFormatter.dateFormat = "EEE MMM d HH:mm:ss zzz yyy" @@ -220,13 +223,11 @@ public class Entry: NSObject { return String(str!) } - public init(identifier: String, date: NSDate, device: String) {//, type: Type) { + public init(identifier: String, date: NSDate, device: String) { self.idString = identifier self.date = date self.device = device - // self.type = type } - } struct EntryPropertyKey { @@ -296,7 +297,7 @@ public extension Entry { } } - if let sgv = dict[EntryPropertyKey.sgvKey] as? Int { + if let sgv = dict[EntryPropertyKey.sgvKey] as? Double { sgvItem?.sgv = sgv } @@ -349,11 +350,11 @@ public extension Entry { #endif NSError(domain: NightscoutModelErrorDomain, code: -11, userInfo: ["description": errorString]) - if let sgv = dict[EntryPropertyKey.sgvKey] as? String { + if let sgv = dict[EntryPropertyKey.sgvKey] as? Double { if let directionString = dict[EntryPropertyKey.directionKey] as? String { if let direction = Direction(rawValue: directionString) { - let sgvInt: Int = Int(sgv.toInt()!) - let sgvValue = SensorGlucoseValue(sgv: sgvInt, direction: direction, filtered: 0, unfiltered: 0, rssi: 0, noise: .None) + // let sgvInt: Int = Int(sgv.toInt()!) + let sgvValue = SensorGlucoseValue(sgv: sgv, direction: direction, filtered: 0, unfiltered: 0, rssi: 0, noise: Noise.None) sgvItem = sgvValue } } @@ -372,19 +373,21 @@ public extension Entry { if (sgvItem != nil) && (calItem != nil){ self.raw = rawIsigToRawBg(sgvItem!, calValue: calItem!) } - } - - // TODO: Is tihs the best it can be? Should it be a cumputed property? - func rawIsigToRawBg(sgValue: SensorGlucoseValue, calValue: Calibration) -> Double { +} + +// TODO: fix this! +// TODO: Is tihs the best it can be? Should it be a cumputed property? +public extension Entry { + public func rawIsigToRawBg(sgValue: SensorGlucoseValue, calValue: Calibration) -> Double { var raw: Double = 0 + let unfiltered = Double(sgValue.unfiltered) + let filtered = Double(sgValue.filtered) + let sgv: Double = sgValue.sgv.isInteger ? sgValue.sgv : sgValue.sgv.toMgdl let slope = calValue.slope - let unfiltered: Double = Double(sgValue.unfiltered) - let filtered: Double = Double(sgValue.filtered) - let sgv: Double = Double(sgValue.sgv) - let scale: Double = Double(calValue.scale) + let scale = calValue.scale let intercept = calValue.intercept if (slope == 0 || unfiltered == 0 || scale == 0) { @@ -392,8 +395,8 @@ public extension Entry { } else if (filtered == 0 || sgv < 40) { raw = scale * (unfiltered - intercept) / slope } else { - let ratioCalc1 = scale * (filtered - intercept) / slope - let ratio = ratioCalc1 / sgv + let ratioCalc = scale * (filtered - intercept) / slope + let ratio = ratioCalc / sgv //FIXME: there is divid by zero happining here... need to recheck the math. // Fixed but could it be cleaner? @@ -401,7 +404,6 @@ public extension Entry { raw = rawCalc / ratio } - return round(Double(raw)) + return sgValue.sgv.isInteger ? round(raw) : raw } - -} +} \ No newline at end of file diff --git a/NightscouterKit/Models/ServerConfiguration.swift b/NightscouterKit/Models/ServerConfiguration.swift index aab9879..e798d1c 100644 --- a/NightscouterKit/Models/ServerConfiguration.swift +++ b/NightscouterKit/Models/ServerConfiguration.swift @@ -28,10 +28,15 @@ public enum EnabledOptions: String, Printable { public enum Units: String, Printable { case Mgdl = "mg/dl" - case Mmoll = "mmol/L" + case Mmol = "mmol" public var description: String { - return self.rawValue + switch self { + case .Mgdl: + return "mg/dL" + case .Mmol: + return "mmol/L" + } } } @@ -46,10 +51,10 @@ public enum RawBGMode: String, Printable { } public struct Threshold: Printable { - public let bg_high: Int - public let bg_low: Int - public let bg_target_bottom :Int - public let bg_target_top :Int + public let bg_high: Double + public let bg_low: Double + public let bg_target_bottom :Double + public let bg_target_top :Double public var description: String { let dict = ["bg_high": bg_high, "bg_low": bg_low, "bg_target_bottom": bg_target_bottom, "bg_target_top": bg_target_top] @@ -189,7 +194,7 @@ public struct ServerConfiguration: Printable { if let name = name { dict["name"] = name } - + return dict.description } } @@ -218,7 +223,7 @@ public extension ServerConfiguration { let unitsRootUnit = Units(rawValue: unitsRootString)! serverConfig.unitsRoot = unitsRootUnit } - + if let headString = root[ConfigurationPropertyKey.headKey] as? String { serverConfig.head = headString } @@ -277,10 +282,10 @@ public extension ServerConfiguration { var threasholdsThreshold: Threshold? if let thresholdsDict = jsonDictionary[ConfigurationPropertyKey.thresholdsKey] as? [String : AnyObject] { - let bg_high = thresholdsDict[ConfigurationPropertyKey.bg_highKey] as! Int - let bg_low = thresholdsDict[ConfigurationPropertyKey.bg_lowKey] as! Int - let bg_target_bottom = thresholdsDict[ConfigurationPropertyKey.bg_target_bottomKey] as! Int - let bg_target_top = thresholdsDict[ConfigurationPropertyKey.bg_target_topKey] as! Int + let bg_high = thresholdsDict[ConfigurationPropertyKey.bg_highKey] as! Double + let bg_low = thresholdsDict[ConfigurationPropertyKey.bg_lowKey] as! Double + let bg_target_bottom = thresholdsDict[ConfigurationPropertyKey.bg_target_bottomKey] as! Double + let bg_target_top = thresholdsDict[ConfigurationPropertyKey.bg_target_topKey] as! Double threasholdsThreshold = Threshold(bg_high: bg_high, bg_low: bg_low, bg_target_bottom: bg_target_bottom, bg_target_top: bg_target_top) } serverConfig.thresholds = threasholdsThreshold @@ -297,18 +302,21 @@ public enum DesiredColorState { // TODO: Should this be here? Maybe it shuld be a threshold extension. public extension ServerConfiguration { - public func boundedColorForGlucoseValue(value: Int) -> DesiredColorState { + public func boundedColorForGlucoseValue(mgdlSGV: Double) -> DesiredColorState { var color = DesiredColorState.Neutral + + var mgdlValue: Double = mgdlSGV + if let thresholds = self.thresholds { - if (value >= thresholds.bg_high) { + if (mgdlValue >= thresholds.bg_high) { color = .Alert - } else if (value > thresholds.bg_target_top && value < thresholds.bg_high) { + } else if (mgdlValue > thresholds.bg_target_top && mgdlValue < thresholds.bg_high) { color = .Warning - } else if (value >= thresholds.bg_target_bottom && value <= thresholds.bg_target_top) { + } else if (mgdlValue >= thresholds.bg_target_bottom && mgdlValue <= thresholds.bg_target_top) { color = .Positive - } else if (value < thresholds.bg_target_bottom && value > thresholds.bg_low) { + } else if (mgdlValue < thresholds.bg_target_bottom && mgdlValue > thresholds.bg_low) { color = .Warning - } else if (value <= thresholds.bg_low && value != 0) { + } else if (mgdlValue <= thresholds.bg_low && mgdlValue != 0) { color = .Alert } } @@ -344,7 +352,8 @@ public extension ServerConfiguration { } else if let name = name { return name } else { - return "Nightscout" + return NSLocalizedString("nightscoutTitleString", tableName: nil, bundle: NSBundle.mainBundle(), value: "", comment: "Label used to when we can't find a title for the website.") + } } @@ -357,4 +366,4 @@ public extension ServerConfiguration { return .Mgdl } } -} +} \ No newline at end of file diff --git a/NightscouterKit/Models/WatchEntry.swift b/NightscouterKit/Models/WatchEntry.swift index 7caad25..e290982 100644 --- a/NightscouterKit/Models/WatchEntry.swift +++ b/NightscouterKit/Models/WatchEntry.swift @@ -23,13 +23,19 @@ let WatchFaceDeviceValue = "watchFace" public class WatchEntry: Entry { public var now: NSDate - public var bgdelta: Int + public var bgdelta: Double public let battery: Int public var batteryString: String { get{ // Convert int from JSON into a proper precentge. var percentage = Float(battery)/100 - return "\(NSNumberFormatter.localizedStringFromNumber(percentage, numberStyle: NSNumberFormatterStyle.PercentStyle))" + + let numberFormatter: NSNumberFormatter = NSNumberFormatter() + numberFormatter.numberStyle = .PercentStyle + numberFormatter.zeroSymbol = "---%" + + return numberFormatter.stringFromNumber(percentage)! +// return "\(NSNumberFormatter.localizedStringFromNumber(percentage, numberStyle: NSNumberFormatterStyle.PercentStyle))" } } public var batteryColorState: DesiredColorState { @@ -41,7 +47,7 @@ public class WatchEntry: Entry { return DesiredColorState.Neutral } - public init(identifier: String, date: NSDate, device: String, now: NSDate, bgdelta: Int, battery: Int) { + public init(identifier: String, date: NSDate, device: String, now: NSDate, bgdelta: Double, battery: Int) { self.now = now self.bgdelta = bgdelta self.battery = battery @@ -55,7 +61,7 @@ public extension WatchEntry { var now: NSDate = NSDate() var date: NSDate = NSDate() var device: String = WatchFaceDeviceValue - var bgdelta: Int = 0 + var bgdelta: Double = 0 var battery: Int = 0 var sgvItem: SensorGlucoseValue? var calItem: Calibration? @@ -87,7 +93,7 @@ public extension WatchEntry { } if let sgvString = bgs[EntryPropertyKey.sgvKey] as? String { - sgvItem?.sgv = sgvString.toInt()! + sgvItem?.sgv = sgvString.toDouble! } if let filtered = bgs[EntryPropertyKey.filteredKey] as? Int { @@ -104,8 +110,11 @@ public extension WatchEntry { } } - if let bgdeltaInt = bgs[EntryPropertyKey.bgdeltaKey] as? Int { - bgdelta = bgdeltaInt + if let bgdeltaString = bgs[EntryPropertyKey.bgdeltaKey] as? String { + bgdelta = bgdeltaString.toDouble! + } + if let bgdeltaNumber = bgs[EntryPropertyKey.bgdeltaKey] as? Double { + bgdelta = bgdeltaNumber } if let batteryString = bgs[EntryPropertyKey.batteryKey] as? String { diff --git a/NightscouterToday/SiteNSNowTableViewCell.swift b/NightscouterToday/SiteNSNowTableViewCell.swift index bf10c3d..94294ea 100644 --- a/NightscouterToday/SiteNSNowTableViewCell.swift +++ b/NightscouterToday/SiteNSNowTableViewCell.swift @@ -75,16 +75,27 @@ class SiteNSNowTableViewCell: UITableViewCell { let rawEnabled = contains(enabledOptions, EnabledOptions.rawbg) if rawEnabled { if let rawValue = watchEntry.raw { - let color = colorForDesiredColorState(configuration.boundedColorForGlucoseValue(Int(rawValue))) + let color = colorForDesiredColorState(configuration.boundedColorForGlucoseValue(rawValue)) + + let numberFormatter = NSNumberFormatter() + var raw = rawValue + if configuration.displayUnits == .Mmol { + raw = rawValue.toMmol + numberFormatter.numberStyle = .DecimalStyle + numberFormatter.minimumFractionDigits = 1 + numberFormatter.maximumFractionDigits = 1 + numberFormatter.secondaryGroupingSize = 1 + } + siteRawLabel?.textColor = color - siteRawLabel.text = "\(NSNumberFormatter.localizedStringFromNumber(rawValue, numberStyle: .DecimalStyle)) : \(sgvValue.noise)" + siteRawLabel.text = "\(numberFormatter.stringFromNumber(raw)!) : \(sgvValue.noise)" } } else { siteRawHeader.hidden = true siteRawLabel.hidden = true } } - + let timeAgo = watchEntry.date.timeIntervalSinceNow let isStaleData = configuration.isDataStaleWith(interval: timeAgo) // siteCompassControl.shouldLookStale(look: isStaleData.warn) From f4c8c4dd97472c2d1ed7aa9f730b8e8435695fcd Mon Sep 17 00:00:00 2001 From: Peter Ina Date: Tue, 25 Aug 2015 20:21:09 -0400 Subject: [PATCH 2/6] Remove Int Extension --- Nightscouter.xcodeproj/project.pbxproj | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Nightscouter.xcodeproj/project.pbxproj b/Nightscouter.xcodeproj/project.pbxproj index a56e470..070249c 100644 --- a/Nightscouter.xcodeproj/project.pbxproj +++ b/Nightscouter.xcodeproj/project.pbxproj @@ -31,7 +31,6 @@ 1771B0691B7524AA006C1F5E /* NightscoutAPIClient.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1771B0651B7524AA006C1F5E /* NightscoutAPIClient.swift */; }; 1771B0751B7524D5006C1F5E /* CompassControl+Convience.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1771B06B1B7524D5006C1F5E /* CompassControl+Convience.swift */; }; 1771B0761B7524D5006C1F5E /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1771B06C1B7524D5006C1F5E /* Double+Extension.swift */; }; - 1771B0771B7524D5006C1F5E /* Int+Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1771B06D1B7524D5006C1F5E /* Int+Extensions.swift */; }; 1771B0781B7524D5006C1F5E /* NSAssetKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1771B06E1B7524D5006C1F5E /* NSAssetKit.swift */; }; 1771B0791B7524D5006C1F5E /* NSAssetKit+Helpers.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1771B06F1B7524D5006C1F5E /* NSAssetKit+Helpers.swift */; }; 1771B07A1B7524D5006C1F5E /* NSCalendar+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1771B0701B7524D5006C1F5E /* NSCalendar+Extension.swift */; }; @@ -126,7 +125,6 @@ 1771B0651B7524AA006C1F5E /* NightscoutAPIClient.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NightscoutAPIClient.swift; path = API/NightscoutAPIClient.swift; sourceTree = ""; }; 1771B06B1B7524D5006C1F5E /* CompassControl+Convience.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "CompassControl+Convience.swift"; path = "Extensions/CompassControl+Convience.swift"; sourceTree = ""; }; 1771B06C1B7524D5006C1F5E /* Double+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Double+Extension.swift"; path = "Extensions/Double+Extension.swift"; sourceTree = ""; }; - 1771B06D1B7524D5006C1F5E /* Int+Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "Int+Extensions.swift"; path = "Extensions/Int+Extensions.swift"; sourceTree = ""; }; 1771B06E1B7524D5006C1F5E /* NSAssetKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = NSAssetKit.swift; path = Extensions/NSAssetKit.swift; sourceTree = ""; }; 1771B06F1B7524D5006C1F5E /* NSAssetKit+Helpers.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSAssetKit+Helpers.swift"; path = "Extensions/NSAssetKit+Helpers.swift"; sourceTree = ""; }; 1771B0701B7524D5006C1F5E /* NSCalendar+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = "NSCalendar+Extension.swift"; path = "Extensions/NSCalendar+Extension.swift"; sourceTree = ""; }; @@ -370,7 +368,6 @@ isa = PBXGroup; children = ( 1771B06C1B7524D5006C1F5E /* Double+Extension.swift */, - 1771B06D1B7524D5006C1F5E /* Int+Extensions.swift */, 1771B0701B7524D5006C1F5E /* NSCalendar+Extension.swift */, 1771B0711B7524D5006C1F5E /* NSURL-Extensions.swift */, 1771B0721B7524D5006C1F5E /* String+Extensions.swift */, @@ -614,7 +611,6 @@ 1771B0761B7524D5006C1F5E /* Double+Extension.swift in Sources */, 1771B0751B7524D5006C1F5E /* CompassControl+Convience.swift in Sources */, 1771B0781B7524D5006C1F5E /* NSAssetKit.swift in Sources */, - 1771B0771B7524D5006C1F5E /* Int+Extensions.swift in Sources */, 1771B0671B7524AA006C1F5E /* AppTheme.swift in Sources */, 1771B0871B7524FD006C1F5E /* WatchEntry.swift in Sources */, 1771B0681B7524AA006C1F5E /* Constants.swift in Sources */, From d288d1204c0d95e2d5d85d7891b3c678cab20c90 Mon Sep 17 00:00:00 2001 From: Peter Ina Date: Tue, 25 Aug 2015 21:33:01 -0400 Subject: [PATCH 3/6] fixing chart issue --- Nightscouter/Info.plist | 2 +- NightscouterKit/Models/Entry.swift | 19 ++++++++++++------- NightscouterToday/Info.plist | 2 +- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/Nightscouter/Info.plist b/Nightscouter/Info.plist index c2fd49d..073855b 100644 --- a/Nightscouter/Info.plist +++ b/Nightscouter/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 130 + 131 LSRequiresIPhoneOS NSUserActivityTypes diff --git a/NightscouterKit/Models/Entry.swift b/NightscouterKit/Models/Entry.swift index 155c4a7..9b312ca 100644 --- a/NightscouterKit/Models/Entry.swift +++ b/NightscouterKit/Models/Entry.swift @@ -349,14 +349,19 @@ public extension Entry { println(errorString) #endif NSError(domain: NightscoutModelErrorDomain, code: -11, userInfo: ["description": errorString]) - + sgvItem = SensorGlucoseValue(sgv: 0, direction: .None, filtered: 0, unfiltered: 0, rssi: 0, noise: .None) + if let sgv = dict[EntryPropertyKey.sgvKey] as? Double { - if let directionString = dict[EntryPropertyKey.directionKey] as? String { - if let direction = Direction(rawValue: directionString) { - // let sgvInt: Int = Int(sgv.toInt()!) - let sgvValue = SensorGlucoseValue(sgv: sgv, direction: direction, filtered: 0, unfiltered: 0, rssi: 0, noise: Noise.None) - sgvItem = sgvValue - } + sgvItem?.sgv = sgv + } + + if let sgv = dict[EntryPropertyKey.sgvKey] as? String { + sgvItem?.sgv = sgv.toDouble! + } + + if let directionString = dict[EntryPropertyKey.directionKey] as? String { + if let direction = Direction(rawValue: directionString) { + sgvItem?.direction = direction } } } diff --git a/NightscouterToday/Info.plist b/NightscouterToday/Info.plist index 3f0f208..e3b05a1 100644 --- a/NightscouterToday/Info.plist +++ b/NightscouterToday/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 130 + 131 NSExtension NSExtensionMainStoryboard From eef76be537858157479fb8805606a100cac376fe Mon Sep 17 00:00:00 2001 From: Peter Ina Date: Tue, 25 Aug 2015 21:46:11 -0400 Subject: [PATCH 4/6] forgot to update today widget --- .../SiteNSNowTableViewCell.swift | 21 +++++++++++-------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/NightscouterToday/SiteNSNowTableViewCell.swift b/NightscouterToday/SiteNSNowTableViewCell.swift index 94294ea..9615e28 100644 --- a/NightscouterToday/SiteNSNowTableViewCell.swift +++ b/NightscouterToday/SiteNSNowTableViewCell.swift @@ -63,13 +63,21 @@ class SiteNSNowTableViewCell: UITableViewCell { siteLastReadingLabel.text = watchEntry.dateTimeAgoString if let sgvValue = watchEntry.sgv { - let color = colorForDesiredColorState(site.configuration!.boundedColorForGlucoseValue(sgvValue.sgv)) + + var boundedColor = configuration.boundedColorForGlucoseValue(sgvValue.sgv) + if units == .Mmol { + boundedColor = configuration.boundedColorForGlucoseValue(sgvValue.sgv.toMgdl) + } + let color = colorForDesiredColorState(boundedColor) + siteColorBlockView.backgroundColor = color + siteSgvLabel.text = "\(sgvValue.sgvString) \(sgvValue.direction.emojiForDirection)" siteSgvLabel.textColor = color siteDirectionLabel.text = "\(watchEntry.bgdelta.formattedForBGDelta) \(units.description)" siteDirectionLabel.textColor = color + if let enabledOptions = configuration.enabledOptions { let rawEnabled = contains(enabledOptions, EnabledOptions.rawbg) @@ -77,18 +85,13 @@ class SiteNSNowTableViewCell: UITableViewCell { if let rawValue = watchEntry.raw { let color = colorForDesiredColorState(configuration.boundedColorForGlucoseValue(rawValue)) - let numberFormatter = NSNumberFormatter() - var raw = rawValue + var raw = "\(rawValue.formattedForMgdl)" if configuration.displayUnits == .Mmol { - raw = rawValue.toMmol - numberFormatter.numberStyle = .DecimalStyle - numberFormatter.minimumFractionDigits = 1 - numberFormatter.maximumFractionDigits = 1 - numberFormatter.secondaryGroupingSize = 1 + raw = rawValue.formattedForMmol } siteRawLabel?.textColor = color - siteRawLabel.text = "\(numberFormatter.stringFromNumber(raw)!) : \(sgvValue.noise)" + siteRawLabel.text = "\(raw) : \(sgvValue.noise)" } } else { siteRawHeader.hidden = true From e593311c13705406f3f4eaa7a20a44f72db9e1f4 Mon Sep 17 00:00:00 2001 From: Peter Ina Date: Thu, 3 Sep 2015 21:52:22 -0400 Subject: [PATCH 5/6] Support Nightscout Funnel Cake Release Some properties changed in the status endpoint JSON. This is a quick hack to make it work and still keep support for 7.0. This needs to be refactored. --- .../Models/ServerConfiguration.swift | 116 ++++++++++++++---- 1 file changed, 94 insertions(+), 22 deletions(-) diff --git a/NightscouterKit/Models/ServerConfiguration.swift b/NightscouterKit/Models/ServerConfiguration.swift index e798d1c..a59c49c 100644 --- a/NightscouterKit/Models/ServerConfiguration.swift +++ b/NightscouterKit/Models/ServerConfiguration.swift @@ -20,6 +20,11 @@ public enum EnabledOptions: String, Printable { case errorcodes = "errorcodes" case simplealarms = "simplealarms" case pushover = "pushover" + case maker = "maker" + case cob = "cob" + case bwp = "bwp" + case cage = "cage" + case basal = "basal" public var description: String { return self.rawValue @@ -97,8 +102,10 @@ public struct Defaults: Printable { public let theme: String public let alarms: Alarm public let language: String - public let showPlugins: String? = nil // Not implmented yet - public let enabled: [EnabledOptions]? = nil // Not implmented yet + public let showPlugins: String? + public let enable: [EnabledOptions]? + public let thresholds: Threshold? + public let defaultFeatures: [String]? // End of "defaults" dictionary public var description: String { @@ -114,10 +121,14 @@ struct ConfigurationPropertyKey { static let defaultsKey = "defaults" static let alarmHighKey = "alarmHigh" static let alarmLowKey = "alarmLow" - static let alarmTimeAgoUrgentKey = "alarmTimeAgoUrgent" - static let alarmTimeAgoUrgentMinsKey = "alarmTimeAgoUrgentMins" - static let alarmTimeAgoWarnKey = "alarmTimeAgoWarn" - static let alarmTimeAgoWarnMinsKey = "alarmTimeAgoWarnMins" + static let alarmTimeAgoUrgentKey = "alarmTimeAgoUrgent" // for ns version 7.0. + static let alarmTimeagoUrgentKey = "alarmTimeagoUrgent" // for ns version 8.0. + static let alarmTimeAgoUrgentMinsKey = "alarmTimeAgoUrgentMins" // for ns version 7.0. + static let alarmTimeagoUrgentMinsKey = "alarmTimeagoUrgentMins" // for ns version 8.0. + static let alarmTimeAgoWarnKey = "alarmTimeAgoWarn" // for ns version 7.0. + static let alarmTimeagoWarnKey = "alarmTimeagoWarn" + static let alarmTimeAgoWarnMinsKey = "alarmTimeAgoWarnMins" // for ns version 7.0. + static let alarmTimeagoWarnMinsKey = "alarmTimeagoWarnMins" static let alarmUrgentHighKey = "alarmUrgentHigh" static let alarmUrgentLowKey = "alarmUrgentLow" static let customTitleKey = "customTitle" @@ -132,17 +143,26 @@ struct ConfigurationPropertyKey { static let nameKey = "name" static let statusKey = "status" static let thresholdsKey = "thresholds" + + // ver 7.0 static let bg_highKey = "bg_high" static let bg_lowKey = "bg_low" static let bg_target_bottomKey = "bg_target_bottom" static let bg_target_topKey = "bg_target_top" + + // ver 8.0 + static let bgHighKey = "bgHigh" + static let bgLowKey = "bgLow" + static let bgTargetBottomKey = "bgTargetBottom" + static let bgTargetTopKey = "bgTargetTop" + static let versionKey = "version" // Not implmented yet - // static let extendedSettingsKey = "extendedSettings" - // static let settingsKey = "settings" - // static let enableKey = "enable" - // static let showPluginsKey = "showPlugins" + static let extendedSettingsKey = "extendedSettings" + static let settingsKey = "settings" + static let enableKey = "enable" + static let showPluginsKey = "showPlugins" } public struct ServerConfiguration: Printable { @@ -151,6 +171,7 @@ public struct ServerConfiguration: Printable { public let careportalEnabled: Bool? public let enabledOptions: [EnabledOptions]? public let defaults: Defaults? +// public let settings: Defaults? public let unitsRoot: Units? public let head:String? public let version: String? @@ -244,12 +265,21 @@ public extension ServerConfiguration { } } } - serverConfig.enabledOptions = options if let nameString = root[ConfigurationPropertyKey.nameKey] as? String { serverConfig.name = nameString } + var threshold: Threshold? + if let thresholdsDict = jsonDictionary[ConfigurationPropertyKey.thresholdsKey] as? [String : AnyObject] { + let bg_high = thresholdsDict[ConfigurationPropertyKey.bg_highKey] as! Double + let bg_low = thresholdsDict[ConfigurationPropertyKey.bg_lowKey] as! Double + let bg_target_bottom = thresholdsDict[ConfigurationPropertyKey.bg_target_bottomKey] as! Double + let bg_target_top = thresholdsDict[ConfigurationPropertyKey.bg_target_topKey] as! Double + threshold = Threshold(bg_high: bg_high, bg_low: bg_low, bg_target_bottom: bg_target_bottom, bg_target_top: bg_target_top) + } + + var defaultsDefaults: Defaults? if let defaultsDictionary = root[ConfigurationPropertyKey.defaultsKey] as? [String: AnyObject] { let units = Units(rawValue: defaultsDictionary[ConfigurationPropertyKey.unitsKey] as! String)! @@ -275,21 +305,63 @@ public extension ServerConfiguration { let alarms = Alarm(alarmHigh: aHigh, alarmLow: aLow, alarmTimeAgoUrgent: aTAU, alarmTimeAgoUrgentMins: aTAUMin, alarmTimeAgoWarn: aTAW, alarmTimeAgoWarnMins: aTAWMin, alarmUrgentHigh: aTUH, alarmUrgentLow: aTUL) let language = defaultsDictionary[ConfigurationPropertyKey.languageKey] as! String - - defaultsDefaults = Defaults(units: units, timeFormat: timeFormat, nightMode: nightMode, showRawbg: showRawbg, customTitle: customTitle, theme: theme, alarms: alarms, language: language) + + defaultsDefaults = Defaults(units: units, timeFormat: timeFormat, nightMode: nightMode, showRawbg: showRawbg, customTitle: customTitle, theme: theme, alarms: alarms, language: language, showPlugins: nil, enable: nil, thresholds: nil, defaultFeatures: nil) } - serverConfig.defaults = defaultsDefaults - var threasholdsThreshold: Threshold? - if let thresholdsDict = jsonDictionary[ConfigurationPropertyKey.thresholdsKey] as? [String : AnyObject] { - let bg_high = thresholdsDict[ConfigurationPropertyKey.bg_highKey] as! Double - let bg_low = thresholdsDict[ConfigurationPropertyKey.bg_lowKey] as! Double - let bg_target_bottom = thresholdsDict[ConfigurationPropertyKey.bg_target_bottomKey] as! Double - let bg_target_top = thresholdsDict[ConfigurationPropertyKey.bg_target_topKey] as! Double - threasholdsThreshold = Threshold(bg_high: bg_high, bg_low: bg_low, bg_target_bottom: bg_target_bottom, bg_target_top: bg_target_top) + if let settingsDictionary = root[ConfigurationPropertyKey.settingsKey] as? [String: AnyObject] { + let units = Units(rawValue: (settingsDictionary[ConfigurationPropertyKey.unitsKey] as! String).lowercaseString)! + let timeFormat = (settingsDictionary[ConfigurationPropertyKey.timeFormatKey] as! String).toInt()! + let nightMode = settingsDictionary[ConfigurationPropertyKey.nightModeKey] as! Bool + let showRawbg = RawBGMode(rawValue: settingsDictionary[ConfigurationPropertyKey.showRawbgKey] as! String)! + let customTitle = settingsDictionary[ConfigurationPropertyKey.customTitleKey] as! String + + let theme = settingsDictionary[ConfigurationPropertyKey.themeKey] as! String + + let aHigh = settingsDictionary[ConfigurationPropertyKey.alarmHighKey] as! Bool + let aLow = settingsDictionary[ConfigurationPropertyKey.alarmLowKey] as! Bool + let aTAU = settingsDictionary[ConfigurationPropertyKey.alarmTimeagoUrgentKey] as! Bool + let aTAUMDouble = settingsDictionary[ConfigurationPropertyKey.alarmTimeagoUrgentMinsKey] as! Double + let aTAUMin: NSTimeInterval = aTAUMDouble * 60 // Convert minutes to seconds. + + let aTAW = settingsDictionary[ConfigurationPropertyKey.alarmTimeagoWarnKey] as! Bool + let aTAWMDouble = settingsDictionary[ConfigurationPropertyKey.alarmTimeagoWarnMinsKey] as! Double + let aTAWMin: NSTimeInterval = aTAWMDouble * 60 // Convert minutes to seconds. + let aTUH = settingsDictionary[ConfigurationPropertyKey.alarmUrgentHighKey] as! Bool + let aTUL = settingsDictionary[ConfigurationPropertyKey.alarmUrgentLowKey] as! Bool + + let alarms = Alarm(alarmHigh: aHigh, alarmLow: aLow, alarmTimeAgoUrgent: aTAU, alarmTimeAgoUrgentMins: aTAUMin, alarmTimeAgoWarn: aTAW, alarmTimeAgoWarnMins: aTAWMin, alarmUrgentHigh: aTUH, alarmUrgentLow: aTUL) + + let language = settingsDictionary[ConfigurationPropertyKey.languageKey] as! String + + + if let enableArray = settingsDictionary[ConfigurationPropertyKey.enableKey] as? [String] { + for stringItem in enableArray{ + if let item = EnabledOptions(rawValue: stringItem){ + options.append(item) + } + } + } + + if let thresholdsDict = settingsDictionary[ConfigurationPropertyKey.thresholdsKey] as? [String : AnyObject] { + let bg_high = thresholdsDict[ConfigurationPropertyKey.bgHighKey] as! Double + let bg_low = thresholdsDict[ConfigurationPropertyKey.bgLowKey] as! Double + let bg_target_bottom = thresholdsDict[ConfigurationPropertyKey.bgTargetBottomKey] as! Double + let bg_target_top = thresholdsDict[ConfigurationPropertyKey.bgTargetTopKey] as! Double + threshold = Threshold(bg_high: bg_high, bg_low: bg_low, bg_target_bottom: bg_target_bottom, bg_target_top: bg_target_top) + } + + + + defaultsDefaults = Defaults(units: units, timeFormat: timeFormat, nightMode: nightMode, showRawbg: showRawbg, customTitle: customTitle, theme: theme, alarms: alarms, language: language, showPlugins: nil, enable: options, thresholds: threshold, defaultFeatures: nil) + } - serverConfig.thresholds = threasholdsThreshold + + serverConfig.defaults = defaultsDefaults + serverConfig.thresholds = threshold + serverConfig.enabledOptions = options + self = serverConfig } } From 0182a564286260fb57b9c0d4944941a8126f39a2 Mon Sep 17 00:00:00 2001 From: Peter Ina Date: Tue, 8 Sep 2015 20:59:16 -0400 Subject: [PATCH 6/6] version bump for the next alpha release --- Nightscouter/Info.plist | 2 +- NightscouterToday/Info.plist | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Nightscouter/Info.plist b/Nightscouter/Info.plist index 073855b..1cf934a 100644 --- a/Nightscouter/Info.plist +++ b/Nightscouter/Info.plist @@ -32,7 +32,7 @@ CFBundleVersion - 131 + 132 LSRequiresIPhoneOS NSUserActivityTypes diff --git a/NightscouterToday/Info.plist b/NightscouterToday/Info.plist index e3b05a1..a6336a7 100644 --- a/NightscouterToday/Info.plist +++ b/NightscouterToday/Info.plist @@ -21,7 +21,7 @@ CFBundleSignature ???? CFBundleVersion - 131 + 132 NSExtension NSExtensionMainStoryboard