Browse Source

v2.1-20200518

tags/v2.4
elinkthings 5 years ago
commit
71ef93d696
44 changed files with 3581 additions and 0 deletions
  1. 72
    0
      .gitignore
  2. 487
    0
      AIFit-Demo.xcodeproj/project.pbxproj
  3. 7
    0
      AIFit-Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata
  4. 8
    0
      AIFit-Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
  5. 8
    0
      AIFit-Demo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings
  6. 17
    0
      AIFit-Demo/AppDelegate.h
  7. 31
    0
      AIFit-Demo/AppDelegate.m
  8. 27
    0
      AIFit-Demo/AppUser.h
  9. 13
    0
      AIFit-Demo/AppUser.m
  10. BIN
      AIFit-Demo/Assets.xcassets/AppIcon.appiconset/120-1.png
  11. BIN
      AIFit-Demo/Assets.xcassets/AppIcon.appiconset/120.png
  12. BIN
      AIFit-Demo/Assets.xcassets/AppIcon.appiconset/180.png
  13. BIN
      AIFit-Demo/Assets.xcassets/AppIcon.appiconset/58.png
  14. BIN
      AIFit-Demo/Assets.xcassets/AppIcon.appiconset/80.png
  15. BIN
      AIFit-Demo/Assets.xcassets/AppIcon.appiconset/87.png
  16. 59
    0
      AIFit-Demo/Assets.xcassets/AppIcon.appiconset/Contents.json
  17. 31
    0
      AIFit-Demo/Base.lproj/LaunchScreen.storyboard
  18. 180
    0
      AIFit-Demo/Base.lproj/Main.storyboard
  19. 52
    0
      AIFit-Demo/Info.plist
  20. 13
    0
      AIFit-Demo/MainViewController.h
  21. 489
    0
      AIFit-Demo/MainViewController.m
  22. 17
    0
      AIFit-Demo/SearchDeviceVC.h
  23. 193
    0
      AIFit-Demo/SearchDeviceVC.m
  24. 21
    0
      AIFit-Demo/SetUserViewController.h
  25. 45
    0
      AIFit-Demo/SetUserViewController.m
  26. 109
    0
      AIFit-Demo/SetUserViewController.xib
  27. 16
    0
      AIFit-Demo/main.m
  28. 40
    0
      AIFit-DemoUITests/AIFit_DemoUITests.m
  29. 22
    0
      AIFit-DemoUITests/Info.plist
  30. 67
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/AlgorithmSDK.h
  31. 54
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/AnalysisBLEDataManager.h
  32. 39
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/BLEUser.h
  33. 89
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/BfsCalculateSDK.h
  34. 60
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/BleTools.h
  35. 53
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/DeviceModel.h
  36. 64
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/INBluetoothManager.h
  37. 22
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/InetBleSDK.h
  38. 129
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/UserInfoModel.h
  39. 49
    0
      InetBleSDK/Products/InetBleSDK.framework/Headers/WriteToBLEManager.h
  40. BIN
      InetBleSDK/Products/InetBleSDK.framework/InetBleSDK
  41. BIN
      InetBleSDK/Products/InetBleSDK.framework/Info.plist
  42. 6
    0
      InetBleSDK/Products/InetBleSDK.framework/Modules/module.modulemap
  43. 485
    0
      README.md
  44. 507
    0
      README_CN.md

+ 72
- 0
.gitignore View File

@@ -0,0 +1,72 @@
# Xcode
#
# gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore

## Build generated
build/
DerivedData/

## Various settings
*.pbxuser
!default.pbxuser
*.mode1v3
!default.mode1v3
*.mode2v3
!default.mode2v3
*.perspectivev3
!default.perspectivev3
xcuserdata/

## Other
*.moved-aside
*.xccheckout
*.xcscmblueprint
.DS_Store
*/.DS_Store

## Obj-C/Swift specific
*.hmap
*.ipa
*.dSYM.zip
*.dSYM

# CocoaPods
#
# We recommend against adding the Pods directory to your .gitignore. However
# you should judge for yourself, the pros and cons are mentioned at:
# https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
#
# Pods/

# Carthage
#
# Add this line if you want to avoid checking in source code from Carthage dependencies.
# Carthage/Checkouts

Carthage/Build

# fastlane
#
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
# screenshots whenever they are needed.
# For more information about the recommended setup visit:
# https://docs.fastlane.tools/best-practices/source-control/#source-control

fastlane/report.xml
fastlane/Preview.html
fastlane/screenshots
fastlane/test_output

# Code Injection
#
# After new code Injection tools there's a generated folder /iOSInjectionProject
# https://github.com/johnno1962/injectionforxcode

iOSInjectionProject/

#Auto package ignore
#shell.sh
#exportAdhoc.plist
exportAppstore.plist
IPADir/


+ 487
- 0
AIFit-Demo.xcodeproj/project.pbxproj View File

@@ -0,0 +1,487 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 48;
objects = {

/* Begin PBXBuildFile section */
5D8EC794213AB6990053C2E9 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D8EC793213AB6990053C2E9 /* AppDelegate.m */; };
5D8EC79A213AB6990053C2E9 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5D8EC798213AB6990053C2E9 /* Main.storyboard */; };
5D8EC79C213AB6990053C2E9 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5D8EC79B213AB6990053C2E9 /* Assets.xcassets */; };
5D8EC79F213AB6990053C2E9 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5D8EC79D213AB6990053C2E9 /* LaunchScreen.storyboard */; };
5D8EC7A2213AB6990053C2E9 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D8EC7A1213AB6990053C2E9 /* main.m */; };
5D8EC7AC213AB6990053C2E9 /* AIFit_DemoUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5D8EC7AB213AB6990053C2E9 /* AIFit_DemoUITests.m */; };
827389CF213BD5840057156D /* InetBleSDK.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 827389CE213BD5840057156D /* InetBleSDK.framework */; };
8279C3D6213D21EB00805897 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 8279C3D5213D21EB00805897 /* MainViewController.m */; };
8279C3D9213D243700805897 /* SearchDeviceVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 8279C3D8213D243700805897 /* SearchDeviceVC.m */; };
95DC38BE23AB8D9B00C5E6E3 /* AppUser.m in Sources */ = {isa = PBXBuildFile; fileRef = 95DC38BD23AB8D9B00C5E6E3 /* AppUser.m */; };
95DC38CA23AC836D00C5E6E3 /* SetUserViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 95DC38C823AC836D00C5E6E3 /* SetUserViewController.m */; };
95DC38CB23AC836D00C5E6E3 /* SetUserViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = 95DC38C923AC836D00C5E6E3 /* SetUserViewController.xib */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
5D8EC7A8213AB6990053C2E9 /* PBXContainerItemProxy */ = {
isa = PBXContainerItemProxy;
containerPortal = 5D8EC787213AB6990053C2E9 /* Project object */;
proxyType = 1;
remoteGlobalIDString = 5D8EC78E213AB6990053C2E9;
remoteInfo = "AIFit-Demo";
};
/* End PBXContainerItemProxy section */

/* Begin PBXFileReference section */
5D8EC78F213AB6990053C2E9 /* AIFit-Demo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "AIFit-Demo.app"; sourceTree = BUILT_PRODUCTS_DIR; };
5D8EC792213AB6990053C2E9 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
5D8EC793213AB6990053C2E9 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
5D8EC799213AB6990053C2E9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = "<group>"; };
5D8EC79B213AB6990053C2E9 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
5D8EC79E213AB6990053C2E9 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = "<group>"; };
5D8EC7A0213AB6990053C2E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
5D8EC7A1213AB6990053C2E9 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
5D8EC7A7213AB6990053C2E9 /* AIFit-DemoUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = "AIFit-DemoUITests.xctest"; sourceTree = BUILT_PRODUCTS_DIR; };
5D8EC7AB213AB6990053C2E9 /* AIFit_DemoUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AIFit_DemoUITests.m; sourceTree = "<group>"; };
5D8EC7AD213AB6990053C2E9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
827389CE213BD5840057156D /* InetBleSDK.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = InetBleSDK.framework; path = InetBleSDK/Products/InetBleSDK.framework; sourceTree = SOURCE_ROOT; };
8279C3D4213D21EB00805897 /* MainViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MainViewController.h; sourceTree = "<group>"; };
8279C3D5213D21EB00805897 /* MainViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MainViewController.m; sourceTree = "<group>"; };
8279C3D7213D243700805897 /* SearchDeviceVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SearchDeviceVC.h; sourceTree = "<group>"; };
8279C3D8213D243700805897 /* SearchDeviceVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SearchDeviceVC.m; sourceTree = "<group>"; };
95DC38BC23AB8D9B00C5E6E3 /* AppUser.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppUser.h; sourceTree = "<group>"; };
95DC38BD23AB8D9B00C5E6E3 /* AppUser.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppUser.m; sourceTree = "<group>"; };
95DC38C723AC836D00C5E6E3 /* SetUserViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SetUserViewController.h; sourceTree = "<group>"; };
95DC38C823AC836D00C5E6E3 /* SetUserViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SetUserViewController.m; sourceTree = "<group>"; };
95DC38C923AC836D00C5E6E3 /* SetUserViewController.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = SetUserViewController.xib; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
5D8EC78C213AB6990053C2E9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
827389CF213BD5840057156D /* InetBleSDK.framework in Frameworks */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5D8EC7A4213AB6990053C2E9 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */

/* Begin PBXGroup section */
5D8EC786213AB6990053C2E9 = {
isa = PBXGroup;
children = (
5D8EC791213AB6990053C2E9 /* AIFit-Demo */,
5D8EC7AA213AB6990053C2E9 /* AIFit-DemoUITests */,
5D8EC790213AB6990053C2E9 /* Products */,
5D8EC80C213ACCC80053C2E9 /* Frameworks */,
);
sourceTree = "<group>";
};
5D8EC790213AB6990053C2E9 /* Products */ = {
isa = PBXGroup;
children = (
5D8EC78F213AB6990053C2E9 /* AIFit-Demo.app */,
5D8EC7A7213AB6990053C2E9 /* AIFit-DemoUITests.xctest */,
);
name = Products;
sourceTree = "<group>";
};
5D8EC791213AB6990053C2E9 /* AIFit-Demo */ = {
isa = PBXGroup;
children = (
827389CE213BD5840057156D /* InetBleSDK.framework */,
5D8EC792213AB6990053C2E9 /* AppDelegate.h */,
5D8EC793213AB6990053C2E9 /* AppDelegate.m */,
95DC38BC23AB8D9B00C5E6E3 /* AppUser.h */,
95DC38BD23AB8D9B00C5E6E3 /* AppUser.m */,
8279C3D7213D243700805897 /* SearchDeviceVC.h */,
8279C3D8213D243700805897 /* SearchDeviceVC.m */,
8279C3D4213D21EB00805897 /* MainViewController.h */,
8279C3D5213D21EB00805897 /* MainViewController.m */,
95DC38C723AC836D00C5E6E3 /* SetUserViewController.h */,
95DC38C823AC836D00C5E6E3 /* SetUserViewController.m */,
95DC38C923AC836D00C5E6E3 /* SetUserViewController.xib */,
5D8EC798213AB6990053C2E9 /* Main.storyboard */,
5D8EC79B213AB6990053C2E9 /* Assets.xcassets */,
5D8EC79D213AB6990053C2E9 /* LaunchScreen.storyboard */,
5D8EC7A0213AB6990053C2E9 /* Info.plist */,
5D8EC7A1213AB6990053C2E9 /* main.m */,
);
path = "AIFit-Demo";
sourceTree = "<group>";
};
5D8EC7AA213AB6990053C2E9 /* AIFit-DemoUITests */ = {
isa = PBXGroup;
children = (
5D8EC7AB213AB6990053C2E9 /* AIFit_DemoUITests.m */,
5D8EC7AD213AB6990053C2E9 /* Info.plist */,
);
path = "AIFit-DemoUITests";
sourceTree = "<group>";
};
5D8EC80C213ACCC80053C2E9 /* Frameworks */ = {
isa = PBXGroup;
children = (
);
name = Frameworks;
sourceTree = "<group>";
};
/* End PBXGroup section */

/* Begin PBXNativeTarget section */
5D8EC78E213AB6990053C2E9 /* AIFit-Demo */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5D8EC7B0213AB6990053C2E9 /* Build configuration list for PBXNativeTarget "AIFit-Demo" */;
buildPhases = (
5D8EC78B213AB6990053C2E9 /* Sources */,
5D8EC78C213AB6990053C2E9 /* Frameworks */,
5D8EC78D213AB6990053C2E9 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "AIFit-Demo";
productName = "AIFit-Demo";
productReference = 5D8EC78F213AB6990053C2E9 /* AIFit-Demo.app */;
productType = "com.apple.product-type.application";
};
5D8EC7A6213AB6990053C2E9 /* AIFit-DemoUITests */ = {
isa = PBXNativeTarget;
buildConfigurationList = 5D8EC7B3213AB6990053C2E9 /* Build configuration list for PBXNativeTarget "AIFit-DemoUITests" */;
buildPhases = (
5D8EC7A3213AB6990053C2E9 /* Sources */,
5D8EC7A4213AB6990053C2E9 /* Frameworks */,
5D8EC7A5213AB6990053C2E9 /* Resources */,
);
buildRules = (
);
dependencies = (
5D8EC7A9213AB6990053C2E9 /* PBXTargetDependency */,
);
name = "AIFit-DemoUITests";
productName = "AIFit-DemoUITests";
productReference = 5D8EC7A7213AB6990053C2E9 /* AIFit-DemoUITests.xctest */;
productType = "com.apple.product-type.bundle.ui-testing";
};
/* End PBXNativeTarget section */

/* Begin PBXProject section */
5D8EC787213AB6990053C2E9 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 0920;
ORGANIZATIONNAME = wujia121;
TargetAttributes = {
5D8EC78E213AB6990053C2E9 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Automatic;
};
5D8EC7A6213AB6990053C2E9 = {
CreatedOnToolsVersion = 9.2;
ProvisioningStyle = Automatic;
TestTargetID = 5D8EC78E213AB6990053C2E9;
};
};
};
buildConfigurationList = 5D8EC78A213AB6990053C2E9 /* Build configuration list for PBXProject "AIFit-Demo" */;
compatibilityVersion = "Xcode 8.0";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 5D8EC786213AB6990053C2E9;
productRefGroup = 5D8EC790213AB6990053C2E9 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
5D8EC78E213AB6990053C2E9 /* AIFit-Demo */,
5D8EC7A6213AB6990053C2E9 /* AIFit-DemoUITests */,
);
};
/* End PBXProject section */

/* Begin PBXResourcesBuildPhase section */
5D8EC78D213AB6990053C2E9 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
95DC38CB23AC836D00C5E6E3 /* SetUserViewController.xib in Resources */,
5D8EC79F213AB6990053C2E9 /* LaunchScreen.storyboard in Resources */,
5D8EC79C213AB6990053C2E9 /* Assets.xcassets in Resources */,
5D8EC79A213AB6990053C2E9 /* Main.storyboard in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5D8EC7A5213AB6990053C2E9 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */

/* Begin PBXSourcesBuildPhase section */
5D8EC78B213AB6990053C2E9 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5D8EC7A2213AB6990053C2E9 /* main.m in Sources */,
8279C3D6213D21EB00805897 /* MainViewController.m in Sources */,
95DC38CA23AC836D00C5E6E3 /* SetUserViewController.m in Sources */,
95DC38BE23AB8D9B00C5E6E3 /* AppUser.m in Sources */,
8279C3D9213D243700805897 /* SearchDeviceVC.m in Sources */,
5D8EC794213AB6990053C2E9 /* AppDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
5D8EC7A3213AB6990053C2E9 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
5D8EC7AC213AB6990053C2E9 /* AIFit_DemoUITests.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */

