diff --git a/HDFwear.xcodeproj/project.pbxproj b/HDFwear.xcodeproj/project.pbxproj index 1540b41..3131d03 100644 --- a/HDFwear.xcodeproj/project.pbxproj +++ b/HDFwear.xcodeproj/project.pbxproj @@ -284,6 +284,7 @@ 8473FB622B4BF1A200409148 /* TaskManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8473FB612B4BF1A200409148 /* TaskManager.swift */; }; 847482762B03793C0004F0C2 /* NewWeatherModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847482752B03793C0004F0C2 /* NewWeatherModel.swift */; }; 847672B82B074E43007DC2DE /* NewBeiDouContactModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847672B72B074E43007DC2DE /* NewBeiDouContactModel.swift */; }; + 847AF36E2B4CF35F00E3456E /* NewSleepModel.swift in Sources */ = {isa = PBXBuildFile; fileRef = 847AF36D2B4CF35F00E3456E /* NewSleepModel.swift */; }; B212F1FD2A14CE0400781D59 /* LaunchSetting.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = B212F1FF2A14CE0400781D59 /* LaunchSetting.storyboard */; }; B212F2052A14D28E00781D59 /* LaunchMyBodySettingVC.swift in Sources */ = {isa = PBXBuildFile; fileRef = B212F2042A14D28E00781D59 /* LaunchMyBodySettingVC.swift */; }; B23AA1032A1879E200BB3902 /* SortPageSectionHeader.xib in Resources */ = {isa = PBXBuildFile; fileRef = B23AA1022A1879E200BB3902 /* SortPageSectionHeader.xib */; }; @@ -660,6 +661,7 @@ 8473FB612B4BF1A200409148 /* TaskManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TaskManager.swift; sourceTree = ""; }; 847482752B03793C0004F0C2 /* NewWeatherModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewWeatherModel.swift; sourceTree = ""; }; 847672B72B074E43007DC2DE /* NewBeiDouContactModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewBeiDouContactModel.swift; sourceTree = ""; }; + 847AF36D2B4CF35F00E3456E /* NewSleepModel.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NewSleepModel.swift; sourceTree = ""; }; 847D1C4A2B009FAC0097A96E /* 20231111ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = 20231111ReadMe.md; sourceTree = ""; }; 847D2DE42B3D575F001BA7EF /* 20240110ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = 20240110ReadMe.md; sourceTree = ""; }; B0BDC40FAF3CBA7B780ED655 /* Pods_HDFwear.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = Pods_HDFwear.framework; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -1276,6 +1278,7 @@ 6C6051BD2760C0CB00286B37 /* WeatherModel.swift */, 847482752B03793C0004F0C2 /* NewWeatherModel.swift */, 847672B72B074E43007DC2DE /* NewBeiDouContactModel.swift */, + 847AF36D2B4CF35F00E3456E /* NewSleepModel.swift */, ); path = Model; sourceTree = ""; @@ -1610,6 +1613,7 @@ B279A37A2A4AC2F800A7C7B6 /* BluetoothManager+Function.swift in Sources */, 6C411EE1275DF6F3009B2E02 /* Data+Extension.swift in Sources */, 6C80835927F698B700C13EB2 /* BackgroundProtectionVC.swift in Sources */, + 847AF36E2B4CF35F00E3456E /* NewSleepModel.swift in Sources */, 6C6F405C27434AC500F9473C /* ZCNavigationController.swift in Sources */, 6C41D0BE275F5DAD00747BE4 /* LoaderButtonAnimationDelegate.swift in Sources */, 6C41D0BC275F5DAD00747BE4 /* LoaderBallPulseRotateAnimation.swift in Sources */, diff --git a/HDFwear/20240110ReadMe.md b/HDFwear/20240110ReadMe.md index 320843c..7a6119f 100644 --- a/HDFwear/20240110ReadMe.md +++ b/HDFwear/20240110ReadMe.md @@ -94,3 +94,9 @@ BluetoothManager+Function 压力数据 func parsePressureData (_ content: [UInt8]) 接收: [237, 126, 0, 1, 128, 32, 0, 1, 0, 0, 172, 113] + +睡眠数据 + func parseSleepData (_ content: [UInt8]) + 发送: [237, 126, 0, 1, 0, 40, 0, 1, 0, 2, 6, 1, 140, 110] + 接收: [237, 126, 0, 1, 128, 25, 0, 0, 0, 77, 3, 7, 9, 101, 120, 119, 200, 0, 0, 14, 16, 10, 101, 120, 133, 216, 0, 0, 14, 16, 8, 101, 120, 147, 232, 0, 0, 14, 16, 7, 101, 120, 161, 248, 0, 0, 14, 16, 9, 101, 120, 176, 8, 0, 0, 14, 16, 10, 101, 120, 190, 24, 0, 0, 14, 16, 9, 101, 120, 204, 40, 0, 0, 14, 16, 101, 121, 46, 152, 101, 121, 60, 168, 0, 0, 14, 16, 224, 73] + 接收: [237, 126, 0, 1, 128, 25, 0, 1, 0, 1, 255, 79, 201] diff --git a/HDFwear/Home/HomeViewController.swift b/HDFwear/Home/HomeViewController.swift index 356bebb..ea0186d 100644 --- a/HDFwear/Home/HomeViewController.swift +++ b/HDFwear/Home/HomeViewController.swift @@ -770,9 +770,9 @@ extension HomeViewController: XMLParserDelegate { if queryArray.contains("Sleep"), let index = queryArray.firstIndex(of: "Sleep") { BluetoothManager.shared.getSleepHistoryData() {[weak self] sleepArray, error in self?.queryArray.remove(at: index) - if error == nil { - SleepModel.addArray(sleepArray) - } +// if error == nil { +// SleepModel.addArray(sleepArray) +// } self?.syncPressure(day) } } else { diff --git a/HDFwear/Home/Model/NewSleepModel.swift b/HDFwear/Home/Model/NewSleepModel.swift new file mode 100644 index 0000000..6ad2509 --- /dev/null +++ b/HDFwear/Home/Model/NewSleepModel.swift @@ -0,0 +1,107 @@ +import UIKit +import HandyJSON +import SwiftDate + +enum NewSleepType: UInt8 { + case nightSleep = 1 + case shortNap = 2 + case nightSleepAndNap = 3 +} + +enum NewSleepStatus: UInt8 { + case awake = 7 + case rapidEyeMovement = 8 + case lightSleep = 9 + case deepSleep = 10 +} + +class NewSleepModel: NSObject { + required override init() { } + + struct SleepFragment { + var sleepStatus: NewSleepStatus + var startTime: Date? + var duration: UInt32 + } + + struct NapFragment { + var startTime: Date? + var endTime: Date? + var duration: UInt32 + } + + var sleepType: NewSleepType = .nightSleep + var sleepFragmentCount: Int = 0 + var sleepFragments: [SleepFragment] = [] + var napFragments: [NapFragment] = [] + + init(sleepType: NewSleepType, sleepFragmentCount: Int, sleepFragments: [SleepFragment], napFragments: [NapFragment]) { + self.sleepType = sleepType + self.sleepFragmentCount = sleepFragmentCount + self.sleepFragments = sleepFragments + self.napFragments = napFragments + } + + class func toSleepModel(_ data: [UInt8]) -> NewSleepModel { + let sleepModel = NewSleepModel() + guard data.count >= 1 else { + return sleepModel // 数据长度不够 + } + sleepModel.sleepType = NewSleepType(rawValue:data[0]) ?? .nightSleep + switch sleepModel.sleepType { + case .nightSleep: + sleepModel.sleepFragmentCount = Int(data[1]) + guard data.count >= 2 + 9 * sleepModel.sleepFragmentCount else { + return sleepModel + } + sleepModel.sleepFragments = sleepModel.parseNightSleepData(data: Array(data[2..<2 + 9 * sleepModel.sleepFragmentCount])) + case .shortNap: + sleepModel.napFragments = sleepModel.parseNapData(data: Array(data[2..= 2 + 9 * sleepModel.sleepFragmentCount else { + return sleepModel + } + sleepModel.sleepFragments = sleepModel.parseNightSleepData(data: Array(data[2..<2 + 9 * sleepModel.sleepFragmentCount])) + sleepModel.napFragments = sleepModel.parseNapData(data: Array(data[2 + 9 * sleepModel.sleepFragmentCount.. [SleepFragment] { + // 解析 SleepFragment 数组 + var sleepFragments = [SleepFragment]() + // 将数组分成9个一组 + for index in stride(from: 0, to: data.count, by: 9) { + let sleepStatus = NewSleepStatus(rawValue: data[index]) ?? .awake + let rawStartTime = UInt32(data[index + 1]) | + (UInt32(data[index + 2]) << 8) | + (UInt32(data[index + 3]) << 16) | + (UInt32(data[index + 4]) << 24) + let startTimeInterval = TimeInterval(rawStartTime) + let startTime = Date(timeIntervalSince1970: startTimeInterval) + let duration = UInt32(data[index + 5]) | (UInt32(data[index + 6]) << 8) | (UInt32(data[index + 7]) << 16) | (UInt32(data[index + 8]) << 24) + + let fragment = SleepFragment(sleepStatus: sleepStatus, startTime: startTime, duration: duration) + sleepFragments.append(fragment) + } + return sleepFragments + } + + func parseNapData(data: [UInt8]) -> [NapFragment] { + // 解析 NapFragment 数组 + var napFragments = [NapFragment]() + // 将数组分成12个一组 + for index in stride(from: 0, to: data.count, by: 12) { + let startTime = Date(timeIntervalSince1970: TimeInterval(UInt32(data[index]) | UInt32(data[index + 1]) << 8 | UInt32(data[index + 2]) << 16 | UInt32(data[index + 3]) << 24)) + let endTime = Date(timeIntervalSince1970: TimeInterval(UInt32(data[index + 4]) | UInt32(data[index + 5]) << 8 | UInt32(data[index + 6]) << 16 | UInt32(data[index + 7]) << 24)) + let duration = UInt32(data[index + 8]) | UInt32(data[index + 9]) << 8 | UInt32(data[index + 10]) << 16 | UInt32(data[index + 11]) << 24 + + let napFragment = NapFragment(startTime: startTime, endTime: endTime, duration: duration) + napFragments.append(napFragment) + } + return napFragments + } +} diff --git a/HDFwear/Mine/MineViewController.swift b/HDFwear/Mine/MineViewController.swift index 22e65c4..dca05f6 100644 --- a/HDFwear/Mine/MineViewController.swift +++ b/HDFwear/Mine/MineViewController.swift @@ -434,12 +434,11 @@ extension MineViewController: UITableViewDataSource, UITableViewDelegate { let alert = UIAlertController(title: "plz select fetch type", message: nil, preferredStyle: .actionSheet) let archiveAction9 = UIAlertAction(title: "getSleepHistoryData", style: .default) { action in - BluetoothManager.shared.getSleepHistoryData() { sleepArray, error in + BluetoothManager.shared.getSleepHistoryData(option: .now) { sleepModel, error in if error != nil { print("getSleepHistoryData" + (error?.description ?? "")) }else { print("getSleepHistoryData success") - SleepModel.addArray(sleepArray) } } } diff --git a/HDFwear/Tools/BleMessage+Function.swift b/HDFwear/Tools/BleMessage+Function.swift index 75085c6..3922a92 100644 --- a/HDFwear/Tools/BleMessage+Function.swift +++ b/HDFwear/Tools/BleMessage+Function.swift @@ -124,8 +124,8 @@ extension BleMessage { return createDataPacket(key: .setNoDisturb, bytes: bytes) } - func getSyncCmd(_ type: SyncType) -> Data { - let bytes: [UInt8] = [type.rawValue] + func getSyncCmd(_ type: SyncType, _ option:SyncOption = .now) -> Data { + let bytes: [UInt8] = [type.rawValue, option.rawValue] return createDataPacket(key: .setSynWatch, bytes: bytes) } diff --git a/HDFwear/Tools/Bluetooth+Types.swift b/HDFwear/Tools/Bluetooth+Types.swift index baf9147..61d147b 100644 --- a/HDFwear/Tools/Bluetooth+Types.swift +++ b/HDFwear/Tools/Bluetooth+Types.swift @@ -180,6 +180,11 @@ enum SyncType: UInt8 { case other = 0xff } +enum SyncOption: UInt8 { + case now = 0x01 + case history = 0x02 +} + enum SyncDay: Int { case today = 0 case yesterday = -1 diff --git a/HDFwear/Tools/BluetoothManager+Function.swift b/HDFwear/Tools/BluetoothManager+Function.swift index 7ad3640..cdd209b 100644 --- a/HDFwear/Tools/BluetoothManager+Function.swift +++ b/HDFwear/Tools/BluetoothManager+Function.swift @@ -212,57 +212,57 @@ extension BluetoothManager { //MARK: - 同步健康数据 //拉取数据 - func newGetData(type:SyncType, completion: ((_ error: Int?) -> ())? = nil) { - let data = BleMessage.shared.getSyncCmd(type) + func newGetData(type:SyncType, option: SyncOption = .now, completion: ((_ error: Int?) -> ())? = nil) { + let data = BleMessage.shared.getSyncCmd(type, option) self.setCmdClosure = completion sendData(data) } // 拉取电量数据 - func newGetBatteryData( completion: ((_ error: Int?) -> ())? = nil) { - newGetData(type: .battery, completion: completion) + func newGetBatteryData(option: SyncOption = .now, completion: ((_ error: Int?) -> ())? = nil) { + newGetData(type: .battery, option: option, completion: completion) } // 拉取GPS轨迹数据 //jtd! 需要使用特定的回调,这样才能够直接把数据回调出来 - func newGetGpsData( completion: ((_ error: Int?) -> ())? = nil) { - newGetData(type: .gps, completion: completion) + func newGetGpsData(option: SyncOption = .now, completion: ((_ error: Int?) -> ())? = nil) { + newGetData(type: .gps, option: option, completion: completion) } - //MARK: - history + //MARK: - old code // 拉取睡眠数据 - func getSleepHistoryData( closure: SleepClosure? = nil) { - let data = BleMessage.shared.getSyncCmd(.sleep) + func getSleepHistoryData(option: SyncOption = .now, closure: SleepClosure? = nil) { + let data = BleMessage.shared.getSyncCmd(.sleep, option) newStartSyncHealthData(closure: closure, data: data, synType: .sleep) } // 拉取血氧数据 - func getBloodOxygenHistoryData( closure: BloodOxygenClosure? = nil) { - let data = BleMessage.shared.getSyncCmd(.bloodOxygen) + func getBloodOxygenHistoryData(option: SyncOption = .now, closure: BloodOxygenClosure? = nil) { + let data = BleMessage.shared.getSyncCmd(.bloodOxygen, option) newStartSyncHealthData(closure: closure, data: data, synType: .bloodOxygen) } // 拉取心跳数据 - func getHeartRateHistoryData( closure: HeartRateClosure? = nil) { - let data = BleMessage.shared.getSyncCmd(.heartRate) + func getHeartRateHistoryData(option: SyncOption = .now, closure: HeartRateClosure? = nil) { + let data = BleMessage.shared.getSyncCmd(.heartRate, option) newStartSyncHealthData(closure: closure, data: data, synType: .heartRate) } // 拉取计步数据 - func getStepHistoryData( closure: StepClosure? = nil) { - let data = BleMessage.shared.getSyncCmd(.step) + func getStepHistoryData(option: SyncOption = .now, closure: StepClosure? = nil) { + let data = BleMessage.shared.getSyncCmd(.step, option) newStartSyncHealthData(closure: closure, data: data, synType: .step) } // 拉取训练数据 - func getTrainHistoryData( closure: TrainClosure? = nil) { - let data = BleMessage.shared.getSyncCmd(.train) + func getTrainHistoryData(option: SyncOption = .now, closure: TrainClosure? = nil) { + let data = BleMessage.shared.getSyncCmd(.train, option) newStartSyncHealthData(closure: closure, data: data, synType: .train) } // 拉取压力数据 - func getPressureHistoryData( closure: PressureClosure? = nil) { - let data = BleMessage.shared.getSyncCmd(.pressure) + func getPressureHistoryData(option: SyncOption = .now, closure: PressureClosure? = nil) { + let data = BleMessage.shared.getSyncCmd(.pressure, option) newStartSyncHealthData(closure: closure, data: data, synType: .pressure) } @@ -300,7 +300,7 @@ extension BluetoothManager { case is SleepClosure: if sleepClosure == nil { sleepClosure = closure as? SleepClosure - sleepClosure?([], -1002) + sleepClosure?(nil, -1002) sleepClosure = nil } case is StepClosure: @@ -447,7 +447,13 @@ extension BluetoothManager { case 0x8019:// 睡眠数据上报 print("睡眠数据上报") let content = parseContentFromBytes(bytes) - parseSleepData(content) + if (content.first == 0xff) { + for delegate in syncDelegateList { + delegate.didReceiveFinishCommand(0x8019) + } + }else { + parseSleepData(content) + } case 0x8020:// 历史压力数据上报 print("历史压力数据上报") let content = parseContentFromBytes(bytes) @@ -617,12 +623,11 @@ extension BluetoothManager { func parseSleepData (_ content: [UInt8]) { guard content.count > 0 else { print("无有效的信息") - sleepClosure?([], nil) + sleepClosure?(nil, nil) return } - let array = SleepModel.toSleepArray(content) - SleepModel.addArray(array)// 加入数据库 - sleepClosure?(array, nil) + let model = NewSleepModel.toSleepModel(content) + sleepClosure?(model, nil) } // 实时步数,卡路里,距离数据 diff --git a/HDFwear/Tools/BluetoothManager.swift b/HDFwear/Tools/BluetoothManager.swift index 216dbfa..ac22b7f 100644 --- a/HDFwear/Tools/BluetoothManager.swift +++ b/HDFwear/Tools/BluetoothManager.swift @@ -55,6 +55,8 @@ extension BluetoothSyncDelegate { func didReceiveFindPhoneCommand(value: Int) { } func didReceiveCallOff(){ } func didReceiveCameraCommand(status: UInt8) { } + + func didReceiveFinishCommand(_ receiveDataType: Int) { } } @@ -81,7 +83,7 @@ class BluetoothManager: NSObject { var bloodPressureClosure: BloodPressureClosure? typealias BloodOxygenClosure = (_ boArray: [BloodOxygenModel], _ error: Int?) -> Void var bloodOxygenClosure: BloodOxygenClosure? - typealias SleepClosure = (_ sleepArray: [SleepModel], _ error: Int?) -> Void + typealias SleepClosure = (_ sleepModel: NewSleepModel?, _ error: Int?) -> Void var sleepClosure: SleepClosure? typealias StepClosure = (_ stepArray: [StepModel], _ error: Int?) -> Void var stepClosure: StepClosure? @@ -1271,7 +1273,7 @@ class BluetoothManager: NSObject { heartRateClosure?([], -1001) bloodPressureClosure?([], -1001) bloodOxygenClosure?([], -1001) - sleepClosure?([], -1001) + sleepClosure?(nil, -1001) stepClosure?([], -1001) trainClosure?(nil, -1001) pressureClosure?([], -1001)