diff --git a/Cartfile b/Cartfile index f30fce344e..8749fb806b 100644 --- a/Cartfile +++ b/Cartfile @@ -2,5 +2,6 @@ github "loudnate/LoopKit" ~> 0.3.5 github "loudnate/xDripG5" ~> 0.5.0 github "loudnate/SwiftCharts" "loudnate/naterade" github "mddub/dexcom-share-client-swift" ~> 0.1 +github "mddub/G4ShareSpy" ~> 0.2 github "ps2/rileylink_ios" ~> 0.7.1 github "amplitude/Amplitude-iOS" "mpurland-framework" diff --git a/Cartfile.resolved b/Cartfile.resolved index 4013abb192..767382d408 100644 --- a/Cartfile.resolved +++ b/Cartfile.resolved @@ -1,5 +1,6 @@ github "amplitude/Amplitude-iOS" "a3d6720626e72a678489bce83ed9dacadb505dd7" github "loudnate/Crypto" "13fee45175b88629aeabe60b4b4fc3daf86fa0a3" +github "mddub/G4ShareSpy" "v0.2.0" github "loudnate/LoopKit" "v0.3.5" github "loudnate/SwiftCharts" "8671287afb29640f9cffced6521b1098b7aac085" github "mddub/dexcom-share-client-swift" "v0.1.3" diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/G4ShareSpy b/Carthage/Build/iOS/G4ShareSpy.framework/G4ShareSpy new file mode 100755 index 0000000000..55f34cdb5d Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/G4ShareSpy differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Headers/G4ShareSpy-Swift.h b/Carthage/Build/iOS/G4ShareSpy.framework/Headers/G4ShareSpy-Swift.h new file mode 100644 index 0000000000..a0ccf6a254 --- /dev/null +++ b/Carthage/Build/iOS/G4ShareSpy.framework/Headers/G4ShareSpy-Swift.h @@ -0,0 +1,112 @@ +// Generated by Apple Swift version 2.2 (swiftlang-703.0.18.8 clang-703.0.31) +#pragma clang diagnostic push + +#if defined(__has_include) && __has_include() +# include +#endif + +#pragma clang diagnostic ignored "-Wauto-import" +#include +#include +#include +#include + +#if !defined(SWIFT_TYPEDEFS) +# define SWIFT_TYPEDEFS 1 +# if defined(__has_include) && __has_include() +# include +# elif !defined(__cplusplus) || __cplusplus < 201103L +typedef uint_least16_t char16_t; +typedef uint_least32_t char32_t; +# endif +typedef float swift_float2 __attribute__((__ext_vector_type__(2))); +typedef float swift_float3 __attribute__((__ext_vector_type__(3))); +typedef float swift_float4 __attribute__((__ext_vector_type__(4))); +typedef double swift_double2 __attribute__((__ext_vector_type__(2))); +typedef double swift_double3 __attribute__((__ext_vector_type__(3))); +typedef double swift_double4 __attribute__((__ext_vector_type__(4))); +typedef int swift_int2 __attribute__((__ext_vector_type__(2))); +typedef int swift_int3 __attribute__((__ext_vector_type__(3))); +typedef int swift_int4 __attribute__((__ext_vector_type__(4))); +#endif + +#if !defined(SWIFT_PASTE) +# define SWIFT_PASTE_HELPER(x, y) x##y +# define SWIFT_PASTE(x, y) SWIFT_PASTE_HELPER(x, y) +#endif +#if !defined(SWIFT_METATYPE) +# define SWIFT_METATYPE(X) Class +#endif + +#if defined(__has_attribute) && __has_attribute(objc_runtime_name) +# define SWIFT_RUNTIME_NAME(X) __attribute__((objc_runtime_name(X))) +#else +# define SWIFT_RUNTIME_NAME(X) +#endif +#if defined(__has_attribute) && __has_attribute(swift_name) +# define SWIFT_COMPILE_NAME(X) __attribute__((swift_name(X))) +#else +# define SWIFT_COMPILE_NAME(X) +#endif +#if !defined(SWIFT_CLASS_EXTRA) +# define SWIFT_CLASS_EXTRA +#endif +#if !defined(SWIFT_PROTOCOL_EXTRA) +# define SWIFT_PROTOCOL_EXTRA +#endif +#if !defined(SWIFT_ENUM_EXTRA) +# define SWIFT_ENUM_EXTRA +#endif +#if !defined(SWIFT_CLASS) +# if defined(__has_attribute) && __has_attribute(objc_subclassing_restricted) +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) __attribute__((objc_subclassing_restricted)) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# else +# define SWIFT_CLASS(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# define SWIFT_CLASS_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_CLASS_EXTRA +# endif +#endif + +#if !defined(SWIFT_PROTOCOL) +# define SWIFT_PROTOCOL(SWIFT_NAME) SWIFT_RUNTIME_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +# define SWIFT_PROTOCOL_NAMED(SWIFT_NAME) SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_PROTOCOL_EXTRA +#endif + +#if !defined(SWIFT_EXTENSION) +# define SWIFT_EXTENSION(M) SWIFT_PASTE(M##_Swift_, __LINE__) +#endif + +#if !defined(OBJC_DESIGNATED_INITIALIZER) +# if defined(__has_attribute) && __has_attribute(objc_designated_initializer) +# define OBJC_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer)) +# else +# define OBJC_DESIGNATED_INITIALIZER +# endif +#endif +#if !defined(SWIFT_ENUM) +# define SWIFT_ENUM(_type, _name) enum _name : _type _name; enum SWIFT_ENUM_EXTRA _name : _type +# if defined(__has_feature) && __has_feature(generalized_swift_name) +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) enum _name : _type _name SWIFT_COMPILE_NAME(SWIFT_NAME); enum SWIFT_COMPILE_NAME(SWIFT_NAME) SWIFT_ENUM_EXTRA _name : _type +# else +# define SWIFT_ENUM_NAMED(_type, _name, SWIFT_NAME) SWIFT_ENUM(_type, _name) +# endif +#endif +#if defined(__has_feature) && __has_feature(modules) +@import Foundation; +#endif + +#pragma clang diagnostic ignored "-Wproperty-attribute-mismatch" +#pragma clang diagnostic ignored "-Wduplicate-method-arg" + +@interface NSData (SWIFT_EXTENSION(G4ShareSpy)) +@end + + +@interface NSData (SWIFT_EXTENSION(G4ShareSpy)) +@end + + +@interface NSDate (SWIFT_EXTENSION(G4ShareSpy)) +@end + +#pragma clang diagnostic pop diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Headers/G4ShareSpy.h b/Carthage/Build/iOS/G4ShareSpy.framework/Headers/G4ShareSpy.h new file mode 100644 index 0000000000..3ef4c98e96 --- /dev/null +++ b/Carthage/Build/iOS/G4ShareSpy.framework/Headers/G4ShareSpy.h @@ -0,0 +1,19 @@ +// +// G4ShareSpy.h +// G4ShareSpy +// +// Created by Mark on 7/21/16. +// Copyright © 2016 Mark Wilson. All rights reserved. +// + +#import + +//! Project version number for G4ShareSpy. +FOUNDATION_EXPORT double G4ShareSpyVersionNumber; + +//! Project version string for G4ShareSpy. +FOUNDATION_EXPORT const unsigned char G4ShareSpyVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Info.plist b/Carthage/Build/iOS/G4ShareSpy.framework/Info.plist new file mode 100644 index 0000000000..51f920ad74 Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Info.plist differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm.swiftdoc b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm.swiftdoc new file mode 100644 index 0000000000..ee6c268bae Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm.swiftdoc differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm.swiftmodule b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm.swiftmodule new file mode 100644 index 0000000000..2da22facd4 Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm.swiftmodule differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm64.swiftdoc b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm64.swiftdoc new file mode 100644 index 0000000000..412e078983 Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm64.swiftdoc differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm64.swiftmodule b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm64.swiftmodule new file mode 100644 index 0000000000..449da8b9a4 Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/arm64.swiftmodule differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/i386.swiftdoc b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/i386.swiftdoc new file mode 100644 index 0000000000..0f026b09f7 Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/i386.swiftdoc differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/i386.swiftmodule b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/i386.swiftmodule new file mode 100644 index 0000000000..73c2ddf248 Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/i386.swiftmodule differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/x86_64.swiftdoc b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/x86_64.swiftdoc new file mode 100644 index 0000000000..0eb18d7ad1 Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/x86_64.swiftdoc differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/x86_64.swiftmodule b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/x86_64.swiftmodule new file mode 100644 index 0000000000..3684441745 Binary files /dev/null and b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/G4ShareSpy.swiftmodule/x86_64.swiftmodule differ diff --git a/Carthage/Build/iOS/G4ShareSpy.framework/Modules/module.modulemap b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/module.modulemap new file mode 100644 index 0000000000..be22cea6a2 --- /dev/null +++ b/Carthage/Build/iOS/G4ShareSpy.framework/Modules/module.modulemap @@ -0,0 +1,10 @@ +framework module G4ShareSpy { + umbrella header "G4ShareSpy.h" + + export * + module * { export * } +} + +module G4ShareSpy.Swift { + header "G4ShareSpy-Swift.h" +} diff --git a/Documentation/Screenshots/Phone Graphs.png b/Documentation/Screenshots/Phone Graphs.png old mode 100755 new mode 100644 index 866c17a15d..dc84c5b13c Binary files a/Documentation/Screenshots/Phone Graphs.png and b/Documentation/Screenshots/Phone Graphs.png differ diff --git a/Documentation/Screenshots/Watch Menu.png b/Documentation/Screenshots/Watch Menu.png index 8d62b271f6..be931067aa 100644 Binary files a/Documentation/Screenshots/Watch Menu.png and b/Documentation/Screenshots/Watch Menu.png differ diff --git a/DoseMathTests/Info.plist b/DoseMathTests/Info.plist index 8d8ed6042c..dc2ece127f 100644 --- a/DoseMathTests/Info.plist +++ b/DoseMathTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/LICENSE.md b/LICENSE.md index 04898233f7..fe05606707 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -29,6 +29,10 @@ SOFTWARE. Copyright (c) 2014 Amplitude +## G4ShareSpy.framework + +Copyright (c) 2016 Mark Wilson + ## LoopKit.framework *Including CarbKit.framework, GlucoseKit.framework, and InsulinKit.framework* diff --git a/Loop.xcodeproj/project.pbxproj b/Loop.xcodeproj/project.pbxproj index 988b5e9596..522fea9dfc 100644 --- a/Loop.xcodeproj/project.pbxproj +++ b/Loop.xcodeproj/project.pbxproj @@ -7,6 +7,8 @@ objects = { /* Begin PBXBuildFile section */ + 430DA58E1D4AEC230097D1CA /* NSBundle.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58D1D4AEC230097D1CA /* NSBundle.swift */; }; + 430DA5901D4B0E4C0097D1CA /* MySentryPumpStatusMessageBody.swift in Sources */ = {isa = PBXBuildFile; fileRef = 430DA58F1D4B0E4C0097D1CA /* MySentryPumpStatusMessageBody.swift */; }; 4315D2871CA5CC3B00589052 /* CarbEntryEditTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4315D2861CA5CC3B00589052 /* CarbEntryEditTableViewController.swift */; }; 4315D28A1CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4315D2891CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift */; }; 4328E0181CFBE1DA00E199AA /* ContextInterfaceController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4328E0131CFBE1DA00E199AA /* ContextInterfaceController.swift */; }; @@ -132,6 +134,8 @@ 43F78D4D1C914197002152D1 /* GlucoseKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D491C914197002152D1 /* GlucoseKit.framework */; }; 43F78D4E1C914197002152D1 /* InsulinKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D4A1C914197002152D1 /* InsulinKit.framework */; }; 43F78D4F1C914197002152D1 /* LoopKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F78D4B1C914197002152D1 /* LoopKit.framework */; }; + 4D3B40041D4A9E1A00BC6334 /* G4ShareSpy.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D3B40021D4A9DFE00BC6334 /* G4ShareSpy.framework */; }; + 4D5B7A4B1D457CCA00796CA9 /* GlucoseG4.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4D5B7A4A1D457CCA00796CA9 /* GlucoseG4.swift */; }; C10428971D17BAD400DD539A /* NightscoutUploadKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = C10428961D17BAD400DD539A /* NightscoutUploadKit.framework */; }; /* End PBXBuildFile section */ @@ -216,6 +220,8 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 430DA58D1D4AEC230097D1CA /* NSBundle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = NSBundle.swift; sourceTree = ""; }; + 430DA58F1D4B0E4C0097D1CA /* MySentryPumpStatusMessageBody.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MySentryPumpStatusMessageBody.swift; sourceTree = ""; }; 4315D2861CA5CC3B00589052 /* CarbEntryEditTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CarbEntryEditTableViewController.swift; sourceTree = ""; }; 4315D2891CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "DiagnosticLogger+LoopKit.swift"; sourceTree = ""; }; 4328E0131CFBE1DA00E199AA /* ContextInterfaceController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ContextInterfaceController.swift; sourceTree = ""; }; @@ -345,6 +351,8 @@ 43F78D491C914197002152D1 /* GlucoseKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = GlucoseKit.framework; path = Carthage/Build/iOS/GlucoseKit.framework; sourceTree = ""; }; 43F78D4A1C914197002152D1 /* InsulinKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = InsulinKit.framework; path = Carthage/Build/iOS/InsulinKit.framework; sourceTree = ""; }; 43F78D4B1C914197002152D1 /* LoopKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = LoopKit.framework; path = Carthage/Build/iOS/LoopKit.framework; sourceTree = ""; }; + 4D3B40021D4A9DFE00BC6334 /* G4ShareSpy.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = G4ShareSpy.framework; path = Carthage/Build/iOS/G4ShareSpy.framework; sourceTree = ""; }; + 4D5B7A4A1D457CCA00796CA9 /* GlucoseG4.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GlucoseG4.swift; path = Loop/Models/GlucoseG4.swift; sourceTree = SOURCE_ROOT; }; C10428961D17BAD400DD539A /* NightscoutUploadKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = NightscoutUploadKit.framework; path = Carthage/Build/iOS/NightscoutUploadKit.framework; sourceTree = ""; }; /* End PBXFileReference section */ @@ -363,6 +371,7 @@ C10428971D17BAD400DD539A /* NightscoutUploadKit.framework in Frameworks */, 439897391CD2F82C00223065 /* AmplitudeFramework.framework in Frameworks */, 43F78D4C1C914197002152D1 /* CarbKit.framework in Frameworks */, + 4D3B40041D4A9E1A00BC6334 /* G4ShareSpy.framework in Frameworks */, 43F78D4D1C914197002152D1 /* GlucoseKit.framework in Frameworks */, 43F5C2C91B929C09003EB13D /* HealthKit.framework in Frameworks */, 43F78D4E1C914197002152D1 /* InsulinKit.framework in Frameworks */, @@ -433,10 +442,12 @@ 438849EB1D29EC34003B3F23 /* AmplitudeService.swift */, 4331E0791C85650D00FBE832 /* ChartAxisValueDoubleLog.swift */, 43F41C321D3A17AA00C11ED6 /* ChartAxisValueDoubleUnit.swift */, + 4D5B7A4A1D457CCA00796CA9 /* GlucoseG4.swift */, 434F24CA1CFCB7AB0004498F /* GlucoseRxMessage.swift */, 436FACED1D0BA636004E2427 /* InsulinDataSource.swift */, 436A0DA41D236A2A00104B24 /* LoopError.swift */, 438849ED1D2A1EBB003B3F23 /* MLabService.swift */, + 430DA58F1D4B0E4C0097D1CA /* MySentryPumpStatusMessageBody.swift */, 438849E91D297CB6003B3F23 /* NightscoutService.swift */, 437CCADF1D285C7B0075D2C3 /* ServiceAuthentication.swift */, 434F54601D28859B002A9274 /* ServiceCredential.swift */, @@ -573,6 +584,7 @@ 43649A621C7A347F00523D7F /* CollectionType.swift */, 434FF1E91CF26C29000DB779 /* IdentifiableClass.swift */, 434F54561D287FDB002A9274 /* NibLoadable.swift */, + 430DA58D1D4AEC230097D1CA /* NSBundle.swift */, 43CE7CDD1CA8B63E003CC1B0 /* NSDate.swift */, 4398973A1CD2FC2000223065 /* NSDateFormatter.swift */, 439897341CD2F7DE00223065 /* NSTimeInterval.swift */, @@ -659,6 +671,7 @@ 43F78D481C914197002152D1 /* CarbKit.framework */, 43EDDBF01C361C75007D89B5 /* CommonCrypto.framework */, 43EDDBF51C361D24007D89B5 /* CommonCrypto.framework.dSYM */, + 4D3B40021D4A9DFE00BC6334 /* G4ShareSpy.framework */, 43F78D491C914197002152D1 /* GlucoseKit.framework */, 43F5C2C81B929C09003EB13D /* HealthKit.framework */, 43F78D4A1C914197002152D1 /* InsulinKit.framework */, @@ -927,6 +940,7 @@ "$(SRCROOT)/Carthage/Build/iOS/ShareClient.framework", "$(SRCROOT)/Carthage/Build/iOS/NightscoutUploadKit.framework", "$(SRCROOT)/Carthage/Build/iOS/Crypto.framework", + "$(SRCROOT)/Carthage/Build/iOS/G4ShareSpy.framework", ); outputPaths = ( ); @@ -944,6 +958,7 @@ 434F54571D287FDB002A9274 /* NibLoadable.swift in Sources */, 4315D28A1CA5F45E00589052 /* DiagnosticLogger+LoopKit.swift in Sources */, 43C418B51CE0575200405B6A /* ShareGlucose+GlucoseKit.swift in Sources */, + 430DA58E1D4AEC230097D1CA /* NSBundle.swift in Sources */, 434F24C91CFCA8940004498F /* TransmitterGlucose.swift in Sources */, 434F24CB1CFCB7AB0004498F /* GlucoseRxMessage.swift in Sources */, 43776F901B8022E90074EA36 /* AppDelegate.swift in Sources */, @@ -980,6 +995,8 @@ 43DBF04C1C93B8D700B3C386 /* BolusViewController.swift in Sources */, 4328E0351CFC0AE100E199AA /* WatchDataManager.swift in Sources */, 437CCAE01D285C7B0075D2C3 /* ServiceAuthentication.swift in Sources */, + 430DA5901D4B0E4C0097D1CA /* MySentryPumpStatusMessageBody.swift in Sources */, + 4D5B7A4B1D457CCA00796CA9 /* GlucoseG4.swift in Sources */, 438849EC1D29EC34003B3F23 /* AmplitudeService.swift in Sources */, 43DBF0571C93F6EB00B3C386 /* ReservoirTableViewController.swift in Sources */, 435400341C9F878D00D5819C /* SetBolusUserInfo.swift in Sources */, @@ -1121,7 +1138,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer: loudnate@gmail.com (XZN842LDLT)"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 13; + CURRENT_PROJECT_VERSION = 14; DEBUG_INFORMATION_FORMAT = dwarf; ENABLE_STRICT_OBJC_MSGSEND = YES; ENABLE_TESTABILITY = YES; @@ -1169,7 +1186,7 @@ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; CODE_SIGN_IDENTITY = "iPhone Developer: loudnate@gmail.com (XZN842LDLT)"; COPY_PHASE_STRIP = NO; - CURRENT_PROJECT_VERSION = 13; + CURRENT_PROJECT_VERSION = 14; DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; diff --git a/Loop/Extensions/NSBundle.swift b/Loop/Extensions/NSBundle.swift new file mode 100644 index 0000000000..41ef2dad01 --- /dev/null +++ b/Loop/Extensions/NSBundle.swift @@ -0,0 +1,20 @@ +// +// NSBundle.swift +// Loop +// +// Created by Nate Racklyeft on 7/28/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation + + +extension NSBundle { + var shortVersionString: String { + return objectForInfoDictionaryKey("CFBundleShortVersionString") as! String + } + + var bundleDisplayName: String { + return objectForInfoDictionaryKey("CFBundleDisplayName") as! String + } +} diff --git a/Loop/Extensions/NSUserDefaults.swift b/Loop/Extensions/NSUserDefaults.swift index bbbe068198..b92aa4abf2 100644 --- a/Loop/Extensions/NSUserDefaults.swift +++ b/Loop/Extensions/NSUserDefaults.swift @@ -19,6 +19,9 @@ extension NSUserDefaults { case DosingEnabled = "com.loudnate.Naterade.DosingEnabled" case InsulinActionDuration = "com.loudnate.Naterade.InsulinActionDuration" case InsulinSensitivitySchedule = "com.loudnate.Naterade.InsulinSensitivitySchedule" + case G4ReceiverEnabled = "com.loudnate.Loop.G4ReceiverEnabled" + case G5TransmitterID = "com.loudnate.Naterade.TransmitterID" + case G5TransmitterStartTime = "com.loudnate.Naterade.TransmitterStartTime" case GlucoseTargetRangeSchedule = "com.loudnate.Naterade.GlucoseTargetRangeSchedule" case MaximumBasalRatePerHour = "com.loudnate.Naterade.MaximumBasalRatePerHour" case MaximumBolus = "com.loudnate.Naterade.MaximumBolus" @@ -26,8 +29,6 @@ extension NSUserDefaults { case PumpID = "com.loudnate.Naterade.PumpID" case PumpModelNumber = "com.loudnate.Naterade.PumpModelNumber" case PumpTimeZone = "com.loudnate.Naterade.PumpTimeZone" - case TransmitterID = "com.loudnate.Naterade.TransmitterID" - case TransmitterStartTime = "com.loudnate.Naterade.TransmitterStartTime" } var basalRateSchedule: BasalRateSchedule? { @@ -192,27 +193,36 @@ extension NSUserDefaults { } } + var receiverEnabled: Bool { + get { + return boolForKey(Key.G4ReceiverEnabled.rawValue) + } + set { + setBool(newValue, forKey: Key.G4ReceiverEnabled.rawValue) + } + } + var transmitterStartTime: NSTimeInterval? { get { - let value = doubleForKey(Key.TransmitterStartTime.rawValue) + let value = doubleForKey(Key.G5TransmitterStartTime.rawValue) return value > 0 ? value : nil } set { if let value = newValue { - setDouble(value, forKey: Key.TransmitterStartTime.rawValue) + setDouble(value, forKey: Key.G5TransmitterStartTime.rawValue) } else { - removeObjectForKey(Key.TransmitterStartTime.rawValue) + removeObjectForKey(Key.G5TransmitterStartTime.rawValue) } } } var transmitterID: String? { get { - return stringForKey(Key.TransmitterID.rawValue) + return stringForKey(Key.G5TransmitterID.rawValue) } set { - setObject(newValue, forKey: Key.TransmitterID.rawValue) + setObject(newValue, forKey: Key.G5TransmitterID.rawValue) } } diff --git a/Loop/Info.plist b/Loop/Info.plist index 4ff74ecbf7..468ecb31df 100644 --- a/Loop/Info.plist +++ b/Loop/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/Loop/Managers/DeviceDataManager.swift b/Loop/Managers/DeviceDataManager.swift index 163e4cee5f..830493c690 100644 --- a/Loop/Managers/DeviceDataManager.swift +++ b/Loop/Managers/DeviceDataManager.swift @@ -8,6 +8,7 @@ import Foundation import CarbKit +import G4ShareSpy import GlucoseKit import HealthKit import InsulinKit @@ -24,7 +25,7 @@ private enum State { } -class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { +class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate, ReceiverDelegate { /// Notification posted by the instance when new glucose data was processed static let GlucoseUpdatedNotification = "com.loudnate.Naterade.notification.GlucoseUpdated" @@ -57,6 +58,26 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { } } + // The Dexcom Share receiver object + var receiver: Receiver? + + var receiverEnabled: Bool = false { + didSet { + if (receiverEnabled) { + receiver = Receiver() + receiver!.delegate = self + } else { + receiver = nil + } + NSUserDefaults.standardUserDefaults().receiverEnabled = receiverEnabled + enableRileyLinkHeartbeatIfNeeded() + } + } + + var sensorInfo: SensorDisplayable? { + return latestGlucoseG5 ?? latestGlucoseG4 ?? latestPumpStatus + } + // MARK: - RileyLink @objc private func receivedRileyLinkManagerNotification(note: NSNotification) { @@ -118,6 +139,16 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { } } + func enableRileyLinkHeartbeatIfNeeded() { + if case .Ready = transmitterState { + rileyLinkManager.timerTickEnabled = false + } else if receiverEnabled { + rileyLinkManager.timerTickEnabled = false + } else { + rileyLinkManager.timerTickEnabled = true + } + } + // MARK: Pump data var latestPumpStatus: MySentryPumpStatusMessageBody? @@ -436,7 +467,7 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { // MARK: TransmitterDelegate - func transmitter(transmitter: Transmitter, didError error: ErrorType) { + func transmitter(transmitter: xDripG5.Transmitter, didError error: ErrorType) { logger.addMessage([ "error": "\(error)", "collectedAt": NSDateFormatter.ISO8601StrictDateFormatter().stringFromDate(NSDate()) @@ -446,16 +477,16 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { assertCurrentPumpData() } - func transmitter(transmitter: Transmitter, didReadGlucose glucoseMessage: GlucoseRxMessage) { + func transmitter(transmitter: xDripG5.Transmitter, didReadGlucose glucoseMessage: xDripG5.GlucoseRxMessage) { transmitterStartTime = transmitter.startTimeInterval assertCurrentPumpData() - guard glucoseMessage != latestGlucoseMessage else { + guard glucoseMessage != latestGlucoseG5 else { return } - latestGlucoseMessage = glucoseMessage + latestGlucoseG5 = glucoseMessage guard let glucose = TransmitterGlucose(glucoseMessage: glucoseMessage, startTime: transmitter.startTimeInterval), glucoseStore = glucoseStore else { NSNotificationCenter.defaultCenter().postNotificationName(self.dynamicType.GlucoseUpdatedNotification, object: self) @@ -487,22 +518,22 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { } } - var latestGlucoseMessage: GlucoseRxMessage? + private var latestGlucoseG5: GlucoseRxMessage? /** Attempts to backfill glucose data from the share servers if a G5 connection hasn't been established. - parameter completion: An optional closure called after the command is complete. */ - private func backfillGlucoseFromShareIfNeeded(completion completion: (() -> Void)? = nil) { - // We should have no G5 data, and a configured ShareClient and GlucoseStore. - guard latestGlucoseMessage == nil, let shareClient = remoteDataManager.shareClient, glucoseStore = glucoseStore else { + private func backfillGlucoseFromShareIfNeeded(completion: (() -> Void)? = nil) { + // We should have no G4 Share or G5 data, and a configured ShareClient and GlucoseStore. + guard latestGlucoseG4 == nil && latestGlucoseG5 == nil, let shareClient = remoteDataManager.shareClient, glucoseStore = glucoseStore else { completion?() return } - // If our last glucose was less than 4 minutes ago, don't fetch. - if let latestGlucose = glucoseStore.latestGlucose where latestGlucose.startDate.timeIntervalSinceNow > -NSTimeInterval(minutes: 4) { + // If our last glucose was less than 4.5 minutes ago, don't fetch. + if let latestGlucose = glucoseStore.latestGlucose where latestGlucose.startDate.timeIntervalSinceNow > -NSTimeInterval(minutes: 4.5) { completion?() return } @@ -533,6 +564,56 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { } } + // MARK: - Share Receiver + + // MARK: ReceiverDelegate + + private var latestGlucoseG4: GlucoseG4? + + func receiver(receiver: Receiver, didReadGlucoseHistory glucoseHistory: [GlucoseG4]) { + assertCurrentPumpData() + + guard let latest = glucoseHistory.sort({ $0.sequence < $1.sequence }).last where latest != latestGlucoseG4 else { + return + } + latestGlucoseG4 = latest + + guard let glucoseStore = glucoseStore else { + return + } + + // In the event that some of the glucose history was already backfilled from Share, don't overwrite it. + let includeAfter = glucoseStore.latestGlucose?.startDate.dateByAddingTimeInterval(NSTimeInterval(minutes: 1)) + + let validGlucose = glucoseHistory.flatMap({ + $0.isValid ? $0 : nil + }).filterDateRange(includeAfter, nil).map({ + (quantity: $0.quantity, date: $0.startDate, displayOnly: $0.isDisplayOnly) + }) + + // "Dexcom G4 Platinum Transmitter (Retail) US" - see https://accessgudid.nlm.nih.gov/devices/search?query=dexcom+g4 + let device = HKDevice(name: "G4ShareSpy", manufacturer: "Dexcom", model: "G4 Share", hardwareVersion: nil, firmwareVersion: nil, softwareVersion: String(G4ShareSpyVersionNumber), localIdentifier: nil, UDIDeviceIdentifier: "40386270000048") + + glucoseStore.addGlucoseValues(validGlucose, device: device, resultHandler: { (_, _, error) -> Void in + if let error = error { + self.logger.addError(error, fromSource: "GlucoseStore") + } + + NSNotificationCenter.defaultCenter().postNotificationName(self.dynamicType.GlucoseUpdatedNotification, object: self) + }) + } + + func receiver(receiver: Receiver, didError error: ErrorType) { + logger.addMessage(["error": "\(error)", "collectedAt": NSDateFormatter.ISO8601StrictDateFormatter().stringFromDate(NSDate())], toCollection: "g4") + + assertCurrentPumpData() + } + + func receiver(receiver: Receiver, didLogBluetoothEvent event: String) { + // Uncomment to debug communication + // NSLog("G4: \(event)") + } + // MARK: - Configuration // MARK: Pump @@ -631,13 +712,10 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { private var transmitterState: State = .NeedsConfiguration { didSet { - switch transmitterState { - case .Ready(let transmitter): + if case .Ready(let transmitter) = transmitterState { transmitter.delegate = self - rileyLinkManager.timerTickEnabled = false - case .NeedsConfiguration: - rileyLinkManager.timerTickEnabled = true } + enableRileyLinkHeartbeatIfNeeded() } } @@ -859,6 +937,7 @@ class DeviceDataManager: CarbStoreDelegate, TransmitterDelegate { defer { transmitterID = NSUserDefaults.standardUserDefaults().transmitterID + receiverEnabled = NSUserDefaults.standardUserDefaults().receiverEnabled } } } diff --git a/Loop/Managers/WatchDataManager.swift b/Loop/Managers/WatchDataManager.swift index 75b3c3a13b..ae393bcefd 100644 --- a/Loop/Managers/WatchDataManager.swift +++ b/Loop/Managers/WatchDataManager.swift @@ -107,8 +107,8 @@ class WatchDataManager: NSObject, WCSessionDelegate { context.loopLastRunDate = lastLoopCompleted context.recommendedBolusDose = units - if let trend = self.deviceDataManager.latestGlucoseMessage?.trend { - context.glucoseTrend = Int(trend) + if let trend = self.deviceDataManager.sensorInfo?.trendDescription { + context.glucoseTrend = trend } completionHandler(context: context) diff --git a/Loop/Models/GlucoseG4.swift b/Loop/Models/GlucoseG4.swift new file mode 100644 index 0000000000..7077c73af5 --- /dev/null +++ b/Loop/Models/GlucoseG4.swift @@ -0,0 +1,54 @@ +// +// GlucoseG4.swift +// Loop +// +// Created by Mark Wilson on 7/21/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import Foundation +import G4ShareSpy +import HealthKit +import LoopKit + + +extension GlucoseG4 { + var isValid: Bool { + return glucose >= 20 + } +} + + +extension GlucoseG4: GlucoseValue { + public var quantity: HKQuantity { + return HKQuantity(unit: HKUnit.milligramsPerDeciliterUnit(), doubleValue: Double(glucose)) + } + + public var startDate: NSDate { + return time + } +} + + +extension GlucoseG4: SensorDisplayable { + var stateDescription: String { + if isValid { + return "✓" + } else { + return String(format: "%02x", glucose) + } + } + + var trendDescription: String { + switch trend { + case 1: return "⇈" + case 2: return "↑" + case 3: return "↗" + case 4: return "→" + case 5: return "↘" + case 6: return "↓" + case 7: return "⇊" + default: return "" + } + } +} diff --git a/Loop/Models/GlucoseRxMessage.swift b/Loop/Models/GlucoseRxMessage.swift index bc9c79fa39..d12a480749 100644 --- a/Loop/Models/GlucoseRxMessage.swift +++ b/Loop/Models/GlucoseRxMessage.swift @@ -10,8 +10,35 @@ import Foundation import xDripG5 -extension GlucoseRxMessage { +protocol SensorDisplayable { + // Describes the state of the sensor in the current localization + var stateDescription: String { get } + + // Describes the trend of the sensor values in the current localization + var trendDescription: String { get } +} + + +extension GlucoseRxMessage: SensorDisplayable { + var stateDescription: String { + let status: String + switch self.status { + case .OK: + status = "" + case .LowBattery: + status = NSLocalizedString("Low Battery", comment: "The description of a low G5 transmitter battery") + case .Unknown(let value): + status = String(format: "%02x", value) + } + + return String(format: "%1$02x %2$@", state, status) + } + var trendDescription: String { + guard trend < Int8.max else { + return "" + } + let direction: String switch trend { case let x where x < -10: @@ -23,9 +50,9 @@ extension GlucoseRxMessage { case let x where x > 0: direction = "↑" default: - direction = "" + direction = "→" } - return direction + return String(format: NSLocalizedString("%1$d %2$@", comment: "The format string describing the G5 sensor trend (1: The raw trend value)(2: The direction arrow)"), trend, direction) } } \ No newline at end of file diff --git a/Loop/Models/MySentryPumpStatusMessageBody.swift b/Loop/Models/MySentryPumpStatusMessageBody.swift new file mode 100644 index 0000000000..465d8224f4 --- /dev/null +++ b/Loop/Models/MySentryPumpStatusMessageBody.swift @@ -0,0 +1,43 @@ +// +// MySentryPumpStatusMessageBody.swift +// Loop +// +// Created by Nate Racklyeft on 7/28/16. +// Copyright © 2016 Nathan Racklyeft. All rights reserved. +// + +import LoopKit +import MinimedKit + + +extension MySentryPumpStatusMessageBody: SensorDisplayable { + var stateDescription: String { + switch glucose { + case .Active: + return "✓" + case .Off: + return "" + default: + return String(glucose) + } + } + + var trendDescription: String { + guard case .Active = glucose else { + return "" + } + + switch glucoseTrend { + case .Flat: + return "→" + case .Up: + return "⇈" + case .UpUp: + return "↑" + case .Down: + return "↓" + case .DownDown: + return "⇊" + } + } +} \ No newline at end of file diff --git a/Loop/View Controllers/SettingsTableViewController.swift b/Loop/View Controllers/SettingsTableViewController.swift index 3828427b3c..965571debe 100644 --- a/Loop/View Controllers/SettingsTableViewController.swift +++ b/Loop/View Controllers/SettingsTableViewController.swift @@ -46,7 +46,7 @@ class SettingsTableViewController: UITableViewController, DailyValueScheduleTabl dataManager.rileyLinkManager.deviceScanningEnabled = true - if dataManager.transmitterID != nil, let glucoseStore = dataManager.glucoseStore where glucoseStore.authorizationRequired { + if dataManager.transmitterID != nil || dataManager.receiverEnabled, let glucoseStore = dataManager.glucoseStore where glucoseStore.authorizationRequired { glucoseStore.authorize({ (success, error) -> Void in // Do nothing for now }) @@ -96,6 +96,7 @@ class SettingsTableViewController: UITableViewController, DailyValueScheduleTabl private enum ConfigurationRow: Int { case PumpID = 0 case TransmitterID + case ReceiverEnabled case GlucoseTargetRange case InsulinActionDuration case BasalRate @@ -104,7 +105,7 @@ class SettingsTableViewController: UITableViewController, DailyValueScheduleTabl case MaxBasal case MaxBolus - static let count = 9 + static let count = 10 } private enum ServiceRow: Int { @@ -163,13 +164,24 @@ class SettingsTableViewController: UITableViewController, DailyValueScheduleTabl case .PreferredInsulinDataSource: let segmentCell = tableView.dequeueReusableCellWithIdentifier(SegmentedControlTableViewCell.className, forIndexPath: indexPath) as! SegmentedControlTableViewCell - segmentCell.titleLabel.text = NSLocalizedString("Nightscout history uploading", comment: "The title text for the preferred insulin data source config") + segmentCell.titleLabel.text = NSLocalizedString("Nightscout History Upload", comment: "The title text for the preferred insulin data source config") segmentCell.segmentedControl.selectedSegmentIndex = dataManager.preferredInsulinDataSource.rawValue segmentCell.segmentedControl.addTarget(self, action: #selector(preferredInsulinDataSourceChanged(_:)), forControlEvents: .ValueChanged) return segmentCell } case .Configuration: + if case .ReceiverEnabled = ConfigurationRow(rawValue: indexPath.row)! { + let switchCell = tableView.dequeueReusableCellWithIdentifier(SwitchTableViewCell.className, forIndexPath: indexPath) as! SwitchTableViewCell + + switchCell.`switch`?.on = dataManager.receiverEnabled + switchCell.titleLabel.text = NSLocalizedString("G4 Share Receiver (beta)", comment: "The title text for the G4 Share Receiver enabled switch cell") + + switchCell.`switch`?.addTarget(self, action: #selector(receiverEnabledChanged(_:)), forControlEvents: .ValueChanged) + + return switchCell + } + let configCell = tableView.dequeueReusableCellWithIdentifier(ConfigCellIdentifier, forIndexPath: indexPath) switch ConfigurationRow(rawValue: indexPath.row)! { @@ -179,6 +191,8 @@ class SettingsTableViewController: UITableViewController, DailyValueScheduleTabl case .TransmitterID: configCell.textLabel?.text = NSLocalizedString("G5 Transmitter ID", comment: "The title text for the Dexcom G5 transmitter ID config value") configCell.detailTextLabel?.text = dataManager.transmitterID ?? TapToSetString + case .ReceiverEnabled: + break case .BasalRate: configCell.textLabel?.text = NSLocalizedString("Basal Rates", comment: "The title text for the basal rate schedule") @@ -294,8 +308,8 @@ class SettingsTableViewController: UITableViewController, DailyValueScheduleTabl override func tableView(tableView: UITableView, titleForHeaderInSection section: Int) -> String? { switch Section(rawValue: section)! { case .Loop: - let version = NSBundle.mainBundle().objectForInfoDictionaryKey("CFBundleShortVersionString")! - return "Loop iOS v\(version)" + let bundle = NSBundle.mainBundle() + return String(format: NSLocalizedString("%1$@ v%2$@", comment: "The format string for the app name and version number. (1: bundle name)(2: bundle version)"), bundle.bundleDisplayName, bundle.shortVersionString) case .Configuration: return NSLocalizedString("Configuration", comment: "The title of the configuration section in settings") case .Devices: @@ -443,6 +457,8 @@ class SettingsTableViewController: UITableViewController, DailyValueScheduleTabl } else { showViewController(scheduleVC, sender: sender) } + case .ReceiverEnabled: + break } case .Devices: let vc = RileyLinkDeviceTableViewController() @@ -533,6 +549,10 @@ class SettingsTableViewController: UITableViewController, DailyValueScheduleTabl } } + func receiverEnabledChanged(sender: UISwitch) { + dataManager.receiverEnabled = sender.on + } + // MARK: - TextFieldTableViewControllerDelegate func textFieldTableViewControllerDidEndEditing(controller: TextFieldTableViewController) { diff --git a/Loop/View Controllers/StatusTableViewController.swift b/Loop/View Controllers/StatusTableViewController.swift index a67095c92d..ca75005fcd 100644 --- a/Loop/View Controllers/StatusTableViewController.swift +++ b/Loop/View Controllers/StatusTableViewController.swift @@ -541,22 +541,13 @@ class StatusTableViewController: UITableViewController, UIGestureRecognizerDeleg } } case .Trend: - cell.textLabel?.text = NSLocalizedString("Trend", comment: "The title of the cell containing the current glucose trend") + cell.textLabel?.text = NSLocalizedString("Sensor Trend", comment: "The title of the cell containing the current glucose trend") - if let glucose = dataManager.latestGlucoseMessage, trendString = numberFormatter.stringFromNumber(NSNumber(char: glucose.trend)) { - - cell.detailTextLabel?.text = trendString + glucose.trendDescription - } else { - cell.detailTextLabel?.text = emptyValueString - } + cell.detailTextLabel?.text = dataManager.sensorInfo?.trendDescription ?? emptyValueString case .State: - cell.textLabel?.text = NSLocalizedString("Calibration state", comment: "The title of the cell containing the current sensor state") + cell.textLabel?.text = NSLocalizedString("Sensor State", comment: "The title of the cell containing the current sensor state") - if let glucose = dataManager.latestGlucoseMessage { - cell.detailTextLabel?.text = String(format: "%02x", glucose.state) - } else { - cell.detailTextLabel?.text = nil - } + cell.detailTextLabel?.text = dataManager.sensorInfo?.stateDescription ?? emptyValueString } return cell diff --git a/LoopTests/Info.plist b/LoopTests/Info.plist index 8d8ed6042c..dc2ece127f 100644 --- a/LoopTests/Info.plist +++ b/LoopTests/Info.plist @@ -15,7 +15,7 @@ CFBundlePackageType BNDL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/README.md b/README.md index b6ee7f5c59..a447866d49 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ Please understand that this project: Screenshot of glucose complication on Apple Watch Screenshot of carb entry on Apple Watch Screenshot of bolus entry on Apple Watch -Screenshot of bolus failure notification on Apple Watch +Screenshot of the app menu on Apple Watch Screenshot of bolus failure notification on Apple Watch Screenshot of bolus failure notification on Apple Watch @@ -40,32 +40,27 @@ Please understand that this project: CGM - Dexcom G4 + Share + Dexcom G4 ✅1 21 Dexcom G5 - ✅2 - ✅ - - - Dexcom G4 without Share - ✅124 - ✅ + ✅2 3 + ✅3 MM CGM - ❌3 + ❌4 ✅ -
1. Internet connection required to retrieve glucose -
2. Pump must have a remote ID added in the [Remote Options](https://www.medtronicdiabetes.com/sites/default/files/library/download-library/workbooks/x22_menu_map.pdf) menu -
3. It's not impossible, but comms-heavy and there's some work to be done. File an issue if you're someone who's up for the challenge and can test this hardware configuration. -
4. Requires CGM data to be uploaded to Dexcom Share servers - and then downloaded into loop. At time of writing this has been tested using xDrip+ (https://github.com/jamorham/xDrip-plus). +
1. Offline access to glucose requires a Receiver with Share and the [Share2 app](https://itunes.apple.com/us/app/dexcom-share2/id834775275?mt=8) to be running on the same device. Internet-dependent access via Share servers is also supported. +
2. Pump must have a remote ID added in the [Remote Options](https://www.medtronicdiabetes.com/sites/default/files/library/download-library/workbooks/x22_menu_map.pdf) menu. +
3. Early firmware only available on select models is required for using Closed Loop and Bolus features. +
4. It's not impossible, but comms-heavy and there's some work to be done. File an issue if you're someone who's up for the challenge and can test this hardware configuration. ### RileyLink @@ -95,7 +90,7 @@ Loop optionally supports select third-party remote services, which are configure | Service | Description | ---------------------- | ------------- -| Dexcom Share | Downloads glucose data if the G5 transmitter is not available. This is the sole source of glucose data for G4 users. +| Dexcom Share | Downloads glucose data if a local G5 Transmitter or G4 Receiver with Share is not available. | Nightscout | Uploads treatments and other pump data. Note you will need to set "Nightscout history uploading" to "On" in Settings for treatments to be fetched from your pump and uploaded to Nightscout. | mLab | Uploads diagnostic data about each loop run, as well as app errors. At this time, it is strongly recommended that you configure this service in case retrospective analysis is needed. | Amplitude | Tracks private, single-user behavioral and system analytics diff --git a/WatchApp Extension/Controllers/StatusInterfaceController.swift b/WatchApp Extension/Controllers/StatusInterfaceController.swift index 51a36b5835..4740412846 100644 --- a/WatchApp Extension/Controllers/StatusInterfaceController.swift +++ b/WatchApp Extension/Controllers/StatusInterfaceController.swift @@ -50,7 +50,7 @@ class StatusInterfaceController: ContextInterfaceController { dispatch_async(dispatch_get_main_queue()) { if let glucose = context?.glucose, unit = context?.preferredGlucoseUnit { let glucoseValue = glucose.doubleValueForUnit(unit) - let trend = context?.glucoseTrendDescription ?? "" + let trend = context?.glucoseTrend ?? "" self.glucoseLabel.setText((numberFormatter.stringFromNumber(glucoseValue) ?? "") + trend) self.glucoseLabel.setHidden(false) diff --git a/WatchApp Extension/Info.plist b/WatchApp Extension/Info.plist index 3ed6a6ab53..5aea6cb93e 100644 --- a/WatchApp Extension/Info.plist +++ b/WatchApp Extension/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType XPC! CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion diff --git a/WatchApp Extension/Models/WatchContext.swift b/WatchApp Extension/Models/WatchContext.swift index f0aa9dce2f..3646dc3a98 100644 --- a/WatchApp Extension/Models/WatchContext.swift +++ b/WatchApp Extension/Models/WatchContext.swift @@ -18,7 +18,7 @@ class WatchContext: NSObject, RawRepresentable { var preferredGlucoseUnit: HKUnit? var glucose: HKQuantity? - var glucoseTrend: Int? + var glucoseTrend: String? var eventualGlucose: HKQuantity? var glucoseDate: NSDate? @@ -56,7 +56,7 @@ class WatchContext: NSObject, RawRepresentable { eventualGlucose = HKQuantity(unit: unit, doubleValue: glucoseValue) } } - glucoseTrend = rawValue["gt"] as? Int + glucoseTrend = rawValue["gt"] as? String glucoseDate = rawValue["gd"] as? NSDate IOB = rawValue["iob"] as? Double @@ -87,7 +87,7 @@ class WatchContext: NSObject, RawRepresentable { raw["gv"] = glucose?.doubleValueForUnit(unit) } - raw["gt"] = glucoseTrend + raw["gtd"] = glucoseTrend raw["gd"] = glucoseDate raw["iob"] = IOB raw["ld"] = loopLastRunDate @@ -97,22 +97,4 @@ class WatchContext: NSObject, RawRepresentable { return raw } - - var glucoseTrendDescription: String { - let direction: String - switch glucoseTrend { - case let x? where x < -10: - direction = "⇊" - case let x? where x < 0: - direction = "↓" - case let x? where x > 10: - direction = "⇈" - case let x? where x > 0: - direction = "↑" - default: - direction = "→" - } - - return direction - } } \ No newline at end of file diff --git a/WatchApp/Info.plist b/WatchApp/Info.plist index b9c851f070..a907609d2d 100644 --- a/WatchApp/Info.plist +++ b/WatchApp/Info.plist @@ -17,7 +17,7 @@ CFBundlePackageType APPL CFBundleShortVersionString - 0.7.1 + 0.8.0 CFBundleSignature ???? CFBundleVersion