/* Begin PBXTargetDependency section */
5D8EC7A9213AB6990053C2E9 /* PBXTargetDependency */ = {
isa = PBXTargetDependency;
target = 5D8EC78E213AB6990053C2E9 /* AIFit-Demo */;
targetProxy = 5D8EC7A8213AB6990053C2E9 /* PBXContainerItemProxy */;
};
/* End PBXTargetDependency section */

/* Begin PBXVariantGroup section */
5D8EC798213AB6990053C2E9 /* Main.storyboard */ = {
isa = PBXVariantGroup;
children = (
5D8EC799213AB6990053C2E9 /* Base */,
);
name = Main.storyboard;
sourceTree = "<group>";
};
5D8EC79D213AB6990053C2E9 /* LaunchScreen.storyboard */ = {
isa = PBXVariantGroup;
children = (
5D8EC79E213AB6990053C2E9 /* Base */,
);
name = LaunchScreen.storyboard;
sourceTree = "<group>";
};
/* End PBXVariantGroup section */

/* Begin XCBuildConfiguration section */
5D8EC7AE213AB6990053C2E9 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
};
name = Debug;
};
5D8EC7AF213AB6990053C2E9 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
CODE_SIGN_IDENTITY = "iPhone Developer";
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 11.2;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
VALIDATE_PRODUCT = YES;
};
name = Release;
};
5D8EC7B1213AB6990053C2E9 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20200518;
DEVELOPMENT_TEAM = YEU77XR292;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/InetBleSDK/Products";
HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "AIFit-Demo/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 2.1;
PRODUCT_BUNDLE_IDENTIFIER = com.pingwang.InetBleSDKDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
5D8EC7B2213AB6990053C2E9 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 20200518;
DEVELOPMENT_TEAM = YEU77XR292;
FRAMEWORK_SEARCH_PATHS = "$(PROJECT_DIR)/InetBleSDK/Products";
HEADER_SEARCH_PATHS = "";
INFOPLIST_FILE = "AIFit-Demo/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 2.1;
PRODUCT_BUNDLE_IDENTIFIER = com.pingwang.InetBleSDKDemo;
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
5D8EC7B4213AB6990053C2E9 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = "AIFit-DemoUITests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.pingwang.AIFit-DemoUITests";
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = "AIFit-Demo";
};
name = Debug;
};
5D8EC7B5213AB6990053C2E9 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
CODE_SIGN_STYLE = Automatic;
INFOPLIST_FILE = "AIFit-DemoUITests/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
PRODUCT_BUNDLE_IDENTIFIER = "com.pingwang.AIFit-DemoUITests";
PRODUCT_NAME = "$(TARGET_NAME)";
TARGETED_DEVICE_FAMILY = "1,2";
TEST_TARGET_NAME = "AIFit-Demo";
};
name = Release;
};
/* End XCBuildConfiguration section */

/* Begin XCConfigurationList section */
5D8EC78A213AB6990053C2E9 /* Build configuration list for PBXProject "AIFit-Demo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5D8EC7AE213AB6990053C2E9 /* Debug */,
5D8EC7AF213AB6990053C2E9 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5D8EC7B0213AB6990053C2E9 /* Build configuration list for PBXNativeTarget "AIFit-Demo" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5D8EC7B1213AB6990053C2E9 /* Debug */,
5D8EC7B2213AB6990053C2E9 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
5D8EC7B3213AB6990053C2E9 /* Build configuration list for PBXNativeTarget "AIFit-DemoUITests" */ = {
isa = XCConfigurationList;
buildConfigurations = (
5D8EC7B4213AB6990053C2E9 /* Debug */,
5D8EC7B5213AB6990053C2E9 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 5D8EC787213AB6990053C2E9 /* Project object */;
}

+ 7
- 0
AIFit-Demo.xcodeproj/project.xcworkspace/contents.xcworkspacedata View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>

+ 8
- 0
AIFit-Demo.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>

+ 8
- 0
AIFit-Demo.xcodeproj/project.xcworkspace/xcshareddata/WorkspaceSettings.xcsettings View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>BuildSystemType</key>
<string>Original</string>
</dict>
</plist>

+ 17
- 0
AIFit-Demo/AppDelegate.h View File

@@ -0,0 +1,17 @@
//
// AppDelegate.h
// AIFit-Demo
//
// Created by wujia121 on 2018/9/1.
// Copyright © 2018年 wujia121. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;


@end


+ 31
- 0
AIFit-Demo/AppDelegate.m View File

@@ -0,0 +1,31 @@
//
// AppDelegate.m
// AIFit-Demo
//
// Created by wujia121 on 2018/9/1.
// Copyright © 2018年 wujia121. All rights reserved.
//

#import "AppDelegate.h"
#import <InetBleSDK/InetBleSDK.h>

@interface AppDelegate ()

@end

@implementation AppDelegate


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//apply sdk key website http://sdk.aicare.net.cn/
[INBluetoothManager configAppKey:@"885fd30a19f54fb0" secret:@"000fec8b4dadbca6a3d4e00875"];
return YES;
}




@end

+ 27
- 0
AIFit-Demo/AppUser.h View File

@@ -0,0 +1,27 @@
//
// AppUser.h
// AIFit-Demo
//
// Created by steven wu on 2019/12/19.
// Copyright © 2019 wujia121. All rights reserved.
//

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface AppUser : NSObject


@property (nonatomic, assign) float weightKg;
/**Be Noted:
male: 1 female: 2
*/
@property (nonatomic, assign) int sex;
@property (nonatomic, assign) int age;
@property (nonatomic, assign) int height;
@property (nonatomic, assign) int adc;

@end

NS_ASSUME_NONNULL_END

+ 13
- 0
AIFit-Demo/AppUser.m View File

@@ -0,0 +1,13 @@
//
// AppUser.m
// AIFit-Demo
//
// Created by steven wu on 2019/12/19.
// Copyright © 2019 wujia121. All rights reserved.
//

#import "AppUser.h"

@implementation AppUser

@end

BIN
AIFit-Demo/Assets.xcassets/AppIcon.appiconset/120-1.png View File


BIN
AIFit-Demo/Assets.xcassets/AppIcon.appiconset/120.png View File


BIN
AIFit-Demo/Assets.xcassets/AppIcon.appiconset/180.png View File


BIN
AIFit-Demo/Assets.xcassets/AppIcon.appiconset/58.png View File


BIN
AIFit-Demo/Assets.xcassets/AppIcon.appiconset/80.png View File


BIN
AIFit-Demo/Assets.xcassets/AppIcon.appiconset/87.png View File


+ 59
- 0
AIFit-Demo/Assets.xcassets/AppIcon.appiconset/Contents.json View File

@@ -0,0 +1,59 @@
{
"images" : [
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "2x"
},
{
"idiom" : "iphone",
"size" : "20x20",
"scale" : "3x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "58.png",
"scale" : "2x"
},
{
"size" : "29x29",
"idiom" : "iphone",
"filename" : "87.png",
"scale" : "3x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "80.png",
"scale" : "2x"
},
{
"size" : "40x40",
"idiom" : "iphone",
"filename" : "120.png",
"scale" : "3x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "120-1.png",
"scale" : "2x"
},
{
"size" : "60x60",
"idiom" : "iphone",
"filename" : "180.png",
"scale" : "3x"
},
{
"idiom" : "ios-marketing",
"size" : "1024x1024",
"scale" : "1x"
}
],
"info" : {
"version" : 1,
"author" : "xcode"
}
}

+ 31
- 0
AIFit-Demo/Base.lproj/LaunchScreen.storyboard View File

@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="13771" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="13772"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--View Controller-->
<scene sceneID="EHf-IW-A2E">
<objects>
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="Yjt-lG-WWf"/>
<viewControllerLayoutGuide type="bottom" id="0qM-4s-Ocv"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
</view>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="53" y="375"/>
</scene>
</scenes>
</document>

+ 180
- 0
AIFit-Demo/Base.lproj/Main.storyboard View File

@@ -0,0 +1,180 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="lGz-vQ-rIV">
<device id="retina4_7" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
<!--Main View Controller-->
<scene sceneID="M5v-mj-yx8">
<objects>
<viewController id="lGz-vQ-rIV" customClass="MainViewController" sceneMemberID="viewController">
<layoutGuides>
<viewControllerLayoutGuide type="top" id="lRu-BS-3Ti"/>
<viewControllerLayoutGuide type="bottom" id="MN7-HW-Fpp"/>
</layoutGuides>
<view key="view" contentMode="scaleToFill" id="NkZ-Gv-FdY">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="5Kt-f7-SXj">
<rect key="frame" x="10" y="25" width="355" height="35"/>
<color key="backgroundColor" red="0.81568627450980391" green="1" blue="0.88235294117647056" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="35" id="rKn-Ml-Igo"/>
</constraints>
<state key="normal" title="Connect Device"/>
<connections>
<action selector="Click_Ble:" destination="lGz-vQ-rIV" eventType="touchUpInside" id="Ht0-QE-HDi"/>
</connections>
</button>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="bzc-dA-DuA" userLabel="隔栏--------">
<rect key="frame" x="0.0" y="70" width="375" height="5"/>
<color key="backgroundColor" red="0.66666668650000005" green="0.66666668650000005" blue="0.66666668650000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="5" id="Tgt-tF-HS7"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="User Info -&gt;" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="78Y-KE-lWH">
<rect key="frame" x="10" y="80" width="90" height="30"/>
<constraints>
<constraint firstAttribute="width" constant="90" id="3zK-me-rOk"/>
<constraint firstAttribute="height" constant="30" id="Txo-Ni-992"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Unit:" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="gVu-AQ-2bu">
<rect key="frame" x="10" y="190" width="65" height="28"/>
<constraints>
<constraint firstAttribute="width" constant="65" id="B19-2X-DQV"/>
<constraint firstAttribute="height" constant="28" id="sd6-bi-owp"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="15"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="Zf3-rF-BZy">
<rect key="frame" x="83" y="190" width="276" height="29"/>
<segments>
<segment title="KG"/>
<segment title="LB"/>
<segment title="ST"/>
<segment title="斤"/>
</segments>
<connections>
<action selector="ChooseUnit:" destination="lGz-vQ-rIV" eventType="valueChanged" id="79T-rr-7H1"/>
</connections>
</segmentedControl>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="MRu-AK-Tza" userLabel="隔栏--------">
<rect key="frame" x="0.0" y="228" width="375" height="6"/>
<color key="backgroundColor" red="0.66666668650000005" green="0.66666668650000005" blue="0.66666668650000005" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="6" id="4EE-XR-4yP"/>
</constraints>
</view>
<view contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="waM-g5-AjV">
<rect key="frame" x="0.0" y="240" width="375" height="427"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Tips" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="xbU-hm-1Sk">
<rect key="frame" x="5" y="0.0" width="365" height="30"/>
<constraints>
<constraint firstAttribute="height" constant="30" id="esF-6v-SVM"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="1" green="0.14913141730000001" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<tableView clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="prototypes" style="plain" separatorStyle="default" rowHeight="-1" estimatedRowHeight="-1" sectionHeaderHeight="28" sectionFooterHeight="28" translatesAutoresizingMaskIntoConstraints="NO" id="vMl-1e-9Hx">
<rect key="frame" x="0.0" y="30" width="375" height="387"/>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
</tableView>
</subviews>
<color key="backgroundColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<constraints>
<constraint firstItem="xbU-hm-1Sk" firstAttribute="leading" secondItem="waM-g5-AjV" secondAttribute="leading" constant="5" id="3Qn-be-kyt"/>
<constraint firstAttribute="bottom" secondItem="vMl-1e-9Hx" secondAttribute="bottom" constant="10" id="5QN-18-odJ"/>
<constraint firstItem="vMl-1e-9Hx" firstAttribute="top" secondItem="xbU-hm-1Sk" secondAttribute="bottom" id="83E-Fz-Bra"/>
<constraint firstItem="vMl-1e-9Hx" firstAttribute="leading" secondItem="waM-g5-AjV" secondAttribute="leading" id="9Rx-s5-oHi"/>
<constraint firstItem="xbU-hm-1Sk" firstAttribute="top" secondItem="waM-g5-AjV" secondAttribute="top" id="PYj-lG-nd1"/>
<constraint firstAttribute="trailing" secondItem="vMl-1e-9Hx" secondAttribute="trailing" id="SYO-6O-Shx"/>
<constraint firstAttribute="trailing" secondItem="xbU-hm-1Sk" secondAttribute="trailing" constant="5" id="Sjv-QS-PGB"/>
</constraints>
</view>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" textAlignment="natural" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="6kj-dC-o6z">
<rect key="frame" x="127.5" y="80" width="120" height="95.5"/>
<constraints>
<constraint firstAttribute="width" constant="120" id="kds-sZ-9g0"/>
</constraints>
<string key="text">sex: 1
age:25
height:175
weight:72.0
adc:560</string>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="b8T-HZ-nQw">
<rect key="frame" x="261" y="110" width="85" height="36"/>
<color key="backgroundColor" red="0.81568627450980391" green="1" blue="0.88235294117647056" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstAttribute="height" constant="36" id="Fh4-K7-OYJ"/>
<constraint firstAttribute="width" constant="85" id="Tyc-9q-bhQ"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<state key="normal" title="Edit User"/>
<connections>
<action selector="editUser:" destination="lGz-vQ-rIV" eventType="touchUpInside" id="xiI-7j-PIm"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="bzc-dA-DuA" firstAttribute="leading" secondItem="NkZ-Gv-FdY" secondAttribute="leading" id="3Lt-dy-cm0"/>
<constraint firstAttribute="trailing" secondItem="bzc-dA-DuA" secondAttribute="trailing" id="5lo-tb-HYQ"/>
<constraint firstItem="78Y-KE-lWH" firstAttribute="top" secondItem="bzc-dA-DuA" secondAttribute="bottom" constant="5" id="B0k-kZ-Qh3"/>
<constraint firstItem="gVu-AQ-2bu" firstAttribute="top" secondItem="78Y-KE-lWH" secondAttribute="bottom" constant="80" id="EQV-SW-PC5"/>
<constraint firstItem="6kj-dC-o6z" firstAttribute="top" secondItem="78Y-KE-lWH" secondAttribute="top" id="GwU-eR-QsS"/>
<constraint firstAttribute="trailing" secondItem="5Kt-f7-SXj" secondAttribute="trailing" constant="10" id="KlA-QB-HSu"/>
<constraint firstItem="6kj-dC-o6z" firstAttribute="leading" secondItem="78Y-KE-lWH" secondAttribute="trailing" constant="27.5" id="OjO-jw-djP"/>
<constraint firstItem="78Y-KE-lWH" firstAttribute="leading" secondItem="NkZ-Gv-FdY" secondAttribute="leading" constant="10" id="QB9-im-L5N"/>
<constraint firstAttribute="trailing" secondItem="MRu-AK-Tza" secondAttribute="trailing" id="QeK-C3-Lrf"/>
<constraint firstItem="Zf3-rF-BZy" firstAttribute="leading" secondItem="gVu-AQ-2bu" secondAttribute="trailing" constant="8" id="RCk-og-j5B"/>
<constraint firstItem="5Kt-f7-SXj" firstAttribute="leading" secondItem="NkZ-Gv-FdY" secondAttribute="leading" constant="10" id="Rla-9j-jdj"/>
<constraint firstAttribute="trailing" secondItem="b8T-HZ-nQw" secondAttribute="trailing" constant="29" id="S1e-8O-kNf"/>
<constraint firstItem="gVu-AQ-2bu" firstAttribute="leading" secondItem="78Y-KE-lWH" secondAttribute="leading" id="TLW-5V-lLv"/>
<constraint firstAttribute="trailing" secondItem="Zf3-rF-BZy" secondAttribute="trailing" constant="16" id="UZu-dr-qec"/>
<constraint firstItem="b8T-HZ-nQw" firstAttribute="centerY" secondItem="6kj-dC-o6z" secondAttribute="centerY" id="YgB-Rw-dQ4"/>
<constraint firstItem="Zf3-rF-BZy" firstAttribute="centerY" secondItem="gVu-AQ-2bu" secondAttribute="centerY" id="Z3a-qD-19b"/>
<constraint firstItem="waM-g5-AjV" firstAttribute="top" secondItem="MRu-AK-Tza" secondAttribute="bottom" constant="6" id="cFk-yZ-hTb"/>
<constraint firstItem="MRu-AK-Tza" firstAttribute="top" secondItem="gVu-AQ-2bu" secondAttribute="bottom" constant="10" id="cQ0-3t-WFB"/>
<constraint firstItem="bzc-dA-DuA" firstAttribute="top" secondItem="5Kt-f7-SXj" secondAttribute="bottom" constant="10" id="dZU-C7-vgj"/>
<constraint firstItem="MN7-HW-Fpp" firstAttribute="top" secondItem="waM-g5-AjV" secondAttribute="bottom" id="fVN-gd-61G"/>
<constraint firstItem="MRu-AK-Tza" firstAttribute="leading" secondItem="NkZ-Gv-FdY" secondAttribute="leading" id="jXP-c0-g9T"/>
<constraint firstItem="waM-g5-AjV" firstAttribute="leading" secondItem="NkZ-Gv-FdY" secondAttribute="leading" id="lVq-CY-oPR"/>
<constraint firstItem="78Y-KE-lWH" firstAttribute="leading" secondItem="5Kt-f7-SXj" secondAttribute="leading" id="rSV-bQ-38y"/>
<constraint firstItem="5Kt-f7-SXj" firstAttribute="top" secondItem="lRu-BS-3Ti" secondAttribute="bottom" constant="5" id="sU1-UF-vn7"/>
<constraint firstAttribute="trailing" secondItem="waM-g5-AjV" secondAttribute="trailing" id="xLI-R1-Qbc"/>
</constraints>
</view>
<navigationItem key="navigationItem" id="kGm-2k-A3l"/>
<connections>
<outlet property="connectedDevicesButton" destination="5Kt-f7-SXj" id="DM6-Vv-YYE"/>
<outlet property="tableView" destination="vMl-1e-9Hx" id="fsv-7u-yZ5"/>
<outlet property="tipLB" destination="xbU-hm-1Sk" id="TZg-UN-EyA"/>
<outlet property="unitSegmentedControl" destination="Zf3-rF-BZy" id="4dh-d2-rI7"/>
<outlet property="userInfoLabel" destination="6kj-dC-o6z" id="Fw2-3H-dxU"/>
</connections>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="crl-Of-xUZ" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="-738.39999999999998" y="84.107946026986511"/>
</scene>
</scenes>
</document>

+ 52
- 0
AIFit-Demo/Info.plist View File

@@ -0,0 +1,52 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleDisplayName</key>
<string>InetBleSDKDemo</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>APPL</string>
<key>CFBundleShortVersionString</key>
<string>$(MARKETING_VERSION)</string>
<key>CFBundleVersion</key>
<string>$(CURRENT_PROJECT_VERSION)</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>NSAppTransportSecurity</key>
<dict>
<key>NSAllowsArbitraryLoads</key>
<true/>
</dict>
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Use bluetooth to connect body fat scale</string>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UIMainStoryboardFile</key>
<string>Main</string>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>

+ 13
- 0
AIFit-Demo/MainViewController.h View File

@@ -0,0 +1,13 @@
//
// AIFit-Demo
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <UIKit/UIKit.h>

@interface MainViewController : UIViewController

@end


+ 489
- 0
AIFit-Demo/MainViewController.m View File

@@ -0,0 +1,489 @@
//
// AIFit-Demo
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import "MainViewController.h"

#import "SearchDeviceVC.h"
#import <InetBleSDK/InetBleSDK.h>
#import "AppUser.h"
#import "SetUserViewController.h"

@interface MainViewController () <AnalysisBLEDataManagerDelegate, INBluetoothManagerDelegate,UITableViewDataSource,UITableViewDelegate>

@property (weak, nonatomic) IBOutlet UIButton *connectedDevicesButton;
@property (weak, nonatomic) IBOutlet UILabel *userInfoLabel;
@property (weak, nonatomic) IBOutlet UISegmentedControl *unitSegmentedControl;

@property (weak, nonatomic) IBOutlet UITableView *tableView;
@property (nonatomic, strong) NSArray *itemNameArr;
@property (nonatomic, strong) NSMutableArray *itemValueArr;

@property (weak, nonatomic) IBOutlet UILabel *tipLB;

@property (nonatomic, strong) UserInfoModel *currentInfoModel;
@property (nonatomic, strong) DeviceModel *targetDeviceModel;

@property (nonatomic, strong) AppUser *appUser;

@end

@implementation MainViewController

- (NSArray *)itemNameArr {
if (_itemNameArr == nil) {
_itemNameArr = @[
@"weight:",
@"BMI:",
@"fatRate:",
@"muscle:",
@"moisture:",
@"boneMass:",
@"BMR:",
@"visceralFat:",
@"subcutaneousFat:",
@"proteinRate:",
@"physicalAge:",
@"ADC:",
@"temperature:",
@"standardWeight:",
@"weightControl:",
@"fatMass:",
@"weightWithoutFat:",
@"muscleMass:",
@"proteinMass:",
@"fatlevel:"
];
}
return _itemNameArr;
}


- (NSMutableArray *)itemValueArr {
if (_itemValueArr == nil) {
_itemValueArr = [[NSMutableArray alloc] init];
for (int i = 0; i < self.itemNameArr.count; i++) {
[_itemValueArr addObject:@"--.--"];
}
}
return _itemValueArr;
}


#pragma mark ============ life circle ==============

- (void)viewDidLoad {
[super viewDidLoad];
UITapGestureRecognizer *tap = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(makeViewEndEditing)];
[self.view addGestureRecognizer:tap];
//set default value
_appUser = [[AppUser alloc] init];
_appUser.sex = 1;
_appUser.age = 25;
_appUser.height = 175;
_appUser.weightKg = 0.0;
_appUser.adc = 0;
_userInfoLabel.text = [NSString stringWithFormat:@" sex:%d\n age:%d\n height:%d\n weight:%.1f\n adc:%d",_appUser.sex,_appUser.age,_appUser.height,_appUser.weightKg,_appUser.adc];
self.tableView.dataSource = self;
self.tableView.delegate = self;
//reset label
[self resetLBText];
}

- (void)makeViewEndEditing {
[self.view endEditing:YES];
}


- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
//setDelegate
[AnalysisBLEDataManager shareManager].infoDelegate = self;
[INBluetoothManager shareManager].delegate = self;
[INBluetoothManager enableSDKLogs:YES]; //open log switch
}

-(void)resetLBText {
self.itemValueArr = nil;
self.tipLB.text = @"--.--";
}


#pragma mark ============ click action ==============

- (IBAction)Click_Ble:(id)sender {
if ([INBluetoothManager shareManager].bleState != CBCentralManagerStatePoweredOn) {
[[[UIAlertView alloc] initWithTitle:@"Alert" message:@"BLE closed, pls open!" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil, nil] show];
return;
}

SearchDeviceVC *searchVC = [[SearchDeviceVC alloc]init];
__weak typeof(self) weakSelf = self;
searchVC.didSelectDeviceBlock = ^(DeviceModel *device) {
[weakSelf backFromSearchDeviceVC:device];
};
searchVC.gobackBlock = ^{
[weakSelf.connectedDevicesButton setTitle:@"Connect Device" forState:UIControlStateNormal];
};
[self presentViewController:searchVC animated:YES completion:nil];
}

- (void)backFromSearchDeviceVC:(DeviceModel *)device {
NSLog(@"---device:%@",device);

_targetDeviceModel = device;
[self.connectedDevicesButton setTitle:device.deviceAddress forState:UIControlStateNormal];
if (device.acNumber.intValue < 2) { //0、1 is broadcast scale
[[INBluetoothManager shareManager] handleDataForBroadScale:device];
} else { //2、3 is Link scale
[[INBluetoothManager shareManager] connectToLinkScale:device];
}
}


- (IBAction)editUser:(id)sender {
SetUserViewController *vc = [[SetUserViewController alloc] init];
vc.user = _appUser;
__weak typeof(self) weakSelf = self;
vc.editUserCallBack = ^{
weakSelf.userInfoLabel.text = [NSString stringWithFormat:@" sex:%d\n age:%d\n height:%d\n weight:%.1f\n adc:%d",weakSelf.appUser.sex,weakSelf.appUser.age,weakSelf.appUser.height,weakSelf.appUser.weightKg,weakSelf.appUser.adc];
[weakSelf syncWeighingUserToBle];
//If no need offline history function, do not call this method
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[weakSelf syncOfflineUserListToBle];
});
};
[self presentViewController:vc animated:YES completion:nil];
}


// click sync user button
- (void)syncWeighingUserToBle {
if (_targetDeviceModel.acNumber.intValue < 2) {
//broadcast scale do not need to sync user
} else {
//connect scale must input sex、weight、age
BLEUser *user = [[BLEUser alloc] init];
user.userSex = _appUser.sex;
user.userAge = _appUser.age;
user.userHeight = _appUser.height;
[[WriteToBLEManager shareManager] syncWeighingUser:user];
}
}


/// If no need offline history function, do not call this method
- (void)syncOfflineUserListToBle {
if (_targetDeviceModel.acNumber.intValue < 2) {
//broadcast scale can not receive write command
} else {
BLEUser *user = [[BLEUser alloc] init];
user.userSex = _appUser.sex;
user.userAge = _appUser.age;
user.userHeight = _appUser.height;
user.userWeight = _appUser.weightKg; //note
user.userAdc = _appUser.adc; //note
[[WriteToBLEManager shareManager] sendOfflineUserListToBle:@[user]]; //you can add more than one user to array
}
}

// click change unit segmentedControl
- (IBAction)ChooseUnit:(UISegmentedControl *)Segmented {
if (_targetDeviceModel.acNumber.intValue < 2) {
//broadcast scale can not receive write command
} else {
[[WriteToBLEManager shareManager] write_To_Unit:Segmented.selectedSegmentIndex];
NSString *weightShow = [self getWeightShowStr:_currentInfoModel unit:_unitSegmentedControl.selectedSegmentIndex];
[self.itemValueArr replaceObjectAtIndex:0 withObject:weightShow];
}
}

#pragma mark ============ BluetoothManagerDelegate ==============
- (void)BluetoothManager:(INBluetoothManager *)manager updateCentralManagerState:(BluetoothManagerState)state {
switch (state) {
case BluetoothManagerState_PowerOn:
{
_tipLB.text = @"BLE open";
break;
}
case BluetoothManagerState_PowerOff:
{
_tipLB.text = @"BLE closed";
break;
}
case BluetoothManagerState_Disconnect:
{
_tipLB.text = @"BLE Disconnect";
break;
}
default:
break;
}
}

//only used for link scale
- (void)BluetoothManager:(INBluetoothManager *)manager didConnectDevice:(DeviceModel *)deviceModel {
_targetDeviceModel = deviceModel;
}

#pragma mark - AnalysisBLEDataManagerDelegate

- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager updateBleDataAnalysisStatus:(BleDataAnalysisStatus)bleDataAnalysisStatus {
switch (bleDataAnalysisStatus) {
case BleDataAnalysisStatus_SyncTimeSuccess:
{
_tipLB.text = @"sync time success";
//set unit
[self ChooseUnit:self.unitSegmentedControl];
//then sync user to be weighing
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncWeighingUserToBle];
});

//sync offline userlist(If no need offline history function, do not call this method)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncOfflineUserListToBle];
});
//request history (If no need offline history function, do not call this method)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[WriteToBLEManager shareManager] requestOfflineHistory];
});

break;
}
case BleDataAnalysisStatus_SyncTimeFailed:
{
_tipLB.text = @"sync time failed";
break;
}
case BleDataAnalysisStatus_SyncUserSuccess:
{
_tipLB.text = @"sync weighing user success";
break;
}
case BleDataAnalysisStatus_SyncUserFailed:
{
_tipLB.text = @"sync weighing user failed";
break;
}
case BleDataAnalysisStatus_UnstableWeight:
{
_tipLB.text = @"measuring...\nUnstable Weight";
break;
}
case BleDataAnalysisStatus_StableWeight:
{
_tipLB.text = @"Stable Weight";
break;
}
case BleDataAnalysisStatus_MeasureComplete:
{
_tipLB.text = @"measure complete";
break;
}
case BleDataAnalysisStatus_AdcError:
{
_tipLB.text = @"adc measure failed";
break;
}
case BleDataAnalysisStatus_LightOff:
{
_tipLB.text = @"your linkScale light off";
break;
}
default:
break;
}
}

- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager updateMeasureUserInfo:(UserInfoModel *)infoModel {
NSLog(@"---infoModel:%@",infoModel);
_currentInfoModel = infoModel;
[self refreshTableView];
if (_currentInfoModel.measureStatus == MeasureStatus_Complete && _currentInfoModel.weightsum > 0 && _currentInfoModel.newAdc > 0) { //Measure Complete
float weight = _currentInfoModel.weightsum/pow(10, _currentInfoModel.weightOriPoint);//6895->68.95
float adc = _currentInfoModel.newAdc;
_appUser.weightKg = weight;
_appUser.adc = adc;
_userInfoLabel.text = [NSString stringWithFormat:@" sex:%d\n age:%d\n height:%d\n weight:%.1f\n adc:%d",_appUser.sex,_appUser.age,_appUser.height,_appUser.weightKg,_appUser.adc];
if (_targetDeviceModel.acNumber.intValue < 2) { //BroadScale BM15 mesure complete

AlgorithmModel *algModel = [AlgorithmSDK getBodyfatWithWeight:weight adc:adc sex:_appUser.sex age:_appUser.age height:_appUser.height];
NSLog(@"---BM15 AlgorithmModel: %@",algModel);
_currentInfoModel.fatRate = algModel.bfr.floatValue;
_currentInfoModel.BMI = algModel.bmi.floatValue;
_currentInfoModel.moisture = algModel.vwc.floatValue;
_currentInfoModel.muscle = algModel.rom.floatValue;
_currentInfoModel.BMR = algModel.bmr.floatValue;
_currentInfoModel.boneMass = algModel.bm.floatValue;
_currentInfoModel.visceralFat = algModel.uvi.floatValue;
_currentInfoModel.proteinRate = algModel.pp.floatValue;
_currentInfoModel.physicalAge = algModel.physicalAge.floatValue;
_currentInfoModel.subcutaneousFat = algModel.sfr.floatValue;
//refresh
[self refreshTableView];
} else { //connect scale measure complete
[self syncWeighingUserToBle];
// If no need offline history function, do not call this method
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncOfflineUserListToBle];
});
}

}
}


- (void)refreshTableView {
NSString *weightShow = [self getWeightShowStr:_currentInfoModel unit:_unitSegmentedControl.selectedSegmentIndex];
[self.itemValueArr replaceObjectAtIndex:0 withObject:weightShow];
[self.itemValueArr replaceObjectAtIndex:1 withObject:[NSString stringWithFormat:@"%.1f",_currentInfoModel.BMI]];
[self.itemValueArr replaceObjectAtIndex:2 withObject:[NSString stringWithFormat:@"%.1f",_currentInfoModel.fatRate]];
[self.itemValueArr replaceObjectAtIndex:3 withObject:[NSString stringWithFormat:@"%.1f%",_currentInfoModel.muscle]];
[self.itemValueArr replaceObjectAtIndex:4 withObject:[NSString stringWithFormat:@"%.1f%",_currentInfoModel.moisture]];
[self.itemValueArr replaceObjectAtIndex:5 withObject:[NSString stringWithFormat:@"%.1f",_currentInfoModel.boneMass]];
[self.itemValueArr replaceObjectAtIndex:6 withObject:[NSString stringWithFormat:@"%.1fkcal",_currentInfoModel.BMR]];
[self.itemValueArr replaceObjectAtIndex:7 withObject:[NSString stringWithFormat:@"%.0f",_currentInfoModel.visceralFat]];
[self.itemValueArr replaceObjectAtIndex:8 withObject:[NSString stringWithFormat:@"%.1f%",_currentInfoModel.subcutaneousFat]];
[self.itemValueArr replaceObjectAtIndex:9 withObject:[NSString stringWithFormat:@"%.1f%",_currentInfoModel.proteinRate]];
[self.itemValueArr replaceObjectAtIndex:10 withObject:[NSString stringWithFormat:@"%.1f",_currentInfoModel.physicalAge]];
[self.itemValueArr replaceObjectAtIndex:11 withObject:[NSString stringWithFormat:@"%.0f",_currentInfoModel.newAdc]];
[self.itemValueArr replaceObjectAtIndex:12 withObject:[NSString stringWithFormat:@"%.1f°C",_currentInfoModel.temperature]];
float weight = _currentInfoModel.weightsum/pow(10, _currentInfoModel.weightOriPoint);//6895->68.95
int sex = _appUser.sex;
int height = _appUser.height;
NSString *bfr = [NSString stringWithFormat:@"%.1f",_currentInfoModel.fatRate];
NSString *rom = [NSString stringWithFormat:@"%.1f%",_currentInfoModel.muscle];
NSString *pp = [NSString stringWithFormat:@"%.1f%",_currentInfoModel.proteinRate];
BfsCalculateItem *item = [BfsCalculateSDK getBodyfatItemWithSex:sex height:height weight:weight bfr:bfr rom:rom pp:pp];

[self.itemValueArr replaceObjectAtIndex:13 withObject:[NSString stringWithFormat:@"%.1fkg",item.standardWeight]];
[self.itemValueArr replaceObjectAtIndex:14 withObject:[NSString stringWithFormat:@"%.1fkg",item.weightControl]];
[self.itemValueArr replaceObjectAtIndex:15 withObject:[NSString stringWithFormat:@"%.1fkg",item.fatMass]];
[self.itemValueArr replaceObjectAtIndex:16 withObject:[NSString stringWithFormat:@"%.1fkg",item.weightWithoutFat]];
[self.itemValueArr replaceObjectAtIndex:17 withObject:[NSString stringWithFormat:@"%.1fkg",item.muscleMass]];
[self.itemValueArr replaceObjectAtIndex:18 withObject:[NSString stringWithFormat:@"%.1fkg",item.proteinMass]];
[self.itemValueArr replaceObjectAtIndex:19 withObject:[NSString stringWithFormat:@"%zd",item.fatlevel]];
[self.tableView reloadData];
}

//If no need offline history function, do not implement this callback
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager backOfflineHistorys:(NSMutableArray <UserInfoModel *> *)historysMutableArr {
_tipLB.text = [NSString stringWithFormat:@"Got %zd offline historys! check sdk log.",historysMutableArr.count];
for (UserInfoModel *info in historysMutableArr) {
NSLog(@"---get offline history:\n %@",info);
}

}

#pragma mark ============ tableView datasource ==============
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return self.itemNameArr.count;
}

static NSString * const CellID = @"CellID";
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellID];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleValue1 reuseIdentifier:CellID];
cell.textLabel.textColor = [UIColor blackColor];
cell.detailTextLabel.textColor = [UIColor blueColor];
}
//赋值
cell.textLabel.text = self.itemNameArr[indexPath.row];
cell.detailTextLabel.text = self.itemValueArr[indexPath.row];
return cell;
}


#pragma mark ============ handle weight point ==============

// change weight unit
- (NSString *)getWeightShowStr:(UserInfoModel *)infoModel unit:(NSInteger)unit {
float weight = infoModel.weightsum/pow(10, infoModel.weightOriPoint);//6895->68.95
NSString *formatStr = [NSString stringWithFormat:@"%%.%df",infoModel.weightKgPoint]; //@"%.1f"
NSString *showWeight = @"";
if (unit == 0) {
formatStr = [formatStr stringByAppendingString:@"kg"]; //@"%.1fkg"
showWeight = [NSString stringWithFormat:formatStr,weight];
} else if (unit == 1) {
formatStr = [formatStr stringByAppendingString:@"lb"]; //@"%.1flb"
showWeight = [NSString stringWithFormat:formatStr,weight*2.2046226f];
} else if (unit == 2) {
showWeight = [self kg2St:weight]; //st(lb/14): **lb:**st
} else if (unit == 3) {
formatStr = [formatStr stringByAppendingString:@"斤"]; //@"%.1f斤"
showWeight = [NSString stringWithFormat:formatStr,weight*2];
}else {
formatStr = [formatStr stringByAppendingString:@"kg"]; //@"%.1fkg"
showWeight = [NSString stringWithFormat:formatStr,weight];
}
return showWeight;
}


- (NSString *)kg2St:(float)kgWeight {
NSString *oneString = [NSString stringWithFormat:@"%d",(int)(kgWeight*2.2046226f)/14];
NSString *twoString = [NSString stringWithFormat:@"%d",((int)(kgWeight*2.2046226f)%14)];
return [NSString stringWithFormat:@"%@:%@st",oneString,twoString];
}



@end






+ 17
- 0
AIFit-Demo/SearchDeviceVC.h View File

@@ -0,0 +1,17 @@
//
// AIFit-Demo
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <UIKit/UIKit.h>

@class DeviceModel;
@interface SearchDeviceVC : UIViewController

@property (nonatomic, copy) void(^didSelectDeviceBlock)(DeviceModel *device);

@property (nonatomic, copy) void(^gobackBlock)(void);

@end

+ 193
- 0
AIFit-Demo/SearchDeviceVC.m View File

@@ -0,0 +1,193 @@
//
// AIFit-Demo
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import "SearchDeviceVC.h"
#import <InetBleSDK/InetBleSDK.h>
#import "MainViewController.h"

@interface SearchDeviceVC () <UITableViewDelegate,UITableViewDataSource,INBluetoothManagerDelegate>
{
CGFloat topDis;
}

@property (nonatomic, strong)UITableView *BleTableView;
@property (nonatomic, strong) NSMutableArray *peripheralArray;
@property (nonatomic, assign) BOOL isAddPeripheraling;



@end

@implementation SearchDeviceVC

#pragma mark - ================= 视图 ==========================
- (void)viewDidLoad
{
[super viewDidLoad];
self.view.backgroundColor = [UIColor colorWithRed:235/255.0 green:250/255.0 blue:250/255.0 alpha:1.0];
[self setupBackButton];
[self setupStartScanBtn];
[self setupStopScanBtn];
[self setupTableView];
if ([INBluetoothManager shareManager].bleState == CBCentralManagerStatePoweredOn) {
[INBluetoothManager shareManager].delegate = self;
[[INBluetoothManager shareManager] startBleScan];
} else {
NSLog(@"---Error: BLE not avalible, pls check.");
}
}


-(void)setupBackButton
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
topDis = (UIScreen.mainScreen.bounds.size.height == 812) ? (34+10) : (20+10);
btn.frame = CGRectMake(25, topDis, 250, 40);
[btn setTitle:@"<< BackAndCloseBLE" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
[btn setContentHorizontalAlignment:UIControlContentHorizontalAlignmentLeft];
[self.view addSubview:btn];
[btn addTarget:self action:@selector(goBack) forControlEvents:UIControlEventTouchUpInside];
}
-(void)goBack
{
[[INBluetoothManager shareManager] closeBleAndDisconnect];
__weak typeof(self) weakSelf = self;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
weakSelf.gobackBlock();
[weakSelf dismissViewControllerAnimated:YES completion:nil];
});

}


- (void)setupStartScanBtn
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(25, topDis+40+10, 100, 40);
[btn setTitle:@"start scan" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
btn.backgroundColor = [UIColor whiteColor];
[self.view addSubview:btn];
[btn addTarget:self action:@selector(scanPeripheral) forControlEvents:UIControlEventTouchUpInside];
}


- (void)setupStopScanBtn
{
UIButton *btn = [UIButton buttonWithType:UIButtonTypeSystem];
btn.frame = CGRectMake(self.view.bounds.size.width-25-100, topDis+40+10, 100, 40);
[btn setTitle:@"stop scan" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
btn.backgroundColor = [UIColor whiteColor];
[self.view addSubview:btn];
[btn addTarget:self action:@selector(stopScan) forControlEvents:UIControlEventTouchUpInside];
}

- (void)setupTableView {
_BleTableView = [[UITableView alloc]init];
_BleTableView.frame = CGRectMake(25, topDis+50+50, self.view.bounds.size.width-50, self.view.bounds.size.height-(topDis+50+50)-20);
_BleTableView.dataSource = self;
_BleTableView.delegate = self;
[self.view addSubview:_BleTableView];
}

- (void)scanPeripheral
{
[[INBluetoothManager shareManager] startBleScan];
}

- (void)stopScan
{
[[INBluetoothManager shareManager] stopBleScan];
}


#pragma mark - BluetoothManagerDelegate

- (void)BluetoothManager:(INBluetoothManager *)manager didDiscoverDevice:(DeviceModel *)deviceModel
{

if (self.isAddPeripheraling == YES) return;
self.isAddPeripheraling = YES;
BOOL willAdd = YES;
for (DeviceModel *model in self.peripheralArray) //avoid add the same device
{
if ([model.deviceAddress isEqualToString:deviceModel.deviceAddress] && [model.deviceName isEqualToString:deviceModel.deviceName])
{
willAdd = NO;
}
}
if (willAdd) {
[self.peripheralArray addObject:deviceModel];
[self.BleTableView reloadData];
}
self.isAddPeripheraling = NO;
}


#pragma mark - UITableViewDataSource

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return self.peripheralArray.count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"AIFitCell"];
if (!cell) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"AIFitCell"];
}
DeviceModel *peripheralModel = self.peripheralArray[indexPath.row];
cell.textLabel.text = peripheralModel.deviceName;
cell.detailTextLabel.text = peripheralModel.deviceAddress;

return cell;
}

-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
DeviceModel *peripheralModel = self.peripheralArray[indexPath.row];

if (_didSelectDeviceBlock) {
_didSelectDeviceBlock(peripheralModel);
//note: just go back, keep ble scan all the time
[self dismissViewControllerAnimated:YES completion:nil];
}

}


#pragma mark - Setter and Getter

- (NSMutableArray *)peripheralArray
{
if (_peripheralArray == nil) {
_peripheralArray = [[NSMutableArray alloc] init];
}
return _peripheralArray;
}

- (void)dealloc
{
NSLog(@"---class:%@ instance:%p already dealloc!",self.class,self);
}

@end

+ 21
- 0
AIFit-Demo/SetUserViewController.h View File

@@ -0,0 +1,21 @@
//
// SetUserViewController.h
// AIFit-Demo
//
// Created by steven wu on 2019/12/20.
// Copyright © 2019 wujia121. All rights reserved.
//

#import <UIKit/UIKit.h>
@class AppUser;
NS_ASSUME_NONNULL_BEGIN

@interface SetUserViewController : UIViewController

@property (nonatomic, strong) AppUser *user;

@property (nonatomic, copy) void(^editUserCallBack)(void);

@end

NS_ASSUME_NONNULL_END

+ 45
- 0
AIFit-Demo/SetUserViewController.m View File

@@ -0,0 +1,45 @@
//
// SetUserViewController.m
// AIFit-Demo
//
// Created by steven wu on 2019/12/20.
// Copyright © 2019 wujia121. All rights reserved.
//

#import "SetUserViewController.h"
#import "AppUser.h"
#import <InetBleSDK/InetBleSDK.h>

@interface SetUserViewController ()

@property (weak, nonatomic) IBOutlet UISegmentedControl *sexSegmentedC;
@property (weak, nonatomic) IBOutlet UITextField *ageTextF;
@property (weak, nonatomic) IBOutlet UITextField *heightTextF;

@end

@implementation SetUserViewController

- (void)viewDidLoad {
[super viewDidLoad];
_sexSegmentedC.selectedSegmentIndex = self.user.sex == 1 ? 0 : 1;
_ageTextF.text = [NSString stringWithFormat:@"%d",self.user.age];
_heightTextF.text = [NSString stringWithFormat:@"%d",self.user.height];
}


- (IBAction)saveUserInfo:(id)sender {
_user.sex = _sexSegmentedC.selectedSegmentIndex == 0 ? 1 : 2; //male:1 female:2
_user.age = _ageTextF.text.intValue;
_user.height = _heightTextF.text.intValue;
if (_editUserCallBack) {
_editUserCallBack();
}
[self dismissViewControllerAnimated:YES completion:nil];
}



@end

+ 109
- 0
AIFit-Demo/SetUserViewController.xib View File

@@ -0,0 +1,109 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="14490.70" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES">
<device id="retina6_1" orientation="portrait">
<adaptation id="fullscreen"/>
</device>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="14490.49"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<objects>
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="SetUserViewController">
<connections>
<outlet property="ageTextF" destination="vHr-Ek-MOn" id="PsD-0X-Yz0"/>
<outlet property="heightTextF" destination="gaE-XL-e9v" id="6hD-fd-SIm"/>
<outlet property="sexSegmentedC" destination="zDW-b7-hgQ" id="wmY-vU-6TK"/>
<outlet property="view" destination="i5M-Pr-FkT" id="sfx-zR-JGt"/>
</connections>
</placeholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/>
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="i5M-Pr-FkT">
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Set User Info" textAlignment="center" lineBreakMode="tailTruncation" numberOfLines="0" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="cCJ-dU-qVg">
<rect key="frame" x="107" y="60" width="200" height="40"/>
<constraints>
<constraint firstAttribute="width" constant="200" id="L3v-jq-db6"/>
<constraint firstAttribute="height" constant="40" id="aAm-Uo-8Wh"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<segmentedControl opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="top" segmentControlStyle="plain" selectedSegmentIndex="0" translatesAutoresizingMaskIntoConstraints="NO" id="zDW-b7-hgQ">
<rect key="frame" x="207" y="180" width="153" height="29"/>
<segments>
<segment title="Male(1)"/>
<segment title="Female(2)"/>
</segments>
</segmentedControl>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Age :" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="sZN-4s-rmi">
<rect key="frame" x="128" y="253" width="39" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Height :" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Smm-hx-0FP">
<rect key="frame" x="107" y="323" width="60" height="20.5"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="25" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="vHr-Ek-MOn">
<rect key="frame" x="207" y="248" width="153" height="30"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<textInputTraits key="textInputTraits"/>
</textField>
<textField opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="left" contentVerticalAlignment="center" text="172" borderStyle="roundedRect" textAlignment="natural" minimumFontSize="17" translatesAutoresizingMaskIntoConstraints="NO" id="gaE-XL-e9v">
<rect key="frame" x="207" y="318" width="153" height="30"/>
<nil key="textColor"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/>
<textInputTraits key="textInputTraits"/>
</textField>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Sex :" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="iwH-k3-tJl">
<rect key="frame" x="129" y="183.5" width="38" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="roundedRect" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="iag-qe-5sf">
<rect key="frame" x="334" y="55" width="60" height="50"/>
<constraints>
<constraint firstAttribute="height" constant="50" id="0Oe-e7-65D"/>
<constraint firstAttribute="width" constant="60" id="YZ8-qE-lCY"/>
</constraints>
<fontDescription key="fontDescription" type="system" pointSize="18"/>
<state key="normal" title="SAVE"/>
<connections>
<action selector="saveUserInfo:" destination="-1" eventType="touchUpInside" id="GNI-Zp-ynI"/>
</connections>
</button>
</subviews>
<color key="backgroundColor" red="1" green="1" blue="1" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<constraints>
<constraint firstItem="gaE-XL-e9v" firstAttribute="width" secondItem="vHr-Ek-MOn" secondAttribute="width" id="8Iv-Mw-cr8"/>
<constraint firstItem="vHr-Ek-MOn" firstAttribute="leading" secondItem="zDW-b7-hgQ" secondAttribute="leading" id="96O-ga-aal"/>
<constraint firstItem="iwH-k3-tJl" firstAttribute="centerY" secondItem="zDW-b7-hgQ" secondAttribute="centerY" id="ABB-er-Ht3"/>
<constraint firstItem="zDW-b7-hgQ" firstAttribute="leading" secondItem="iwH-k3-tJl" secondAttribute="trailing" constant="40" id="AoC-0V-OYP"/>
<constraint firstItem="vHr-Ek-MOn" firstAttribute="width" secondItem="zDW-b7-hgQ" secondAttribute="width" id="KMM-XI-gfe"/>
<constraint firstItem="zDW-b7-hgQ" firstAttribute="leading" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="Pht-uG-LBF"/>
<constraint firstAttribute="trailing" secondItem="iag-qe-5sf" secondAttribute="trailing" constant="20" id="W5p-Aj-xhW"/>
<constraint firstItem="gaE-XL-e9v" firstAttribute="leading" secondItem="vHr-Ek-MOn" secondAttribute="leading" id="YMY-14-YT8"/>
<constraint firstItem="iag-qe-5sf" firstAttribute="centerY" secondItem="cCJ-dU-qVg" secondAttribute="centerY" id="ZAV-ME-3YI"/>
<constraint firstItem="zDW-b7-hgQ" firstAttribute="top" secondItem="cCJ-dU-qVg" secondAttribute="bottom" constant="80" id="auh-QW-xIM"/>
<constraint firstItem="gaE-XL-e9v" firstAttribute="top" secondItem="vHr-Ek-MOn" secondAttribute="bottom" constant="40" id="cv9-ZC-Rh7"/>
<constraint firstItem="cCJ-dU-qVg" firstAttribute="centerX" secondItem="i5M-Pr-FkT" secondAttribute="centerX" id="d92-zY-wNc"/>
<constraint firstItem="Smm-hx-0FP" firstAttribute="trailing" secondItem="sZN-4s-rmi" secondAttribute="trailing" id="dGT-7Y-6Bu"/>
<constraint firstItem="Smm-hx-0FP" firstAttribute="centerY" secondItem="gaE-XL-e9v" secondAttribute="centerY" id="fRX-JI-rOy"/>
<constraint firstItem="vHr-Ek-MOn" firstAttribute="top" secondItem="zDW-b7-hgQ" secondAttribute="bottom" constant="40" id="iEf-tC-j8I"/>
<constraint firstItem="sZN-4s-rmi" firstAttribute="trailing" secondItem="iwH-k3-tJl" secondAttribute="trailing" id="nNp-Qb-jqf"/>
<constraint firstItem="cCJ-dU-qVg" firstAttribute="top" secondItem="i5M-Pr-FkT" secondAttribute="top" constant="60" id="qxQ-PV-4FH"/>
<constraint firstItem="sZN-4s-rmi" firstAttribute="centerY" secondItem="vHr-Ek-MOn" secondAttribute="centerY" id="wrr-fg-Jqj"/>
</constraints>
<point key="canvasLocation" x="137.68115942028987" y="152.67857142857142"/>
</view>
</objects>
</document>

+ 16
- 0
AIFit-Demo/main.m View File

@@ -0,0 +1,16 @@
//
// main.m
// AIFit-Demo
//
// Created by wujia121 on 2018/9/1.
// Copyright © 2018年 wujia121. All rights reserved.
//

#import <UIKit/UIKit.h>
#import "AppDelegate.h"

int main(int argc, char * argv[]) {
@autoreleasepool {
return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
}
}

+ 40
- 0
AIFit-DemoUITests/AIFit_DemoUITests.m View File

@@ -0,0 +1,40 @@
//
// AIFit_DemoUITests.m
// AIFit-DemoUITests
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <XCTest/XCTest.h>

@interface AIFit_DemoUITests : XCTestCase

@end

@implementation AIFit_DemoUITests

- (void)setUp {
[super setUp];
// Put setup code here. This method is called before the invocation of each test method in the class.
// In UI tests it is usually best to stop immediately when a failure occurs.
self.continueAfterFailure = NO;
// UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
[[[XCUIApplication alloc] init] launch];
// In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
}

- (void)tearDown {
// Put teardown code here. This method is called after the invocation of each test method in the class.
[super tearDown];
}

- (void)testExample {
// Use recording to get started writing UI tests.
// Use XCTAssert and related functions to verify your tests produce the correct results.
}

@end

+ 22
- 0
AIFit-DemoUITests/Info.plist View File

@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>BNDL</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
</dict>
</plist>

+ 67
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/AlgorithmSDK.h View File

@@ -0,0 +1,67 @@
//
// Algorithm.h
// GreatBody
//
// Created by steven wu on 2019/6/25.
//

#import <Foundation/Foundation.h>

typedef NS_ENUM(NSInteger, AlgUserSex) {
AlgUserSex_Male = 1,
AlgUserSex_Female = 2,
};


@interface AlgorithmModel : NSObject

///bmi
@property (nonatomic, copy) NSString *bmi;
///体脂率 bodyfatRate
@property (nonatomic, copy) NSString *bfr;
///皮下脂肪率 subcutaneousFat rate
@property (nonatomic, copy) NSString *sfr;
///内脏脂肪率 visceralFat rate
@property (nonatomic, copy) NSString *uvi;
///肌肉率 muscle rate
@property (nonatomic, copy) NSString *rom;
///基础代谢率 BMR
@property (nonatomic, copy) NSString *bmr;
///骨骼质量 boneMass
@property (nonatomic, copy) NSString *bm;
///水含量vwc: moisture
@property (nonatomic, copy) NSString *vwc;
///身体年龄 physicalAge
@property (nonatomic, assign) NSString *physicalAge;
///蛋白率 proteinRate
@property (nonatomic, copy) NSString *pp;


/* For example
bmi : 23.7;
bfr : 22.2;
rom : 51;
vwc : 57;
bm : 2.8;
sfr : 19.9;
bmi : 1549;
pp : 16.6;
uvi : 7;
physicalAge : 26;
*/
@end


@interface AlgorithmSDK : NSObject

/**
* Inet AlgorithmSDK 品网算法
* Incoming user information + adc, calculate 10 original body fat data (the connected scale is calculated by the scale end and transmitted to the app via Bluetooth, and the broadcast scale calls this SDK calculation) 传入用户信息+adc,计算出10项原始体脂数据(连接秤由秤端计算并蓝牙传给app,广播秤调用本SDK计算)
* eg:
* kgWeight: 50.6 age: 25 height: 175
*/
+ (AlgorithmModel *)getBodyfatWithWeight:(double)kgWeight adc:(int)adc sex:(AlgUserSex)sex age:(int)age height:(int)height;

@end



+ 54
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/AnalysisBLEDataManager.h View File

@@ -0,0 +1,54 @@
//
// InetBleSDK
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
@class UserInfoModel;


/**
Note:
linkScale has all below status, but broadcastScale just has //b1,b2,b3
*/
typedef NS_ENUM(NSInteger, BleDataAnalysisStatus) {
BleDataAnalysisStatus_SyncTimeSuccess,
BleDataAnalysisStatus_SyncTimeFailed, //lead to error measureTime
BleDataAnalysisStatus_SyncUserSuccess,
BleDataAnalysisStatus_SyncUserFailed, //lead to no bodydata, just weight
BleDataAnalysisStatus_UnstableWeight, //b1
BleDataAnalysisStatus_StableWeight, //b2
BleDataAnalysisStatus_MeasureComplete, //b3
BleDataAnalysisStatus_AdcError,
BleDataAnalysisStatus_LightOff,
};

@class AnalysisBLEDataManager;

@protocol AnalysisBLEDataManagerDelegate <NSObject>
@optional

- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager updateBleDataAnalysisStatus:(BleDataAnalysisStatus)bleDataAnalysisStatus;

- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager updateMeasureUserInfo:(UserInfoModel *)infoModel;

///If no need offline history function, do not implement this callback
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager backOfflineHistorys:(NSMutableArray <UserInfoModel *> *)historysMutableArr;

@end




@interface AnalysisBLEDataManager : NSObject

+ (instancetype)shareManager;
@property (nonatomic, weak) id<AnalysisBLEDataManagerDelegate> infoDelegate;

@end

+ 39
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/BLEUser.h View File

@@ -0,0 +1,39 @@
//
// InetBleSDK
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface BLEUser : NSObject


/**
eg: male:1, femail: 2
*/
@property (nonatomic, assign) int userSex;


/**
eg: 26
*/
@property (nonatomic, assign) int userAge;

/**
eg: 175
*/
@property (nonatomic, assign) int userHeight;

/**
eg: 56.5kg
*/
@property (nonatomic, assign) float userWeight;

/**
eg: 560
*/
@property (nonatomic, assign) int userAdc;

@end

+ 89
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/BfsCalculateSDK.h View File

@@ -0,0 +1,89 @@
//
// FRK_fatScalesSDK.h
// FRK_fatScalesSDK
//
// Created by zhang on 17/2/24.
// Copyright © 2017年 taolei. All rights reserved.
//

#import <Foundation/Foundation.h>

typedef NS_ENUM(NSInteger, BfsUserSex) {
BfsUserSex_Male = 1,
BfsUserSex_Female = 2,
};


@interface BfsCalculateItem : NSObject

/**
* 标准体重 standardWeight
*/
@property (nonatomic, assign) double standardWeight;
/**
* 体重控制量 weightControl
*/
@property (nonatomic, assign) double weightControl;
/**
* 脂肪量 fatMass
*/
@property (nonatomic, assign) double fatMass;
/**
* 去脂体重 weightWithoutFat
*/
@property (nonatomic, assign) double weightWithoutFat;
/**
* 肌肉量 muscleMass
*/
@property (nonatomic, assign) double muscleMass;
/**
* 蛋白量 proteinMass
*/
@property (nonatomic, assign) double proteinMass;
/**
* 肥胖等级 fatlevel
* 1.标准 standard
* 2.偏瘦 thin
* 3.偏重 over weight
* 4.体重不足 insufficient
* 5.超重 Severely overweight
*/
@property (nonatomic, assign) NSInteger fatlevel;


/** For example
(double) _standardWeight = 66.5
(double) _weightControl = 6.1999998092651367
(double) _fatMass = 16.100000381469727
(double) _weightWithoutFat = 56.599998474121094
(double) _muscleMass = 37.099998474121094
(double) _proteinMass = 12.100000381469727
(NSInteger) _fatlevel = 1
*/
@end



@interface BfsCalculateSDK : NSObject


/**
* According to the bfr / rom / pp in the basic parameters returned by the scale, calculate 7 additional items that the App needs to display 根据秤返回的基本参数中的bfr/rom/pp,计算出App需要额外显示的7个项目
*@param sex
* 性别: 男:1 女 2
* @param height
* 身高:1~270(CM)
* @param weight
* 体重:1~220(KG)
* @param bfr
* 体脂率 43.6
* @param rom
* 肌肉率 55.2
* @param pp
* 蛋白率 25.9
* @return BfsCalculateItem
*/
+ (BfsCalculateItem *)getBodyfatItemWithSex:(BfsUserSex)sex height:(NSInteger)height weight:(double)weight bfr:(NSString *)bfr rom:(NSString *)rom pp:(NSString *)pp;


@end

+ 60
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/BleTools.h View File

@@ -0,0 +1,60 @@
//
// BleTools.h
// GreatBody
//
// Created by steven wu on 2019/6/25.
//

#import <Foundation/Foundation.h>

@interface BleTools : NSObject


/**
得到当前时间,年月日时分秒
*/
+ (NSString *)returnCurrentTime;

/**
计算两个时间的差值,单位:秒
*/
+ (NSString *)getTimeInterval:(NSString *)startTime end:(NSString *)endTime;

/**
十进制整数byte(0-255)转二进制字符串,如 255 =》@"11111111"
*/
+ (NSString *)returnBinaryStringWithByte:(Byte)byte;
/**
二进制字符串 =》 十进制整数字符串,如 @"11111111" =》@"255"
*/
+ (NSString *)toDecimalSystemWithBinarySystem:(NSString *)binary;

/**
蓝牙部分使用判断版本
*/
+ (NSInteger)compareDate:(NSString*)aDate withDate:(NSString*)bDate;


///将传入的data转换为16进制字符串格式<xxxx xxxx>
/// IOS13以后苹果修改了NSData的-description实现方式
/// iOS13之前:<ac02fa02 0000ccc8>
/// iOS13之后:{length = 8, bytes = 0xac02fa020000ccc8}
+ (NSString *)hexStrFromData:(NSData *)data;


#pragma mark ============ 根据给定的原始kg整数(如565)、单位、小数点,转换为要显示的值(如56.5或8:12.6) ==============

///getKg
+ (NSString *)getKg_withKgSum:(NSString *)kgIntStr kgOriginDecimal:(NSInteger)kgOriginDecimal kgShowDecimal:(NSInteger)kgShowDecimal kggraduation:(NSInteger)kg_graduation lbgraduation:(NSInteger)lb_graduation isJin:(BOOL)jin;

///getLb
+ (NSString *)getLb_withKgSum:(NSString *)kgIntStr kgOriginDecimal:(NSInteger)kgOriginDecimal lbShowDecimal:(NSInteger)lbShowDecimal kggraduation:(NSInteger)kg_graduation lbgraduation:(NSInteger)lb_graduation;

///getSt
+ (NSString *)getSt_withKgSum:(NSString *)kgIntStr kgOriginDecimal:(NSInteger)kgOriginDecimal stShowDecimal:(NSInteger)stShowDecimal kggraduation:(NSInteger)kg_graduation lbgraduation:(NSInteger)lb_graduation;

///getJin
+ (NSString *)getJin_withKgSum:(NSString *)kgIntStr kgOriginDecimal:(NSInteger)kgOriginDecimal kgShowDecimal:(NSInteger)kgShowDecimal kggraduation:(NSInteger)kg_graduation lbgraduation:(NSInteger)lb_graduation isJin:(BOOL)jin;

@end


+ 53
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/DeviceModel.h View File

@@ -0,0 +1,53 @@
//
// InetBleSDK
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>

@interface DeviceModel : NSObject

@property(nonatomic, copy) NSString *deviceUUIDString;

@property(nonatomic, copy) NSString *deviceName;


/**
ble scale type:
0: broadcast
1: broadcast(temperature)
2: linkScale
3: linkScale(temperature)
*/
@property(nonatomic, strong) NSNumber *acNumber;

@property(nonatomic, copy) NSString *deviceAddress;

@property(nonatomic, assign) BOOL deviceIsLight;

//algorithm(so far only used for BM15)
//@property (nonatomic,assign) NSInteger Algorithm_number;

//DID
@property (nonatomic,assign) NSInteger DID_number;

/**
-centralManager:didDiscoverPeripheral:advertisementData:RSSI
this DeviceModel created base on this peripheral
*/
@property (strong, nonatomic) CBPeripheral *peripheral;

@end

/*
deviceUUIDString : CA2A7E77-D709-4F29-1552-AE69BC4A3752;
deviceName : SWAN;
acNumber : 2;
deviceAddress : 03:B3:EC:8F:70:76;
deviceIsLight : 0;
Algorithm_number : 0;
DID_number : 0;
*/

+ 64
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/INBluetoothManager.h View File

@@ -0,0 +1,64 @@
//
// InetBleSDK
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <Foundation/Foundation.h>
#import <CoreBluetooth/CoreBluetooth.h>
@class UserInfoModel,DeviceModel;

typedef NS_ENUM(NSInteger,BluetoothManagerState) {
BluetoothManagerState_PowerOn,
BluetoothManagerState_PowerOff,
BluetoothManagerState_UnknowErr,
BluetoothManagerState_StartScan,
BluetoothManagerState_StopScan,
BluetoothManagerState_ConnectSuccess,
BluetoothManagerState_ConnectFailed,
BluetoothManagerState_Disconnect
};


@class INBluetoothManager;
@protocol INBluetoothManagerDelegate <NSObject>

@optional
- (void)BluetoothManager:(INBluetoothManager *)manager didDiscoverDevice:(DeviceModel *)deviceModel;

@optional
- (void)BluetoothManager:(INBluetoothManager *)manager didConnectDevice:(DeviceModel *)deviceModel;

@optional
- (void)BluetoothManager:(INBluetoothManager *)manager updateCentralManagerState:(BluetoothManagerState)state;

@end



@interface INBluetoothManager : NSObject

//apply sdk key website http://sdk.aicare.net.cn/
+ (void)configAppKey:(NSString *)appKey secret:(NSString *)appSecret;

+ (instancetype)shareManager;

@property (nonatomic, weak) id <INBluetoothManagerDelegate> delegate;
@property (nonatomic, assign, readonly) CBCentralManagerState bleState;

- (void)startBleScan;
- (void)stopBleScan;
- (void)closeBleAndDisconnect;

- (void)connectToLinkScale:(DeviceModel *)linkScaleDeviceModel;
- (void)handleDataForBroadScale:(DeviceModel *)broadScaleDeviceModel;

//SDK使用者无需调用此方法,直接使用WriteToBLEManager来写入即可
- (void)sendDataToBle:(NSData *)data;

+ (void)enableSDKLogs:(BOOL)enable;

+ (NSString *)sdkVersion;

@end

+ 22
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/InetBleSDK.h View File

@@ -0,0 +1,22 @@
//
// InetBleSDK
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#ifndef InetBleSDK_h
#define InetBleSDK_h

#import "INBluetoothManager.h"
#import "AnalysisBLEDataManager.h"
#import "WriteToBLEManager.h"
#import "DeviceModel.h"
#import "UserInfoModel.h"
#import "BLEUser.h"
#import "AlgorithmSDK.h"
#import "BfsCalculateSDK.h"
#import "BleTools.h"

#endif /* InetBleSDK_h */


+ 129
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/UserInfoModel.h View File

@@ -0,0 +1,129 @@
//
// InetBleSDK
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <Foundation/Foundation.h>
@class BLEUser;


typedef NS_ENUM(NSInteger, WeightUnitType) {
WeightUnitType_KG = 0,
WeightUnitType_LB,
WeightUnitType_ST,
WeightUnitType_JIN,
};

typedef NS_ENUM(NSInteger, MeasureStatus) {
MeasureStatus_Unstable = 0,
MeasureStatus_Stable,
MeasureStatus_Complete,
MeasureStatus_OfflineHistory,
};

@interface UserInfoModel : NSObject<NSCopying>

//@property (nonatomic, assign) double weightTimeStamp;
@property (nonatomic, copy) NSString *date;
@property (nonatomic, copy) NSString *time;

///only used for offline history, other it is empty
@property (nonatomic, strong) BLEUser *bleUser;


/// weight
@property (nonatomic, assign) float weightsum;

/// TEMP
@property (nonatomic, assign) float temperature;

/// BMI
@property (nonatomic, assign) float BMI;

/// bfr
@property (nonatomic, assign) float fatRate;

/// rom
@property (nonatomic, assign) float muscle;

/// vwc
@property (nonatomic, assign) float moisture;

/// bm
@property (nonatomic, assign) float boneMass;

/// sfr
@property (nonatomic, assign) float subcutaneousFat;

/// bmr
@property (nonatomic, assign) float BMR;

/// pp
@property (nonatomic, assign) float proteinRate;

/// uvi
@property (nonatomic, assign) float visceralFat;

/// bodyAge
@property (nonatomic, assign) float physicalAge;

/// adc
@property (nonatomic, assign) float newAdc;

/// kg origin point
@property (nonatomic, assign) int weightOriPoint;

/// kg show point
@property (nonatomic, assign) int weightKgPoint;

/// lb show point
@property (nonatomic, assign) int weightLbPoint;

/// st show point
@property (nonatomic, assign) int weightStPoint;

/// kg show graduation
@property (nonatomic, assign) int KGgraduation;

/// lb show graduation
@property (nonatomic, assign) int LBgradution;

//algorithm(so far only used for BM15)
@property (nonatomic, assign) NSInteger Algorithm_number;

/// bm15 broad scale now showing unit
@property (nonatomic, assign) WeightUnitType bm15ScaleUnit;

@property (nonatomic, assign) MeasureStatus measureStatus;

@end

/* For example
date : 2019-12-23;
time : 17:22:28;
bleUser : <BLEUser: 0x2808e0840>;
weightsum : 727;
temperature : 24.5;
BMI : 23.7;
fatRate : 22.2;
muscle : 51;
moisture : 57;
boneMass : 2.8;
subcutaneousFat : 19.9;
BMR : 1549;
proteinRate : 16.6;
visceralFat : 7;
physicalAge : 26;
newAdc : 580;
weightOriPoint : 1;
weightKgPoint : 1;
weightLbPoint : 1;
weightStPoint : 1;
KGgraduation : 1;
LBgradution : 1;
Algorithm_number : 1;
bm15ScaleUnit : 0;
measureStatus : 2;
*/

+ 49
- 0
InetBleSDK/Products/InetBleSDK.framework/Headers/WriteToBLEManager.h View File

@@ -0,0 +1,49 @@
//
// InetBleSDK
//
// Created by iot_wz on 2018/9/1.
// Copyright © 2018年 iot_wz. All rights reserved.
//

#import <Foundation/Foundation.h>
@class BLEUser;


@interface WriteToBLEManager : NSObject


+ (instancetype)shareManager;


/**
send user info to connectable scale

@param sex 1:Male 2:Female
@param height @"177"
@param age @"18"
*/
- (void)synchronousUserWithSex:(NSInteger)sex withHeight:(NSString *)height withAge:(NSString *)age NS_DEPRECATED_IOS(2_0,8_0);
- (void)syncWeighingUser:(BLEUser *)user;

/**
set Unit for connectable scale

@param unitNumber kg:0 lb:1 st:2 斤:3
*/
- (void)write_To_Unit:(NSInteger)unitNumber;



/**
send offline user list to Ble
*/
- (void)sendOfflineUserListToBle:(NSArray <BLEUser *> *)usrsArr;


/**
request historys
*/
- (void)requestOfflineHistory;

@end


BIN
InetBleSDK/Products/InetBleSDK.framework/InetBleSDK View File


BIN
InetBleSDK/Products/InetBleSDK.framework/Info.plist View File


+ 6
- 0
InetBleSDK/Products/InetBleSDK.framework/Modules/module.modulemap View File

@@ -0,0 +1,6 @@
framework module InetBleSDK {
umbrella header "InetBleSDK.h"

export *
module * { export * }
}

+ 485
- 0
README.md View File

@@ -0,0 +1,485 @@
[中文文档](README_CN.md)

# Inet Body Fat Scale SDK Instructions


Note: This SDK upgrade to version 2.0 (AIFit-Demo-New) is a major version upgrade with new features and improved stability. Some class names and method names have changed. Not compatible with previous versions. The old version of AIFit-Demo is no longer maintained, please use the new version as much as possible.


## Contents

* Overview
* Conditions of Use
* SDK integration
* Get SDK version
* Get the Bluetooth status of the IOS system
* Get INBluetoothManager working status
* Get AnalysisBLEDataManager working status
* Device Type
* Scan device list
* Broadcast scale interactive process
* Connection scale interactive process
* Version history
* FAQ
* Technical Support


## Overview

* What is the Inet Body Fat Scale SDK?

> Inet Body Fat Scale SDK is a Bluetooth development tool provided to Inet partners. This SDK implements and encapsulates the Inet Bluetooth protocol and is responsible for the communication between the mobile phone App and the Bluetooth body fat scale device. It is designed to facilitate partners to customize themselves. Bluetooth Body Fat Scale Application.


* Scope

> Partners who need to personalize their own iOS Bluetooth Body Fat Scale App.


## Conditions of Use

* 1. Minimum version of iOS 8.0
* 2. The Bluetooth version used by the device needs 4.0 and above
* 3. Support armv7 / i386 / x86_64 / arm64 instruction set;

## SDK integration

* 1. Import InetBleSDK.framework into Xcode project. <br><br>
* 2. Set the following privacy permission usage description in the project's `Info.plist`, and the actual description content is set by each project.

```
<key> NSBluetoothAlwaysUsageDescription </key>
<string> Use bluetooth to connect body fat scale </string>
```

* 3. Firstly, you need config the SDK with key and secret, please see: [http://sdk.aicare.net.cn/](http://sdk.aicare.net.cn/)

```
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//apply sdk key website http://sdk.aicare.net.cn/
[INBluetoothManager configAppKey:@"885fd30a19f54fb0" secret:@"000fec8b4dadbca6a3d4e00875"];
return YES;
}

```

* 4. Import `#import <InetBleSDK/InetBleSDK.h>` in the xxx.m file that needs to use the SDK, and follow the `<INBluetoothManagerDelegate, AnalysisBLEDataManagerDelegate>` protocol, set the proxy, and implement the proxy method.



## Get SDK version

The SDK version number can be obtained by calling the method [INBluetoothManager sdkVersion], and the SDK version number will be automatically printed on the console after the app starts. Example: v2.0-20191225


## Get the Bluetooth status of the IOS system

You can get the Bluetooth state of the system through [BluetoothManagershareManager].bleState
<br>Refer to the CBCentralManagerState enumeration definition for the obtained state.

```
typedef NS_ENUM (NSInteger, CBCentralManagerState) {
CBCentralManagerStateUnknown = CBManagerStateUnknown,
CBCentralManagerStateResetting = CBManagerStateResetting,
CBCentralManagerStateUnsupported = CBManagerStateUnsupported,
CBCentralManagerStateUnauthorized = CBManagerStateUnauthorized,
CBCentralManagerStatePoweredOff = CBManagerStatePoweredOff,
CBCentralManagerStatePoweredOn = CBManagerStatePoweredOn,
}
```

## Get INBluetoothManager working status

Set the agent of the SDK Bluetooth management class [INBluetoothManager shareManager] .delegate = self; and implement the following proxy method to monitor the working status of the Bluetooth management class INBluetoothManager.

```
-(void) BluetoothManager: (INBluetoothManager *) manager updateCentralManagerState: (BluetoothManagerState) state {
}

// BluetoothManagerState enumeration is as follows:
typedef NS_ENUM (NSInteger, BluetoothManagerState) {
    BluetoothManagerState_PowerOn,
    BluetoothManagerState_PowerOff,
    BluetoothManagerState_UnknowErr,
    BluetoothManagerState_StartScan,
    BluetoothManagerState_StopScan,
    BluetoothManagerState_ConnectSuccess,
    BluetoothManagerState_ConnectFailed,
    BluetoothManagerState_Disconnect
};

```

## Get AnalysisBLEDataManager working status

Set the proxy of the data analysis class [AnalysisBLEDataManager shareManager] .infoDelegate = self; and implement the following proxy method to get the working status of the data analysis class AnalysisBLEDataManager

```
-(void) AnalysisBLEDataManager: (AnalysisBLEDataManager *) analysisManager updateBleDataAnalysisStatus: (BleDataAnalysisStatus) bleDataAnalysisStatus {
}

// BleDataAnalysisStatus enumeration is as follows:

/ **
 Note:
 linkScale has all below status, but broadcastScale just has // b1, b2, b3
 * /
typedef NS_ENUM (NSInteger, BleDataAnalysisStatus) {
    
    BleDataAnalysisStatus_SyncTimeSuccess,
    BleDataAnalysisStatus_SyncTimeFailed, // lead to error measureTime
    BleDataAnalysisStatus_SyncUserSuccess,
    BleDataAnalysisStatus_SyncUserFailed, // lead to no bodydata, just weight
    
    BleDataAnalysisStatus_UnstableWeight, // b1
    BleDataAnalysisStatus_StableWeight, // b2
    BleDataAnalysisStatus_MeasureComplete, // b3
    BleDataAnalysisStatus_AdcError,
    
    BleDataAnalysisStatus_LightOff,
};

```


## Device Type

Devices are mainly divided into the following two categories, and the device type can be obtained according to the acNumber attribute of deviceModel called by -BluetoothManager:didDiscoverDevice: proxy method callback.

1. Broadcast scale: acNumber = 0 or acNumber = 1
> * The broadcast scale uses Bluetooth broadcast to transmit data to the outside world and cannot be connected. The broadcast scale is only responsible for determining the user's weight and impedance, and does not calculate any body fat data.<br><br>
> * After the app parses the weight and impedance via Bluetooth broadcast, it calls the corresponding method in the SDK algorithm class AlgorithmSDK to calculate 10 items of body fat data.<br><br>
> * acNumber = 0 is a broadcast scale without temperature, acNumber = 1 is a broadcast scale with temperature. Currently the SDK only supports BM15 broadcast scales.


2. Link scale: acNumber = 2 or acNumber = 3
> * The connection scale is responsible for measuring the user's weight and impedance, and calculating 10 items of body fat data according to the user information issued by the App, and transmitting it to the App via Bluetooth.<br><br>
> * acNumber = 2 is the connected scale without temperature, acNumber = 3 is the connected scale with temperature. At present, the SDK only supports scales with 1 decimal place, and does not support protocols with 2 decimal places and 0xAE.

## Scan device list

```
// SearchDeviceVC.m

@interface SearchDeviceVC () <INBluetoothManagerDelegate>
@end

@implementation SearchDeviceVC

-(void) viewDidLoad
{
    [super viewDidLoad];

    if ([INBluetoothManager shareManager] .bleState == CBCentralManagerStatePoweredOn) {
        [INBluetoothManager shareManager] .delegate = self;
        [[INBluetoothManager shareManager] startBleScan];
    } else {
        NSLog (@ "--- Error: BLE not avalible, pls check.");
    }
}


#pragma mark-BluetoothManagerDelegate

-(void) BluetoothManager: (INBluetoothManager *) manager didDiscoverDevice: (DeviceModel *) deviceModel
{

    if (self.isAddPeripheraling == YES) return;
    
    self.isAddPeripheraling = YES;
    
    BOOL willAdd = YES;
    for (DeviceModel * model in self.peripheralArray) // avoid add the same device
    {
        if ([model.deviceAddress isEqualToString: deviceModel.deviceAddress]
        && [model.deviceName isEqualToString: deviceModel.deviceName])
        {
            willAdd = NO;
        }
    }
    
    if (willAdd) {
        [self.peripheralArray addObject: deviceModel];
        [self.BleTableView reloadData];
    }
    
    self.isAddPeripheraling = NO;
    
}


```

## Broadcast scale interactive process

1. Scan the device list (refer to the “Scan Device List” operation), filter out the broadcast scale model according to acNumber = 0 or acNumber = 1

2. Set the proxy of the data analysis class AnalysisBLEDataManager, follow the data analysis protocol AnalysisBLEDataManagerDelegate, and listen to the corresponding proxy method
```
-(void) AnalysisBLEDataManager: (AnalysisBLEDataManager *) analysisManager updateMeasureUserInfo: (UserInfoModel *) infoModel;
```
3. Call the SDK method [[INBluetoothManager shareManager] handleDataForBroadScale: device]; and start processing broadcast scale data.

4. After performing step 3, the proxy method in step 2 starts to call back infoModel (broadcast scale only measures weight and impedance), plus the user information obtained by the App, calls the algorithm provided by AlgorithmSDK + (AlgorithmModel *) getBodyfatWithWeight: (double ) kgWeight adc: (int) adc sex: (AlgUserSex) sex age: (int) age height: (int) height; Calculate 10 items of body fat data

```
-(void) AnalysisBLEDataManager: (AnalysisBLEDataManager *) analysisManager updateMeasureUserInfo: (UserInfoModel *) infoModel {
    NSLog (@ "--- infoModel:% @", infoModel);
    
    _currentInfoModel = infoModel;
    [self refreshTableView];
    
    if (_currentInfoModel.measureStatus == MeasureStatus_Complete && _currentInfoModel.weightsum> 0 && _currentInfoModel.newAdc> 0) {// Measure Complete
        
        float weight = _currentInfoModel.weightsum / pow (10, _currentInfoModel.weightOriPoint); // 6895-> 68.95
        float adc = _currentInfoModel.newAdc;
        _appUser.weightKg = weight;
        _appUser.adc = adc;
        _userInfoLabel.text = [NSString stringWithFormat: @ "sex:% d \ n age:% d \ n height:% d \ n weight:%. 1f \ n adc:% d", _ appUser.sex, _appUser.age, _appUser .height, _appUser.weightKg, _appUser.adc];
        
        if (_targetDeviceModel.acNumber.intValue <2) {// BroadScale BM15 mesure complete

            AlgorithmModel * algModel = [AlgorithmSDK getBodyfatWithWeight: weight adc: adc sex: _appUser.sex age: _appUser.age height: _appUser.height];
            NSLog (@ "--- BM15 AlgorithmModel:% @", algModel);
            _currentInfoModel.fatRate = algModel.bfr.floatValue;
            _currentInfoModel.BMI = algModel.bmi.floatValue;
            _currentInfoModel.moisture = algModel.vwc.floatValue;
            _currentInfoModel.muscle = algModel.rom.floatValue;
            _currentInfoModel.BMR = algModel.bmr.floatValue;
            _currentInfoModel.boneMass = algModel.bm.floatValue;
            _currentInfoModel.visceralFat = algModel.uvi.floatValue;
            _currentInfoModel.proteinRate = algModel.pp.floatValue;
            _currentInfoModel.physicalAge = algModel.physicalAge.floatValue;
            _currentInfoModel.subcutaneousFat = algModel.sfr.floatValue;
            
            // refresh
            [self refreshTableView];
            
        } else {// connect scale measure complete
            
        }

    }
    
}
```

* 5. If you need to obtain 6 additional physical indicators such as fat-free weight and weight control, please call another algorithm provided by the SDK, BfsCalculateSDK to calculate.

```
    float weight = _currentInfoModel.weightsum / pow (10, _currentInfoModel.weightOriPoint); // 6895-> 68.95
    int sex = _appUser.sex;
    int height = _appUser.height;
    NSString * bfr = [NSString stringWithFormat: @ "%. 1f", _ currentInfoModel.fatRate];
    NSString * rom = [NSString stringWithFormat: @ "%. 1f%", _ currentInfoModel.muscle];
    NSString * pp = [NSString stringWithFormat: @ "%. 1f%", _ currentInfoModel.proteinRate];
    BfsCalculateItem * item = [BfsCalculateSDK getBodyfatItemWithSex: sex height: height weight: weight bfr: bfr rom: rom pp: pp];
    
```


## Connection scale interactive process

`1`. Scan the device list (refer to “Scan Device List” operation), and select the connected scale model according to acNumber = 2 or acNumber = 3

`2`. Set the proxy of the data analysis class AnalysisBLEDataManager, follow the data analysis protocol AnalysisBLEDataManagerDelegate, and listen to the corresponding proxy method

```
-(void) AnalysisBLEDataManager: (AnalysisBLEDataManager *) analysisManager
updateBleDataAnalysisStatus: (BleDataAnalysisStatus) bleDataAnalysisStatus;

-(void) AnalysisBLEDataManager: (AnalysisBLEDataManager *) analysisManager
updateMeasureUserInfo: (UserInfoModel *) infoModel;

/// If no need offline history function, do not implement this callback
-(void) AnalysisBLEDataManager: (AnalysisBLEDataManager *) analysisManager backOfflineHistorys: (NSMutableArray <UserInfoModel *> *) historysMutableArr;

```

`3`. Invoke SDK method [[INBluetoothManager shareManager] connectToLinkScale: device]; try to connect the connected scale device.

`4`. Monitor the working status of the data analysis class BleDataAnalysisStatus_SyncTimeSuccess callback, which means that the connection to the scale is successfully connected, the initialization is completed, and the app can receive interactive instructions. At this time, you need to switch the scale unit to keep in sync with the App, synchronize the information of the user who is about to be weighed, synchronize the offline user list, and request offline history (if you don't need offline function, you can ignore it).



```
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager
updateBleDataAnalysisStatus:(BleDataAnalysisStatus)bleDataAnalysisStatus {
switch (bleDataAnalysisStatus) {
case BleDataAnalysisStatus_SyncTimeSuccess:
{
_tipLB.text = @"sync time success";
//set unit
[self ChooseUnit:self.unitSegmentedControl];
//then sync user to be weighing
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncWeighingUserToBle];
});

//sync offline userlist(If no need offline history function, do not call this method)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncOfflineUserListToBle];
});
//request history (If no need offline history function, do not call this method)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[WriteToBLEManager shareManager] requestOfflineHistory];
});

break;
}
case BleDataAnalysisStatus_SyncTimeFailed:
{
_tipLB.text = @"sync time failed";
break;
}
case BleDataAnalysisStatus_SyncUserSuccess:
{
_tipLB.text = @"sync weighing user success";
break;
}
case BleDataAnalysisStatus_SyncUserFailed:
{
_tipLB.text = @"sync weighing user failed";
break;
}
case BleDataAnalysisStatus_UnstableWeight:
{
_tipLB.text = @"measuring...\nUnstable Weight";
break;
}
case BleDataAnalysisStatus_StableWeight:
{
_tipLB.text = @"Stable Weight";
break;
}
case BleDataAnalysisStatus_MeasureComplete:
{
_tipLB.text = @"measure complete";
break;
}
case BleDataAnalysisStatus_AdcError:
{
_tipLB.text = @"adc measure failed";
break;
}
case BleDataAnalysisStatus_LightOff:
{
_tipLB.text = @"your linkScale light off";
break;
}
default:
break;
}
}

```

`5`. After executing step 3, the proxy method set in step 2 starts to call back the weight information model infoModel. The App performs secondary processing on the received data and refreshes the UI interface. At the same time, it is necessary to determine the end of the measurement, and send instructions to update the current and offline user list information.

```
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager updateMeasureUserInfo:(UserInfoModel *)infoModel {
NSLog(@"---infoModel:%@",infoModel);
_currentInfoModel = infoModel;
[self refreshTableView];
if (_currentInfoModel.measureStatus == MeasureStatus_Complete && _currentInfoModel.weightsum > 0 && _currentInfoModel.newAdc > 0) { //Measure Complete
float weight = _currentInfoModel.weightsum/pow(10, _currentInfoModel.weightOriPoint);//6895->68.95
float adc = _currentInfoModel.newAdc;
_appUser.weightKg = weight;
_appUser.adc = adc;
_userInfoLabel.text = [NSString stringWithFormat:@" sex:%d\n age:%d\n height:%d\n weight:%.1f\n adc:%d",_appUser.sex,_appUser.age,_appUser.height,_appUser.weightKg,_appUser.adc];
if (_targetDeviceModel.acNumber.intValue < 2) { //BroadScale BM15 mesure complete
} else { //connect scale measure complete
[self syncWeighingUserToBle];
// If no need offline history function, do not call this method
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncOfflineUserListToBle];
});
}

}
}

```

`6`. If you need to obtain 6 additional physical indicators such as fat-free weight and weight control, please call another algorithm provided by the SDK, BfsCalculateSDK to calculate.

```
float weight = _currentInfoModel.weightsum/pow(10, _currentInfoModel.weightOriPoint);//6895->68.95
int sex = _appUser.sex;
int height = _appUser.height;
NSString *bfr = [NSString stringWithFormat:@"%.1f",_currentInfoModel.fatRate];
NSString *rom = [NSString stringWithFormat:@"%.1f%",_currentInfoModel.muscle];
NSString *pp = [NSString stringWithFormat:@"%.1f%",_currentInfoModel.proteinRate];
BfsCalculateItem *item = [BfsCalculateSDK getBodyfatItemWithSex:sex height:height
weight:weight bfr:bfr rom:rom pp:pp];
```


## Version history

Version number | Update time | Author | Update information |
| --- | --- | --- | --- |
| v1.0 | 9/10 2018 | wz | Preliminary version |
v1.1 | 2019/02/27 | wz | Add impedance measurement failure callback and Log switch |
| v1.2 | 2019/04/25 | wz | Added BM15 algorithm interface |
| v1.3 | 2019/08/12 | wz | Optimize Bluetooth connection |
V1.4 | 2019/10/29 | wz | IOS13 compatible system |
V1.5 | 2019/12/20 | wz | Add offline history function |
V2.0 | 2019/12/25 | wz | Feature update: <br> 1. Modify the BluetoothManager class name to INBluetoothManager to avoid conflicts with the system's private APIs. <br> 2. Standardize methods and properties in AlgorithmSDK and AlgorithmModel classes. br> 3. Added BfsCalculateSDK algorithm, which can obtain additional data for calculating body fat data <br> 4. Automatically read the DID of the scale <br> 5. Fix bugs found during testing |
| V2.1 | 2020/04/20 | wz | Added support for connection scales with 2 decimal |


## FAQ

> Q: How to tell whether the currently scanned DeviceModel is a broadcast scale or a connected scale?

> A: According to the acNumber property value of DeviceModel: acNumber = 0 is a broadcast scale without temperature, acNumber = 1 is a broadcast scale with temperature. acNumber = 2 is the connected scale without temperature, acNumber = 3 is the connected scale with temperature.

> Q: How to judge the end of the measurement?

> A: According to the UserInfoModel * infoModel property.measureStatus of the data analysis class proxy method callback.
>
```
typedef NS_ENUM (NSInteger, MeasureStatus) {
    MeasureStatus_Unstable = 0,
    MeasureStatus_Stable,
    MeasureStatus_Complete,
    MeasureStatus_OfflineHistory,
};
```

> Q: Which units does the Bluetooth protocol support?
>
> A: The unit only supports up to 4 types (kg, lb, st, catty). For details about what units are supported, please refer to the factory settings of the scale.



## Technical Support

Wuz

Inet App Manager

inet_support@163.com

+ 507
- 0
README_CN.md View File

@@ -0,0 +1,507 @@
[README_EN](README.md)
# Inet体脂秤SDK使用说明


注意:本次SDK升级为2.0(AIFit-Demo-New),是大版本升级,新增功能,提升稳定性,部分类名和方法名发生了变化,将不再兼容之前的版本。旧版本AIFit-Demo不再维护,请尽量使用新版本。


## 目录

* 概述
* 使用条件
* SDK集成
* 获取SDK版本号
* 获取IOS系统蓝牙状态
* 获取INBluetoothManager工作状态
* 获取AnalysisBLEDataManager工作状态
* 设备类型
* 扫描设备列表
* 广播秤交互流程
* 连接秤交互流程
* 版本历史
* FAQ
* 技术支持


## 概述

* 什么是Inet体脂秤SDK ?

> Inet体脂秤SDK 是提供给Inet合作伙伴的蓝牙开发工具,该SDK对Inet蓝牙协议进行了实现和封装,负责手机App与蓝牙体脂秤设备之间的通信,旨在方便合作伙伴定制自己的蓝牙体脂秤应用。


* 适用范围

> 需要个性化定制自己的 iOS 蓝牙体脂秤 APP 的合作伙伴。


## 使用条件

1. 最低版本iOS 8.0
2. 设备所使用的蓝牙版本需要4.0及以上
3. 支持armv7/i386/x86_64/arm64指令集;

## SDK集成

1. 将InetBleSDK.framework导入Xcode工程。
2. 在项目的`Info.plist`中设置以下隐私权限使用描述,实际描述内容各项目自行设置

```
<key>NSBluetoothAlwaysUsageDescription</key>
<string>Use bluetooth to connect body fat scale</string>
```
3. 首先给SDK配置key和secret,申请地址为:[http://sdk.aicare.net.cn/](http://sdk.aicare.net.cn/)

```
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
//apply sdk key website http://sdk.aicare.net.cn/
[INBluetoothManager configAppKey:@"885fd30a19f54fb0" secret:@"000fec8b4dadbca6a3d4e00875"];
return YES;
}
```
4. 在需要使用SDK的类.m文件中导入#import \<InetBleSDK/InetBleSDK.h>,并遵守\<INBluetoothManagerDelegate,AnalysisBLEDataManagerDelegate>协议,设置代理,实现代理方法。


## 获取SDK版本号
通过调用方法[INBluetoothManager sdkVersion]可获取SDK版本号,同时App启动后会自动在控制台打印SDK版本号。例如:v2.0-20191225


## 获取IOS系统蓝牙状态
通过[BluetoothManagershareManager].bleState可以获取系统蓝牙状态,获取的状态参考CBCentralManagerState枚举定义。

```
typedef NS_ENUM(NSInteger, CBCentralManagerState) {
CBCentralManagerStateUnknown = CBManagerStateUnknown,
CBCentralManagerStateResetting = CBManagerStateResetting,
CBCentralManagerStateUnsupported = CBManagerStateUnsupported,
CBCentralManagerStateUnauthorized = CBManagerStateUnauthorized,
CBCentralManagerStatePoweredOff = CBManagerStatePoweredOff,
CBCentralManagerStatePoweredOn = CBManagerStatePoweredOn,
}
```

## 获取INBluetoothManager工作状态

设置SDK蓝牙管理类的代理[INBluetoothManager shareManager].delegate = self; 并实现如下代理方法,,即可监听蓝牙管理类INBluetoothManager的工作状态。

```
- (void)BluetoothManager:(INBluetoothManager *)manager updateCentralManagerState:(BluetoothManagerState)state {
}

//BluetoothManagerState枚举如下:
typedef NS_ENUM(NSInteger,BluetoothManagerState) {
BluetoothManagerState_PowerOn,
BluetoothManagerState_PowerOff,
BluetoothManagerState_UnknowErr,
BluetoothManagerState_StartScan,
BluetoothManagerState_StopScan,
BluetoothManagerState_ConnectSuccess,
BluetoothManagerState_ConnectFailed,
BluetoothManagerState_Disconnect
};

```

## 获取AnalysisBLEDataManager工作状态
设置数据解析类的代理[AnalysisBLEDataManager shareManager].infoDelegate = self; 并实现如下代理方法,即可获取数据解析类AnalysisBLEDataManager的工作状态

```
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager updateBleDataAnalysisStatus:(BleDataAnalysisStatus)bleDataAnalysisStatus {
}

//BleDataAnalysisStatus枚举如下:

/**
Note:
linkScale has all below status, but broadcastScale just has //b1,b2,b3
*/
typedef NS_ENUM(NSInteger, BleDataAnalysisStatus) {
BleDataAnalysisStatus_SyncTimeSuccess,
BleDataAnalysisStatus_SyncTimeFailed, //lead to error measureTime
BleDataAnalysisStatus_SyncUserSuccess,
BleDataAnalysisStatus_SyncUserFailed, //lead to no bodydata, just weight
BleDataAnalysisStatus_UnstableWeight, //b1
BleDataAnalysisStatus_StableWeight, //b2
BleDataAnalysisStatus_MeasureComplete, //b3
BleDataAnalysisStatus_AdcError,
BleDataAnalysisStatus_LightOff,
};

```


## 设备类型

设备主要分为以下两大类,可根据-BluetoothManager:didDiscoverDevice:代理方法回调的deviceModel的属性acNumber来获取设备类型。

1. 广播秤(broadcast scale):acNumber=0 或 acNumber=1
> * 广播秤使用蓝牙广播对外界传输数据,不可以被连接。广播秤仅负责测定用户的体重和阻抗,不会计算任何体脂数据。
> * App通过蓝牙广播解析到体重和阻抗后,调用SDK算法类AlgorithmSDK中的对应方法,计算出10项体脂数据。。
> * acNumber=0是不带温度的广播秤,acNumber=1是有温度的广播秤。目前SDK仅支持BM15广播秤。


2. 连接秤(link scale):acNumber=2 或 acNumber=3
> * 连接秤负责测定用户的体重和阻抗,并根据App下发的用户信息计算出10项体脂数据,通过蓝牙传输给App。
> * acNumber=2是不带温度的连接秤,acNumber=3是有温度的连接秤。 目前SDK仅支持1位小数的连接秤,不支持2位小数及0xAE开头的协议。

## 扫描设备列表

```
// SearchDeviceVC.m

@interface SearchDeviceVC () <INBluetoothManagerDelegate>
@end

@implementation SearchDeviceVC

- (void)viewDidLoad
{
[super viewDidLoad];

if ([INBluetoothManager shareManager].bleState == CBCentralManagerStatePoweredOn) {
[INBluetoothManager shareManager].delegate = self;
[[INBluetoothManager shareManager] startBleScan];
} else {
NSLog(@"---Error: BLE not avalible, pls check.");
}
}


#pragma mark - BluetoothManagerDelegate

- (void)BluetoothManager:(INBluetoothManager *)manager didDiscoverDevice:(DeviceModel *)deviceModel
{

if (self.isAddPeripheraling == YES) return;
self.isAddPeripheraling = YES;
BOOL willAdd = YES;
for (DeviceModel *model in self.peripheralArray) //avoid add the same device
{
if ([model.deviceAddress isEqualToString:deviceModel.deviceAddress] && [model.deviceName isEqualToString:deviceModel.deviceName])
{
willAdd = NO;
}
}
if (willAdd) {
[self.peripheralArray addObject:deviceModel];
[self.BleTableView reloadData];
}
self.isAddPeripheraling = NO;
}


```


## 广播秤交互流程
* 1.扫描设备列表(参考“扫描设备列表”操作),根据acNumber=0或acNumber=1筛选出广播秤模型

* 2.设置数据解析类AnalysisBLEDataManager的代理,遵守数据解析协议AnalysisBLEDataManagerDelegate,监听相应的代理方法

```
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager
updateMeasureUserInfo:(UserInfoModel *)infoModel;
```

* 3.调用SDK方法[[INBluetoothManager shareManager] handleDataForBroadScale:device];开始处理广播秤数据。

* 4.执行完步骤3操作后,步骤2中代理方法开始回调infoModel(广播秤仅测定体重和阻抗),加上App获取的用户信息,调用AlgorithmSDK提供的算法 + (AlgorithmModel *)getBodyfatWithWeight:(double)kgWeight adc:(int)adc sex:(AlgUserSex)sex age:(int)age height:(int)height; 计算出10项体脂数据

```
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager updateMeasureUserInfo:(UserInfoModel *)infoModel {
NSLog(@"---infoModel:%@",infoModel);
_currentInfoModel = infoModel;
[self refreshTableView];
if (_currentInfoModel.measureStatus == MeasureStatus_Complete && _currentInfoModel.weightsum > 0 && _currentInfoModel.newAdc > 0) { //Measure Complete
float weight = _currentInfoModel.weightsum/pow(10, _currentInfoModel.weightOriPoint);//6895->68.95
float adc = _currentInfoModel.newAdc;
_appUser.weightKg = weight;
_appUser.adc = adc;
_userInfoLabel.text = [NSString stringWithFormat:@" sex:%d\n age:%d\n height:%d\n weight:%.1f\n adc:%d",_appUser.sex,_appUser.age,_appUser.height,_appUser.weightKg,_appUser.adc];
if (_targetDeviceModel.acNumber.intValue < 2) { //BroadScale BM15 mesure complete

AlgorithmModel *algModel = [AlgorithmSDK getBodyfatWithWeight:weight adc:adc sex:_appUser.sex age:_appUser.age height:_appUser.height];
NSLog(@"---BM15 AlgorithmModel: %@",algModel);
_currentInfoModel.fatRate = algModel.bfr.floatValue;
_currentInfoModel.BMI = algModel.bmi.floatValue;
_currentInfoModel.moisture = algModel.vwc.floatValue;
_currentInfoModel.muscle = algModel.rom.floatValue;
_currentInfoModel.BMR = algModel.bmr.floatValue;
_currentInfoModel.boneMass = algModel.bm.floatValue;
_currentInfoModel.visceralFat = algModel.uvi.floatValue;
_currentInfoModel.proteinRate = algModel.pp.floatValue;
_currentInfoModel.physicalAge = algModel.physicalAge.floatValue;
_currentInfoModel.subcutaneousFat = algModel.sfr.floatValue;
//refresh
[self refreshTableView];
} else { //connect scale measure complete
}

}
}
```

* 5.如需要获取 去脂体重、体重控制量等额外的6项身体指标,请调用SDK提供的另外一个算法BfsCalculateSDK中方法计算。

```
float weight = _currentInfoModel.weightsum/pow(10, _currentInfoModel.weightOriPoint);//6895->68.95
int sex = _appUser.sex;
int height = _appUser.height;
NSString *bfr = [NSString stringWithFormat:@"%.1f",_currentInfoModel.fatRate];
NSString *rom = [NSString stringWithFormat:@"%.1f%",_currentInfoModel.muscle];
NSString *pp = [NSString stringWithFormat:@"%.1f%",_currentInfoModel.proteinRate];
BfsCalculateItem *item = [BfsCalculateSDK getBodyfatItemWithSex:sex height:height weight:weight bfr:bfr rom:rom pp:pp];
```


## 连接秤交互流程

* 1.扫描设备列表(参考“扫描设备列表”操作),根据acNumber=2或acNumber=3筛选出连接秤模型

* 2.设置数据解析类AnalysisBLEDataManager的代理,遵守数据解析协议AnalysisBLEDataManagerDelegate,监听相应的代理方法

```
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager
updateBleDataAnalysisStatus:(BleDataAnalysisStatus)bleDataAnalysisStatus;

- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager
updateMeasureUserInfo:(UserInfoModel *)infoModel;

///If no need offline history function, do not implement this callback
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager backOfflineHistorys:(NSMutableArray <UserInfoModel *> *)historysMutableArr;

```

* 3.调用SDK方法[[INBluetoothManager shareManager] connectToLinkScale:device];尝试连接该连接秤设备。

* 4.监听数据解析类的工作状态BleDataAnalysisStatus_SyncTimeSuccess回调,即代表连接秤连接成功,完成初始化设置,可接收App交互指令。此时需要切换秤的单位与App保持同步,同步当前即将称重那个用户的信息,同步离线用户列表和请求离线历史记录(如无需离线功能,可忽略)。

```
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager
updateBleDataAnalysisStatus:(BleDataAnalysisStatus)bleDataAnalysisStatus {
switch (bleDataAnalysisStatus) {
case BleDataAnalysisStatus_SyncTimeSuccess:
{
_tipLB.text = @"sync time success";
//set unit
[self ChooseUnit:self.unitSegmentedControl];
//then sync user to be weighing
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncWeighingUserToBle];
});

//sync offline userlist(If no need offline history function, do not call this method)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncOfflineUserListToBle];
});
//request history (If no need offline history function, do not call this method)
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
(int64_t)(0.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[[WriteToBLEManager shareManager] requestOfflineHistory];
});

break;
}
case BleDataAnalysisStatus_SyncTimeFailed:
{
_tipLB.text = @"sync time failed";
break;
}
case BleDataAnalysisStatus_SyncUserSuccess:
{
_tipLB.text = @"sync weighing user success";
break;
}
case BleDataAnalysisStatus_SyncUserFailed:
{
_tipLB.text = @"sync weighing user failed";
break;
}
case BleDataAnalysisStatus_UnstableWeight:
{
_tipLB.text = @"measuring...\nUnstable Weight";
break;
}
case BleDataAnalysisStatus_StableWeight:
{
_tipLB.text = @"Stable Weight";
break;
}
case BleDataAnalysisStatus_MeasureComplete:
{
_tipLB.text = @"measure complete";
break;
}
case BleDataAnalysisStatus_AdcError:
{
_tipLB.text = @"adc measure failed";
break;
}
case BleDataAnalysisStatus_LightOff:
{
_tipLB.text = @"your linkScale light off";
break;
}
default:
break;
}
}

```

* 5.执行完步骤3操作后,步骤2中设置的代理方法开始回调体重信息模型infoModel,App对接收的数据进行二次加工,并刷新UI界面。同时需判定测量结束,发送指令更新当前用户及离线用户列表信息。

```
- (void)AnalysisBLEDataManager:(AnalysisBLEDataManager *)analysisManager updateMeasureUserInfo:(UserInfoModel *)infoModel {
NSLog(@"---infoModel:%@",infoModel);
_currentInfoModel = infoModel;
[self refreshTableView];
if (_currentInfoModel.measureStatus == MeasureStatus_Complete && _currentInfoModel.weightsum > 0 && _currentInfoModel.newAdc > 0) { //Measure Complete
float weight = _currentInfoModel.weightsum/pow(10, _currentInfoModel.weightOriPoint);//6895->68.95
float adc = _currentInfoModel.newAdc;
_appUser.weightKg = weight;
_appUser.adc = adc;
_userInfoLabel.text = [NSString stringWithFormat:@" sex:%d\n age:%d\n height:%d\n weight:%.1f\n adc:%d",_appUser.sex,_appUser.age,_appUser.height,_appUser.weightKg,_appUser.adc];
if (_targetDeviceModel.acNumber.intValue < 2) { //BroadScale BM15 mesure complete
} else { //connect scale measure complete
[self syncWeighingUserToBle];
// If no need offline history function, do not call this method
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
[self syncOfflineUserListToBle];
});
}

}
}

```

* 6.如需要获取 去脂体重、体重控制量等额外的6项身体指标,请调用SDK提供的另外一个算法BfsCalculateSDK中方法计算。

```
float weight = _currentInfoModel.weightsum/pow(10, _currentInfoModel.weightOriPoint);//6895->68.95
int sex = _appUser.sex;
int height = _appUser.height;
NSString *bfr = [NSString stringWithFormat:@"%.1f",_currentInfoModel.fatRate];
NSString *rom = [NSString stringWithFormat:@"%.1f%",_currentInfoModel.muscle];
NSString *pp = [NSString stringWithFormat:@"%.1f%",_currentInfoModel.proteinRate];
BfsCalculateItem *item = [BfsCalculateSDK getBodyfatItemWithSex:sex height:height
weight:weight bfr:bfr rom:rom pp:pp];
```


## 版本历史

| 版本号 | 更新时间 | 作者 | 更新信息 |
| --- | --- | --- | --- |
| v1.0 | 2018/9/10 | wz | 初步版本 |
| v1.1 | 2019/02/27 | wz | 新增阻抗测量失败回调及Log开关 |
| v1.2 | 2019/04/25 | wz | 新增BM15算法接口 |
| v1.3 | 2019/08/12 | wz | 优化蓝牙连接 |
| V1.4 | 2019/10/29 | wz | 兼容IOS13系统 |
| V1.5 | 2019/12/20 | wz | 添加离线历史记录功能 |
| V2.0 | 2019/12/25 | wz | 功能更新:<br>1.修改BluetoothManager类名为INBluetoothManager,避免与系统私有API冲突 <br>2.规范AlgorithmSDK和AlgorithmModel类中方法及属性命名 <br>3.新增BfsCalculateSDK算法,可获取额外的计算体脂数据数据 <br>4.自动读取秤的DID <br>5.修复测试发现的bug |
| V2.1 | 2020/04/20 | wz | 增加对2位小数的连接秤的支持 |


## FAQ

+ 1: 如何判断区分当前扫描到的DeviceModel是广播秤还是连接秤?
答:根据DeviceModel的acNumber属性值区分:acNumber=0是不带温度的广播秤,acNumber=1是有温度的广播秤。acNumber=2是不带温度的连接秤,acNumber=3是有温度的连接秤。

+ 2: 如何判定测量结束?
答:根据数据解析类代理方法回调的 UserInfoModel *infoModel属性.measureStatus来判定
```
typedef NS_ENUM(NSInteger, MeasureStatus) {
MeasureStatus_Unstable = 0,
MeasureStatus_Stable,
MeasureStatus_Complete,
MeasureStatus_OfflineHistory,
};
```

+ 3: 蓝牙协议支持哪些单位?

答:单位最多只支持4种(kg,lb,st,斤),具体支持什么单位请参照秤的出厂设置。
+ 4: 扫描不到蓝牙设备?
答:A.拔掉电池重启秤 B.检查秤是否已被其他手机连接,要求其断开(秤未被连接时,秤盘上蓝牙图标会不断闪烁)
+ 5: 支持哪些设备?
答:支持BM系列的连接秤、BM15广播秤
+ 6: 为什么只能测到体重,没有其他体脂数据?
答:必须脱掉鞋和袜子,光脚站在体脂秤的电极片上,才能测出体脂数据。
+ 7: 称量时秤总是显示Error,app显示阻抗测量失败,是什么原因?
答:脱掉鞋和袜子,光脚站在体脂秤的电极片上测量,就不会再显示Error。
+ 8: 如何高效的向技术支持人员提供反馈?
答:1.SDK会在控制台打印log,反馈问题时请先将log保存为txt,发给技术人员
2. 反馈问题时,尽可能将问题出现时的前后操作描述清楚,最好能录制视频告知问题如何复现。
+ 9: 是否有各项体脂数据的判定标准和文案呢?
答:体脂判定标准各厂商标准都可能不一样,目前并没有行业公认的参考标准。如下是我司使用的标准,仅供参考:
《蓝牙体脂秤判定标准及小程序文案20200416》[https://shimo.im/sheets/8dGqCgyhX9P6Xpcw/GX3qk/](https://shimo.im/sheets/8dGqCgyhX9P6Xpcw/GX3qk/)



## 联系我们

深圳市易连物联网有限公司

电话:0755-81773367

官网:www.elinkthings.com

邮箱:app@elinkthings.com

Loading…
Cancel
Save