objects = { | objects = { | ||||
/* Begin PBXBuildFile section */ | /* Begin PBXBuildFile section */ | ||||
7802C5AD2C903A31008D7616 /* ELMeatProbeCustomDataModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5AC2C903A31008D7616 /* ELMeatProbeCustomDataModel.m */; }; | |||||
7802C5B02C903A4B008D7616 /* ELMeatProbeBoxCustomDataModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5AF2C903A4B008D7616 /* ELMeatProbeBoxCustomDataModel.m */; }; | |||||
7802C5C92C903A7F008D7616 /* ELMeatProbeBoxMultipleBleBBQParamModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5B22C903A7F008D7616 /* ELMeatProbeBoxMultipleBleBBQParamModel.m */; }; | |||||
7802C5CA2C903A7F008D7616 /* ELMeatProbeBoxMultipleBleCmdTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5B42C903A7F008D7616 /* ELMeatProbeBoxMultipleBleCmdTool.m */; }; | |||||
7802C5CB2C903A7F008D7616 /* ELMeatProbeBoxMultipleBleParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5B72C903A7F008D7616 /* ELMeatProbeBoxMultipleBleParser.m */; }; | |||||
7802C5CC2C903A7F008D7616 /* MultipleMeatProbeBoxVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5BA2C903A7F008D7616 /* MultipleMeatProbeBoxVC.m */; }; | |||||
7802C5CD2C903A7F008D7616 /* MultipleMeatProbeBoxVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7802C5BB2C903A7F008D7616 /* MultipleMeatProbeBoxVC.xib */; }; | |||||
7802C5CE2C903A7F008D7616 /* ELMeatProbeScreenBoxBleBBQParamModel.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5BE2C903A7F008D7616 /* ELMeatProbeScreenBoxBleBBQParamModel.m */; }; | |||||
7802C5CF2C903A7F008D7616 /* ELMeatProbeScreenBoxBleCmdTool.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5C02C903A7F008D7616 /* ELMeatProbeScreenBoxBleCmdTool.m */; }; | |||||
7802C5D02C903A7F008D7616 /* ELMeatProbeScreenBoxBleParser.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5C32C903A7F008D7616 /* ELMeatProbeScreenBoxBleParser.m */; }; | |||||
7802C5D12C903A7F008D7616 /* MeatProbeScreenBoxVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 7802C5C62C903A7F008D7616 /* MeatProbeScreenBoxVC.m */; }; | |||||
7802C5D22C903A7F008D7616 /* MeatProbeScreenBoxVC.xib in Resources */ = {isa = PBXBuildFile; fileRef = 7802C5C72C903A7F008D7616 /* MeatProbeScreenBoxVC.xib */; }; | |||||
78350BB329D2826900456695 /* libHTBodyfat_SDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78350BB129D2826900456695 /* libHTBodyfat_SDK.a */; }; | 78350BB329D2826900456695 /* libHTBodyfat_SDK.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78350BB129D2826900456695 /* libHTBodyfat_SDK.a */; }; | ||||
78350BB729D282A300456695 /* libBhBodyComposition120.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78350BB429D282A300456695 /* libBhBodyComposition120.a */; }; | 78350BB729D282A300456695 /* libBhBodyComposition120.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 78350BB429D282A300456695 /* libBhBodyComposition120.a */; }; | ||||
78350BBB29D2869000456695 /* BodyScaleVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 78350BB929D2869000456695 /* BodyScaleVC.m */; }; | 78350BBB29D2869000456695 /* BodyScaleVC.m in Sources */ = {isa = PBXBuildFile; fileRef = 78350BB929D2869000456695 /* BodyScaleVC.m */; }; | ||||
/* End PBXContainerItemProxy section */ | /* End PBXContainerItemProxy section */ | ||||
/* Begin PBXFileReference section */ | /* Begin PBXFileReference section */ | ||||
7802C5AB2C903A31008D7616 /* ELMeatProbeCustomDataModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeCustomDataModel.h; sourceTree = "<group>"; }; | |||||
7802C5AC2C903A31008D7616 /* ELMeatProbeCustomDataModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ELMeatProbeCustomDataModel.m; sourceTree = "<group>"; }; | |||||
7802C5AE2C903A4B008D7616 /* ELMeatProbeBoxCustomDataModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeBoxCustomDataModel.h; sourceTree = "<group>"; }; | |||||
7802C5AF2C903A4B008D7616 /* ELMeatProbeBoxCustomDataModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ELMeatProbeBoxCustomDataModel.m; sourceTree = "<group>"; }; | |||||
7802C5B12C903A7F008D7616 /* ELMeatProbeBoxMultipleBleBBQParamModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeBoxMultipleBleBBQParamModel.h; sourceTree = "<group>"; }; | |||||
7802C5B22C903A7F008D7616 /* ELMeatProbeBoxMultipleBleBBQParamModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ELMeatProbeBoxMultipleBleBBQParamModel.m; sourceTree = "<group>"; }; | |||||
7802C5B32C903A7F008D7616 /* ELMeatProbeBoxMultipleBleCmdTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeBoxMultipleBleCmdTool.h; sourceTree = "<group>"; }; | |||||
7802C5B42C903A7F008D7616 /* ELMeatProbeBoxMultipleBleCmdTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ELMeatProbeBoxMultipleBleCmdTool.m; sourceTree = "<group>"; }; | |||||
7802C5B52C903A7F008D7616 /* ELMeatProbeBoxMultipleBleHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeBoxMultipleBleHeader.h; sourceTree = "<group>"; }; | |||||
7802C5B62C903A7F008D7616 /* ELMeatProbeBoxMultipleBleParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeBoxMultipleBleParser.h; sourceTree = "<group>"; }; | |||||
7802C5B72C903A7F008D7616 /* ELMeatProbeBoxMultipleBleParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ELMeatProbeBoxMultipleBleParser.m; sourceTree = "<group>"; }; | |||||
7802C5B92C903A7F008D7616 /* MultipleMeatProbeBoxVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MultipleMeatProbeBoxVC.h; sourceTree = "<group>"; }; | |||||
7802C5BA2C903A7F008D7616 /* MultipleMeatProbeBoxVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MultipleMeatProbeBoxVC.m; sourceTree = "<group>"; }; | |||||
7802C5BB2C903A7F008D7616 /* MultipleMeatProbeBoxVC.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MultipleMeatProbeBoxVC.xib; sourceTree = "<group>"; }; | |||||
7802C5BD2C903A7F008D7616 /* ELMeatProbeScreenBoxBleBBQParamModel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeScreenBoxBleBBQParamModel.h; sourceTree = "<group>"; }; | |||||
7802C5BE2C903A7F008D7616 /* ELMeatProbeScreenBoxBleBBQParamModel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ELMeatProbeScreenBoxBleBBQParamModel.m; sourceTree = "<group>"; }; | |||||
7802C5BF2C903A7F008D7616 /* ELMeatProbeScreenBoxBleCmdTool.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeScreenBoxBleCmdTool.h; sourceTree = "<group>"; }; | |||||
7802C5C02C903A7F008D7616 /* ELMeatProbeScreenBoxBleCmdTool.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ELMeatProbeScreenBoxBleCmdTool.m; sourceTree = "<group>"; }; | |||||
7802C5C12C903A7F008D7616 /* ELMeatProbeScreenBoxBleHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeScreenBoxBleHeader.h; sourceTree = "<group>"; }; | |||||
7802C5C22C903A7F008D7616 /* ELMeatProbeScreenBoxBleParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ELMeatProbeScreenBoxBleParser.h; sourceTree = "<group>"; }; | |||||
7802C5C32C903A7F008D7616 /* ELMeatProbeScreenBoxBleParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ELMeatProbeScreenBoxBleParser.m; sourceTree = "<group>"; }; | |||||
7802C5C52C903A7F008D7616 /* MeatProbeScreenBoxVC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MeatProbeScreenBoxVC.h; sourceTree = "<group>"; }; | |||||
7802C5C62C903A7F008D7616 /* MeatProbeScreenBoxVC.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = MeatProbeScreenBoxVC.m; sourceTree = "<group>"; }; | |||||
7802C5C72C903A7F008D7616 /* MeatProbeScreenBoxVC.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = MeatProbeScreenBoxVC.xib; sourceTree = "<group>"; }; | |||||
78350BB129D2826900456695 /* libHTBodyfat_SDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libHTBodyfat_SDK.a; sourceTree = "<group>"; }; | 78350BB129D2826900456695 /* libHTBodyfat_SDK.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libHTBodyfat_SDK.a; sourceTree = "<group>"; }; | ||||
78350BB229D2826900456695 /* HTBodyfat_SDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTBodyfat_SDK.h; sourceTree = "<group>"; }; | 78350BB229D2826900456695 /* HTBodyfat_SDK.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HTBodyfat_SDK.h; sourceTree = "<group>"; }; | ||||
78350BB429D282A300456695 /* libBhBodyComposition120.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libBhBodyComposition120.a; sourceTree = "<group>"; }; | 78350BB429D282A300456695 /* libBhBodyComposition120.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libBhBodyComposition120.a; sourceTree = "<group>"; }; | ||||
/* End PBXFrameworksBuildPhase section */ | /* End PBXFrameworksBuildPhase section */ | ||||
/* Begin PBXGroup section */ | /* Begin PBXGroup section */ | ||||
7802C5B82C903A7F008D7616 /* BLE */ = { | |||||
isa = PBXGroup; | |||||
children = ( | |||||
7802C5B12C903A7F008D7616 /* ELMeatProbeBoxMultipleBleBBQParamModel.h */, | |||||
7802C5B22C903A7F008D7616 /* ELMeatProbeBoxMultipleBleBBQParamModel.m */, | |||||
7802C5B32C903A7F008D7616 /* ELMeatProbeBoxMultipleBleCmdTool.h */, | |||||
7802C5B42C903A7F008D7616 /* ELMeatProbeBoxMultipleBleCmdTool.m */, | |||||
7802C5B52C903A7F008D7616 /* ELMeatProbeBoxMultipleBleHeader.h */, | |||||
7802C5B62C903A7F008D7616 /* ELMeatProbeBoxMultipleBleParser.h */, | |||||
7802C5B72C903A7F008D7616 /* ELMeatProbeBoxMultipleBleParser.m */, | |||||
); | |||||
path = BLE; | |||||
sourceTree = "<group>"; | |||||
}; | |||||
7802C5BC2C903A7F008D7616 /* 27C_MultipleMeatProbeBox */ = { | |||||
isa = PBXGroup; | |||||
children = ( | |||||
7802C5B82C903A7F008D7616 /* BLE */, | |||||
7802C5B92C903A7F008D7616 /* MultipleMeatProbeBoxVC.h */, | |||||
7802C5BA2C903A7F008D7616 /* MultipleMeatProbeBoxVC.m */, | |||||
7802C5BB2C903A7F008D7616 /* MultipleMeatProbeBoxVC.xib */, | |||||
); | |||||
path = 27C_MultipleMeatProbeBox; | |||||
sourceTree = "<group>"; | |||||
}; | |||||
7802C5C42C903A7F008D7616 /* BLE */ = { | |||||
isa = PBXGroup; | |||||
children = ( | |||||
7802C5BD2C903A7F008D7616 /* ELMeatProbeScreenBoxBleBBQParamModel.h */, | |||||
7802C5BE2C903A7F008D7616 /* ELMeatProbeScreenBoxBleBBQParamModel.m */, | |||||
7802C5BF2C903A7F008D7616 /* ELMeatProbeScreenBoxBleCmdTool.h */, | |||||
7802C5C02C903A7F008D7616 /* ELMeatProbeScreenBoxBleCmdTool.m */, | |||||
7802C5C12C903A7F008D7616 /* ELMeatProbeScreenBoxBleHeader.h */, | |||||
7802C5C22C903A7F008D7616 /* ELMeatProbeScreenBoxBleParser.h */, | |||||
7802C5C32C903A7F008D7616 /* ELMeatProbeScreenBoxBleParser.m */, | |||||
); | |||||
path = BLE; | |||||
sourceTree = "<group>"; | |||||
}; | |||||
7802C5C82C903A7F008D7616 /* 27B_MeatProbeScreenBox */ = { | |||||
isa = PBXGroup; | |||||
children = ( | |||||
7802C5C42C903A7F008D7616 /* BLE */, | |||||
7802C5C52C903A7F008D7616 /* MeatProbeScreenBoxVC.h */, | |||||
7802C5C62C903A7F008D7616 /* MeatProbeScreenBoxVC.m */, | |||||
7802C5C72C903A7F008D7616 /* MeatProbeScreenBoxVC.xib */, | |||||
); | |||||
path = 27B_MeatProbeScreenBox; | |||||
sourceTree = "<group>"; | |||||
}; | |||||
78350BB029D280D300456695 /* DeviceDemo */ = { | 78350BB029D280D300456695 /* DeviceDemo */ = { | ||||
isa = PBXGroup; | isa = PBXGroup; | ||||
children = ( | children = ( | ||||
78DC4DF72990FC10006C6911 /* 25_HeightBodyFatScale */, | 78DC4DF72990FC10006C6911 /* 25_HeightBodyFatScale */, | ||||
78E07B6C2A49664D00E68200 /* 26_MeatProbe */, | 78E07B6C2A49664D00E68200 /* 26_MeatProbe */, | ||||
78E07B702A49664E00E68200 /* 27_MeatProbeBox */, | 78E07B702A49664E00E68200 /* 27_MeatProbeBox */, | ||||
7802C5C82C903A7F008D7616 /* 27B_MeatProbeScreenBox */, | |||||
7802C5BC2C903A7F008D7616 /* 27C_MultipleMeatProbeBox */, | |||||
78CF43522C2EC21A00D0A165 /* 28_Hygrothermograph */, | 78CF43522C2EC21A00D0A165 /* 28_Hygrothermograph */, | ||||
); | ); | ||||
path = DeviceDemo; | path = DeviceDemo; | ||||
78E07B6F2A49664D00E68200 /* MeatProbeVC.h */, | 78E07B6F2A49664D00E68200 /* MeatProbeVC.h */, | ||||
78E07B6D2A49664D00E68200 /* MeatProbeVC.m */, | 78E07B6D2A49664D00E68200 /* MeatProbeVC.m */, | ||||
78E07B6E2A49664D00E68200 /* MeatProbeVC.xib */, | 78E07B6E2A49664D00E68200 /* MeatProbeVC.xib */, | ||||
7802C5AB2C903A31008D7616 /* ELMeatProbeCustomDataModel.h */, | |||||
7802C5AC2C903A31008D7616 /* ELMeatProbeCustomDataModel.m */, | |||||
); | ); | ||||
path = 26_MeatProbe; | path = 26_MeatProbe; | ||||
sourceTree = "<group>"; | sourceTree = "<group>"; | ||||
78E07B732A49664E00E68200 /* ELMeatProbeBoxBleHeader.h */, | 78E07B732A49664E00E68200 /* ELMeatProbeBoxBleHeader.h */, | ||||
78E07B722A49664E00E68200 /* ELMeatProbeBoxBleParser.h */, | 78E07B722A49664E00E68200 /* ELMeatProbeBoxBleParser.h */, | ||||
78E07B752A49664E00E68200 /* ELMeatProbeBoxBleParser.m */, | 78E07B752A49664E00E68200 /* ELMeatProbeBoxBleParser.m */, | ||||
7802C5AE2C903A4B008D7616 /* ELMeatProbeBoxCustomDataModel.h */, | |||||
7802C5AF2C903A4B008D7616 /* ELMeatProbeBoxCustomDataModel.m */, | |||||
); | ); | ||||
path = Ble; | path = Ble; | ||||
sourceTree = "<group>"; | sourceTree = "<group>"; | ||||
78DC4DE32990FB2E006C6911 /* ELDemoScanVC.xib in Resources */, | 78DC4DE32990FB2E006C6911 /* ELDemoScanVC.xib in Resources */, | ||||
E622E26E243F1CA6003C319D /* LaunchScreen.storyboard in Resources */, | E622E26E243F1CA6003C319D /* LaunchScreen.storyboard in Resources */, | ||||
78CF43542C2EC21B00D0A165 /* HygrothermographVC.xib in Resources */, | 78CF43542C2EC21B00D0A165 /* HygrothermographVC.xib in Resources */, | ||||
7802C5CD2C903A7F008D7616 /* MultipleMeatProbeBoxVC.xib in Resources */, | |||||
E622E26B243F1CA6003C319D /* Assets.xcassets in Resources */, | E622E26B243F1CA6003C319D /* Assets.xcassets in Resources */, | ||||
78AC3B2B2C0D994900A62C61 /* PrivacyInfo.bundle in Resources */, | 78AC3B2B2C0D994900A62C61 /* PrivacyInfo.bundle in Resources */, | ||||
7802C5D22C903A7F008D7616 /* MeatProbeScreenBoxVC.xib in Resources */, | |||||
78DC4DF62990FB40006C6911 /* ELDeviceScanCell.xib in Resources */, | 78DC4DF62990FB40006C6911 /* ELDeviceScanCell.xib in Resources */, | ||||
78E07B7B2A49664E00E68200 /* MeatProbeVC.xib in Resources */, | 78E07B7B2A49664E00E68200 /* MeatProbeVC.xib in Resources */, | ||||
78350BBD29D28C1200456695 /* README.md in Resources */, | 78350BBD29D28C1200456695 /* README.md in Resources */, | ||||
95565B7A2786EA3B000265EA /* SkipScanViewController.m in Sources */, | 95565B7A2786EA3B000265EA /* SkipScanViewController.m in Sources */, | ||||
78DC4DFB2990FC10006C6911 /* HeightBodyFatScaleVC.m in Sources */, | 78DC4DFB2990FC10006C6911 /* HeightBodyFatScaleVC.m in Sources */, | ||||
9557263B276C38CD003BFBAC /* FaceMaskScanViewController.m in Sources */, | 9557263B276C38CD003BFBAC /* FaceMaskScanViewController.m in Sources */, | ||||
7802C5D02C903A7F008D7616 /* ELMeatProbeScreenBoxBleParser.m in Sources */, | |||||
9557263F276C38CD003BFBAC /* EightScaleConnectionViewController.m in Sources */, | 9557263F276C38CD003BFBAC /* EightScaleConnectionViewController.m in Sources */, | ||||
9557262B276C38CD003BFBAC /* WheelMonitorScanViewController.m in Sources */, | 9557262B276C38CD003BFBAC /* WheelMonitorScanViewController.m in Sources */, | ||||
7802C5AD2C903A31008D7616 /* ELMeatProbeCustomDataModel.m in Sources */, | |||||
95572629276C38CD003BFBAC /* BloodSugarConnectionViewController.m in Sources */, | 95572629276C38CD003BFBAC /* BloodSugarConnectionViewController.m in Sources */, | ||||
78DC4DE52990FB2E006C6911 /* ELDemoScanVC.m in Sources */, | 78DC4DE52990FB2E006C6911 /* ELDemoScanVC.m in Sources */, | ||||
9557262A276C38CD003BFBAC /* WheelMonitorConnectViewController.m in Sources */, | 9557262A276C38CD003BFBAC /* WheelMonitorConnectViewController.m in Sources */, | ||||
78DC4DF22990FB40006C6911 /* ELDeviceTypeCell.m in Sources */, | 78DC4DF22990FB40006C6911 /* ELDeviceTypeCell.m in Sources */, | ||||
78DC4DF52990FB40006C6911 /* ELDeviceScanCell.m in Sources */, | 78DC4DF52990FB40006C6911 /* ELDeviceScanCell.m in Sources */, | ||||
78DC4DF12990FB40006C6911 /* ELDemoView.m in Sources */, | 78DC4DF12990FB40006C6911 /* ELDemoView.m in Sources */, | ||||
7802C5B02C903A4B008D7616 /* ELMeatProbeBoxCustomDataModel.m in Sources */, | |||||
95572626276C38CD003BFBAC /* AiFreshNutritionScaleConnectionViewController.m in Sources */, | 95572626276C38CD003BFBAC /* AiFreshNutritionScaleConnectionViewController.m in Sources */, | ||||
9557262F276C38CD003BFBAC /* ELBfsWifiConnectTableViewCell.m in Sources */, | 9557262F276C38CD003BFBAC /* ELBfsWifiConnectTableViewCell.m in Sources */, | ||||
95572623276C38CD003BFBAC /* BloodConnectViewController.m in Sources */, | 95572623276C38CD003BFBAC /* BloodConnectViewController.m in Sources */, | ||||
958B4EB5263C08E800476BAE /* MASViewConstraint.m in Sources */, | 958B4EB5263C08E800476BAE /* MASViewConstraint.m in Sources */, | ||||
95572628276C38CD003BFBAC /* BloodSugarScanViewController.m in Sources */, | 95572628276C38CD003BFBAC /* BloodSugarScanViewController.m in Sources */, | ||||
9557264C276C38CD003BFBAC /* RemoteControlScanViewController.m in Sources */, | 9557264C276C38CD003BFBAC /* RemoteControlScanViewController.m in Sources */, | ||||
7802C5D12C903A7F008D7616 /* MeatProbeScreenBoxVC.m in Sources */, | |||||
9557262C276C38CD003BFBAC /* BroadcastNutritionScaleViewController.m in Sources */, | 9557262C276C38CD003BFBAC /* BroadcastNutritionScaleViewController.m in Sources */, | ||||
95572643276C38CD003BFBAC /* BodyFatScaleScanViewController.m in Sources */, | 95572643276C38CD003BFBAC /* BodyFatScaleScanViewController.m in Sources */, | ||||
95572627276C38CD003BFBAC /* BroadcastScaleViewController.m in Sources */, | 95572627276C38CD003BFBAC /* BroadcastScaleViewController.m in Sources */, | ||||
E622E271243F1CA6003C319D /* main.m in Sources */, | E622E271243F1CA6003C319D /* main.m in Sources */, | ||||
78E07B7F2A49664E00E68200 /* MeatProbeBoxVC.m in Sources */, | 78E07B7F2A49664E00E68200 /* MeatProbeBoxVC.m in Sources */, | ||||
95572646276C38CD003BFBAC /* FoodThermometerConnectionViewController.m in Sources */, | 95572646276C38CD003BFBAC /* FoodThermometerConnectionViewController.m in Sources */, | ||||
7802C5CE2C903A7F008D7616 /* ELMeatProbeScreenBoxBleBBQParamModel.m in Sources */, | |||||
958B4EB3263C08E800476BAE /* View+MASAdditions.m in Sources */, | 958B4EB3263C08E800476BAE /* View+MASAdditions.m in Sources */, | ||||
958B4EB1263C08E800476BAE /* MASLayoutConstraint.m in Sources */, | 958B4EB1263C08E800476BAE /* MASLayoutConstraint.m in Sources */, | ||||
9557263A276C38CD003BFBAC /* FaceMaskConnectionViewController.m in Sources */, | 9557263A276C38CD003BFBAC /* FaceMaskConnectionViewController.m in Sources */, | ||||
95572636276C38CD003BFBAC /* OximeterScanViewController.m in Sources */, | 95572636276C38CD003BFBAC /* OximeterScanViewController.m in Sources */, | ||||
78E07B7D2A49664E00E68200 /* ELMeatProbeBoxBleParser.m in Sources */, | 78E07B7D2A49664E00E68200 /* ELMeatProbeBoxBleParser.m in Sources */, | ||||
958B4EA4263C08E800476BAE /* ELInputAlertView.m in Sources */, | 958B4EA4263C08E800476BAE /* ELInputAlertView.m in Sources */, | ||||
7802C5CC2C903A7F008D7616 /* MultipleMeatProbeBoxVC.m in Sources */, | |||||
958B4EB6263C08E800476BAE /* MASViewAttribute.m in Sources */, | 958B4EB6263C08E800476BAE /* MASViewAttribute.m in Sources */, | ||||
958B4EBB263C08E800476BAE /* InheritConnectViewController.m in Sources */, | 958B4EBB263C08E800476BAE /* InheritConnectViewController.m in Sources */, | ||||
958B4EB4263C08E800476BAE /* MASConstraint.m in Sources */, | 958B4EB4263C08E800476BAE /* MASConstraint.m in Sources */, | ||||
7802C5CA2C903A7F008D7616 /* ELMeatProbeBoxMultipleBleCmdTool.m in Sources */, | |||||
958B4EAA263C08E800476BAE /* AilinkSuperConnectViewController.m in Sources */, | 958B4EAA263C08E800476BAE /* AilinkSuperConnectViewController.m in Sources */, | ||||
958B4EB0263C08E800476BAE /* MASConstraintMaker.m in Sources */, | 958B4EB0263C08E800476BAE /* MASConstraintMaker.m in Sources */, | ||||
7802C5C92C903A7F008D7616 /* ELMeatProbeBoxMultipleBleBBQParamModel.m in Sources */, | |||||
78DC4DF32990FB40006C6911 /* ELDemoButton.m in Sources */, | 78DC4DF32990FB40006C6911 /* ELDemoButton.m in Sources */, | ||||
7802C5CF2C903A7F008D7616 /* ELMeatProbeScreenBoxBleCmdTool.m in Sources */, | |||||
958B4EA5263C08E800476BAE /* UILabel+WZAdd.m in Sources */, | 958B4EA5263C08E800476BAE /* UILabel+WZAdd.m in Sources */, | ||||
95572633276C38CD003BFBAC /* BabyScaleConnectViewController.m in Sources */, | 95572633276C38CD003BFBAC /* BabyScaleConnectViewController.m in Sources */, | ||||
78E07B7A2A49664E00E68200 /* MeatProbeVC.m in Sources */, | 78E07B7A2A49664E00E68200 /* MeatProbeVC.m in Sources */, | ||||
95572644276C38CD003BFBAC /* BodyFatScaleConnectViewController.m in Sources */, | 95572644276C38CD003BFBAC /* BodyFatScaleConnectViewController.m in Sources */, | ||||
958B4EBD263C08E800476BAE /* AppDelegate.m in Sources */, | 958B4EBD263C08E800476BAE /* AppDelegate.m in Sources */, | ||||
7802C5CB2C903A7F008D7616 /* ELMeatProbeBoxMultipleBleParser.m in Sources */, | |||||
95565B792786EA3B000265EA /* SkipConnectionViewController.m in Sources */, | 95565B792786EA3B000265EA /* SkipConnectionViewController.m in Sources */, | ||||
958B4EAE263C08E800476BAE /* ViewController+MASAdditions.m in Sources */, | 958B4EAE263C08E800476BAE /* ViewController+MASAdditions.m in Sources */, | ||||
958B4EA8263C08E800476BAE /* CABasicAnimation+ELAnimation.m in Sources */, | 958B4EA8263C08E800476BAE /* CABasicAnimation+ELAnimation.m in Sources */, | ||||
buildSettings = { | buildSettings = { | ||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||
CODE_SIGN_STYLE = Automatic; | CODE_SIGN_STYLE = Automatic; | ||||
CURRENT_PROJECT_VERSION = 20240628; | |||||
CURRENT_PROJECT_VERSION = 20240910; | |||||
DEVELOPMENT_TEAM = YEU77XR292; | DEVELOPMENT_TEAM = YEU77XR292; | ||||
FRAMEWORK_SEARCH_PATHS = ( | FRAMEWORK_SEARCH_PATHS = ( | ||||
"$(inherited)", | "$(inherited)", | ||||
"$(PROJECT_DIR)/AILinkBleSDKDemo/DeviceDemo/13_EightScale/HTBodyfat_SDK", | "$(PROJECT_DIR)/AILinkBleSDKDemo/DeviceDemo/13_EightScale/HTBodyfat_SDK", | ||||
"$(PROJECT_DIR)/AILinkBleSDKDemo/DeviceDemo/13_EightScale/BhBodyComposition120", | "$(PROJECT_DIR)/AILinkBleSDKDemo/DeviceDemo/13_EightScale/BhBodyComposition120", | ||||
); | ); | ||||
MARKETING_VERSION = 1.9.2; | |||||
MARKETING_VERSION = 1.10.0; | |||||
OTHER_LDFLAGS = "-ObjC"; | OTHER_LDFLAGS = "-ObjC"; | ||||
PRODUCT_BUNDLE_IDENTIFIER = com.ellinkthings.ailinksdk.app; | PRODUCT_BUNDLE_IDENTIFIER = com.ellinkthings.ailinksdk.app; | ||||
PRODUCT_NAME = "$(TARGET_NAME)"; | PRODUCT_NAME = "$(TARGET_NAME)"; | ||||
buildSettings = { | buildSettings = { | ||||
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; | ||||
CODE_SIGN_STYLE = Automatic; | CODE_SIGN_STYLE = Automatic; | ||||
CURRENT_PROJECT_VERSION = 20240628; | |||||
CURRENT_PROJECT_VERSION = 20240910; | |||||
DEVELOPMENT_TEAM = YEU77XR292; | DEVELOPMENT_TEAM = YEU77XR292; | ||||
FRAMEWORK_SEARCH_PATHS = ( | FRAMEWORK_SEARCH_PATHS = ( | ||||
"$(inherited)", | "$(inherited)", | ||||
"$(PROJECT_DIR)/AILinkBleSDKDemo/DeviceDemo/13_EightScale/HTBodyfat_SDK", | "$(PROJECT_DIR)/AILinkBleSDKDemo/DeviceDemo/13_EightScale/HTBodyfat_SDK", | ||||
"$(PROJECT_DIR)/AILinkBleSDKDemo/DeviceDemo/13_EightScale/BhBodyComposition120", | "$(PROJECT_DIR)/AILinkBleSDKDemo/DeviceDemo/13_EightScale/BhBodyComposition120", | ||||
); | ); | ||||
MARKETING_VERSION = 1.9.2; | |||||
MARKETING_VERSION = 1.10.0; | |||||
OTHER_LDFLAGS = "-ObjC"; | OTHER_LDFLAGS = "-ObjC"; | ||||
PRODUCT_BUNDLE_IDENTIFIER = com.ellinkthings.ailinksdk.app; | PRODUCT_BUNDLE_IDENTIFIER = com.ellinkthings.ailinksdk.app; | ||||
PRODUCT_NAME = "$(TARGET_NAME)"; | PRODUCT_NAME = "$(TARGET_NAME)"; |
#define AILinkBleSDK_Version_h | #define AILinkBleSDK_Version_h | ||||
//版本号 SDK Version | //版本号 SDK Version | ||||
#define AiLinkBleSDKVersion @"1.9.0" // 20240603 | |||||
#define AiLinkBleSDKVersion @"1.10.0" // 20240910 | |||||
#endif /* AILinkBleSDK_Version_h */ | #endif /* AILinkBleSDK_Version_h */ |
ELBodyFatScaleBleDataType_MCUBackHeartRateMeasureFailed = 0x0D , | ELBodyFatScaleBleDataType_MCUBackHeartRateMeasureFailed = 0x0D , | ||||
/** MCU->APP:MCU请求补全体脂数据 */ | /** MCU->APP:MCU请求补全体脂数据 */ | ||||
ELBodyFatScaleBleDataType_MCUBackNeedsFillBodyData = 0x0E , | ELBodyFatScaleBleDataType_MCUBackNeedsFillBodyData = 0x0E , | ||||
/** MCU->APP:设备上报模式 */ | |||||
ELBodyFatScaleBleDataType_MCUReportingMode = 0x0F , | |||||
/** App发送指令切换单位 */ | /** App发送指令切换单位 */ | ||||
ELBodyFatScaleBleDataType_AppSendUnit = 0x81 , | ELBodyFatScaleBleDataType_AppSendUnit = 0x81 , |
*/ | */ | ||||
- (void)bodyFatScaleManagerCallBackSetIPAddressResult:(NSInteger)result; | - (void)bodyFatScaleManagerCallBackSetIPAddressResult:(NSInteger)result; | ||||
/** MCU reporting mode (MCU上报模式 ) | |||||
* @param mode : 0:体脂模式(默认),1:体重模式(没有阻抗和体脂数据) | |||||
*/ | |||||
- (void)bodyFatScaleManagerCallBackReportingMode:(NSInteger)mode; | |||||
@end | @end | ||||
PHSex_MALE = 1,//男 | PHSex_MALE = 1,//男 | ||||
}; | }; | ||||
//矿物质重量 | |||||
typedef NS_ENUM(NSUInteger, AILinkMineralWeightType) { | |||||
AILinkMineralWeightTypeUnknown = 0,//未知 | |||||
AILinkMineralWeightTypeInsufficient = 1,//不足 | |||||
AILinkMineralWeightTypeStandard = 2,//标准 | |||||
AILinkMineralWeightTypeExcellent = 3,//偏高 | |||||
}; | |||||
//四肢肌肉指数 | //四肢肌肉指数 | ||||
typedef NS_ENUM(NSUInteger, AILinkLimbMuscleIndexType) { | typedef NS_ENUM(NSUInteger, AILinkLimbMuscleIndexType) { | ||||
@interface ELBodyIndexAlgorithmModel : NSObject | @interface ELBodyIndexAlgorithmModel : NSObject | ||||
#pragma mark ============ 标准判断临界值数组 ============== | #pragma mark ============ 标准判断临界值数组 ============== | ||||
/// 四肢肌肉指数 标准判断 | /// 四肢肌肉指数 标准判断 | ||||
/// @param sex 性别 | /// @param sex 性别 | ||||
/// @param cmHeight 身高(cm) | /// @param cmHeight 身高(cm) | ||||
/// @param age 年龄 | /// @param age 年龄 | ||||
+ (NSArray<NSString *> *)getSkeletalMuscleMassScopeSex:(PHSex)sex age:(float)age; | + (NSArray<NSString *> *)getSkeletalMuscleMassScopeSex:(PHSex)sex age:(float)age; | ||||
/// 水分重量 标准判断2个临界值 | |||||
/// @param sex 性别 | |||||
/// @param weight 体重 | |||||
+ (NSArray<NSString *> *)getWaterWeightScopeSex:(PHSex)sex weight:(float)weight; | |||||
/// 皮下脂肪量 标准判断2个临界值 | |||||
/// @param sex 性别 | |||||
/// @param weight 体重 | |||||
+ (NSArray<NSString *> *)getSubcutaneousFatMassScopeSex:(PHSex)sex weight:(float)weight; | |||||
#pragma mark ============ 判断标准数组 ============== | #pragma mark ============ 判断标准数组 ============== | ||||
//四肢肌肉指数标准词条 | //四肢肌肉指数标准词条 | ||||
+(NSArray<NSNumber *> *)getLimbMuscleIndexStandardArray; | +(NSArray<NSNumber *> *)getLimbMuscleIndexStandardArray; | ||||
/// @param weight 体重(KG) | /// @param weight 体重(KG) | ||||
/// @param standardWeight 标准体重(KG) | /// @param standardWeight 标准体重(KG) | ||||
+ (AILinkFatLevelType)getfatLevelWithweight:(double)weight andStandardWeight:(double)standardWeight; | + (AILinkFatLevelType)getfatLevelWithweight:(double)weight andStandardWeight:(double)standardWeight; | ||||
#pragma mark - 新增指标 | |||||
/** | |||||
* 矿物质重量 标准判断 | |||||
* | |||||
* @param mineralWeightValue 体重(KG) | |||||
* @param weight 体重 | |||||
* | |||||
* @return 不足、标准、偏高、Null | |||||
*/ | |||||
+ (AILinkMineralWeightType)getMineralWeightType:(float)mineralWeightValue; | |||||
@end | @end | ||||
NS_ASSUME_NONNULL_END | NS_ASSUME_NONNULL_END |
BroadcastScaleTestStatusADCTestSuccess, | BroadcastScaleTestStatusADCTestSuccess, | ||||
//Impedance measurement failed (the impedance value is 0xFFFF at this time)(阻抗测量失败(此时阻抗数值为 0xFFFF)) | //Impedance measurement failed (the impedance value is 0xFFFF at this time)(阻抗测量失败(此时阻抗数值为 0xFFFF)) | ||||
BroadcastScaleTestStatusADCTestFailed, | BroadcastScaleTestStatusADCTestFailed, | ||||
//Weight mode (skip impedance measurement, the impedance value is 0, and the APP will not prompt impedance failure)( 体重模式(跳过阻抗测量,此时阻抗数值为 0, APP不会提示阻抗失败的提示)) | |||||
BroadcastScaleTestStatusWeightMode, | |||||
//End of test(测试结束) | //End of test(测试结束) | ||||
BroadcastScaleTestStatusTestEnd = 0xFF, | BroadcastScaleTestStatusTestEnd = 0xFF, | ||||
}; | }; |
///MCU返回设备测量信息(测量完成的时候才会回调该方法) | ///MCU返回设备测量信息(测量完成的时候才会回调该方法) | ||||
- (void)eightScaleBleReportTestData:(ELEightScaleBleDataModel *)dataModle bfrData:(ELEightScaleBleBfrDataModel *)bfrDataModle; | - (void)eightScaleBleReportTestData:(ELEightScaleBleDataModel *)dataModle bfrData:(ELEightScaleBleBfrDataModel *)bfrDataModle; | ||||
// 双频八电极mcu测量完成返回数据(测量完成的时候才会回调该方法) | |||||
- (void)eightScaleBle0x0068ReportTestData:(ELEightScaleBleDataModel *)dataModel bodyFatData:(ELEightScaleBleBfrDataModel *)bfrDataModel; | |||||
/** MCU返回操作结果 */ | /** MCU返回操作结果 */ | ||||
- (void)eightScaleBleReportOperationWithType:(enum EightScaleOperationType)type unitResult:(enum EightScaleSwitchUnitResult)result; | - (void)eightScaleBleReportOperationWithType:(enum EightScaleOperationType)type unitResult:(enum EightScaleSwitchUnitResult)result; | ||||
///MCU请求补全体脂数据 | ///MCU请求补全体脂数据 | ||||
- (void)eightScaleBleCompletionBodyFatData; | - (void)eightScaleBleCompletionBodyFatData; | ||||
- (void)eightScaleBleCompletionBodyFatData:(ELEightScaleBleDataModel *)dataModel; | |||||
/** | |||||
Back to impedance measurement(返回阻抗测量) | |||||
@param status 阻抗测量状态 | |||||
*/ | |||||
-(void)eightScaleScaleManagerCallBackAdcMeasureStatus:(DualBandEightScaleAdcMeasureStatus)status; | |||||
@end | @end | ||||
@interface ELEightScaleBleManager : ELBluetoothManager | @interface ELEightScaleBleManager : ELBluetoothManager |
EightScaleErrorCodeType_Overweight = 0x01 , | EightScaleErrorCodeType_Overweight = 0x01 , | ||||
} ; | } ; | ||||
//Impedance measurement process(阻抗测量过程) 双频八电极 | |||||
typedef NS_ENUM(NSUInteger, DualBandEightScaleAdcMeasureStatus) { | |||||
DualBandEightScaleAdcMeasureStatus_Testing = 0x04,//测阻抗中 | |||||
DualBandEightScaleAdcMeasureStatus_Fail = 0x06,//测阻抗失败 | |||||
DualBandEightScaleAdcMeasureStatus_SuccessCustom = 0x07,//The impedance measurement is successful, and the APP algorithm is used. The APP will identify the corresponding algorithm according to VID and PID(测阻抗成功,并使用 APP 算法,APP 会根据 VID,PID 来识 别对应算法) | |||||
}; | |||||
#endif /* ELEightScaleSDKHeader_h */ | #endif /* ELEightScaleSDKHeader_h */ |
ELSupportDeviceTypeBroadcastScale_T6 = (0xffff + 0x09) , //65544 T6广播体脂秤 | ELSupportDeviceTypeBroadcastScale_T6 = (0xffff + 0x09) , //65544 T6广播体脂秤 | ||||
ELSupportDeviceType_dualFrequencyEightelectrodeMCUAlgorithm = 0x0068, //双频八电极MCU算法秤 | |||||
}; | }; | ||||
#endif /* ELExSupportDeviceType_h */ | #endif /* ELExSupportDeviceType_h */ |
TH_Dev_SupportFeatures_GroundLight = 5 , | TH_Dev_SupportFeatures_GroundLight = 5 , | ||||
/// 寻物功能(APP点击寻物时,设备蜂鸣器会响) | /// 寻物功能(APP点击寻物时,设备蜂鸣器会响) | ||||
TH_Dev_SupportFeatures_Lost = 6 , | TH_Dev_SupportFeatures_Lost = 6 , | ||||
/// 接收 APP 下发指令 | |||||
TH_Dev_SupportFeatures_ReceiveCommand = 7 , | |||||
/// 温度单位切换 | |||||
TH_Dev_SupportFeatures_TemperatureUnitSwitch = 8 , | |||||
/// 温度报警 | |||||
TH_Dev_SupportFeatures_TemperatureAlarm = 9 , | |||||
/// 湿度报警 | |||||
TH_Dev_SupportFeatures_HumidityAlarm = 10 , | |||||
}; | }; | ||||
/// @param unit 温度单位 | /// @param unit 温度单位 | ||||
/// @param hum 湿度,单位% | /// @param hum 湿度,单位% | ||||
/// @param state 当前设备状态,详细内容见枚举注释 | /// @param state 当前设备状态,详细内容见枚举注释 | ||||
- (void)newTHManagerReturnDevStatePower:(int)power bootTime:(long long)time tem:(float)tem unit:(enum ELDeviceTemperatureUnit)unit hum:(float)hum devState:(enum TH_DevStateType)state; | |||||
/// @param isCharging 设备充电状态 默认是关闭状态 | |||||
- (void)newTHManagerReturnDevStatePower:(int)power bootTime:(long long)time tem:(float)tem unit:(enum ELDeviceTemperatureUnit)unit hum:(float)hum devState:(enum TH_DevStateType)state isCharging:(BOOL)isCharging; | |||||
/** 设备返回阀值 | /** 设备返回阀值 | ||||
// App绑定设备 完成 | // App绑定设备 完成 | ||||
- (void)bindDeviceDone; | - (void)bindDeviceDone; | ||||
/// 解析A7指令 | |||||
- (void)processA7Data:(NSData *)rawData withMac:(NSData *)mac withCid:(UInt16)cid; | |||||
/// 解析A6指令 | |||||
- (void)processA6Data:(NSData *)rawData; | |||||
/// 生成A7数据包 | |||||
- (NSData * _Nullable)makePacketA7Payload:(NSData *)payload withMac:(NSData *)mac withCid:(UInt16)cid; | |||||
/// 生成A6数据包 | |||||
- (NSData * _Nullable)makePacketA6Payload:(NSData *)payload; | |||||
@end | @end | ||||
{ | |||||
"images" : [ | |||||
{ | |||||
"idiom" : "universal", | |||||
"scale" : "1x" | |||||
}, | |||||
{ | |||||
"filename" : "aibbq_add_equipment_probe_100_ic@2x.png", | |||||
"idiom" : "universal", | |||||
"scale" : "2x" | |||||
}, | |||||
{ | |||||
"filename" : "aibbq_add_equipment_probe_100_ic@3x.png", | |||||
"idiom" : "universal", | |||||
"scale" : "3x" | |||||
} | |||||
], | |||||
"info" : { | |||||
"author" : "xcode", | |||||
"version" : 1 | |||||
} | |||||
} |
{ | |||||
"images" : [ | |||||
{ | |||||
"idiom" : "universal", | |||||
"scale" : "1x" | |||||
}, | |||||
{ | |||||
"filename" : "ailink_cid85_banding_cid_0062_100_ic@2x.png", | |||||
"idiom" : "universal", | |||||
"scale" : "2x" | |||||
}, | |||||
{ | |||||
"filename" : "ailink_cid85_banding_cid_0062_100_ic@3x.png", | |||||
"idiom" : "universal", | |||||
"scale" : "3x" | |||||
} | |||||
], | |||||
"info" : { | |||||
"author" : "xcode", | |||||
"version" : 1 | |||||
} | |||||
} |
// | |||||
// ELMeatProbeCustomDataModel.h | |||||
// AILinkBleSDK | |||||
// | |||||
#import <Foundation/Foundation.h> | |||||
#import <AILinkBleSDK/ELMeatProbeBleTool.h> | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
#pragma pack(1) | |||||
typedef struct ELMeatProbeCustomDataStruct { | |||||
UInt8 ver; //数据版本 (当前版本 0x02) //数据总长度: modelSize() | |||||
UInt32 cookingId; //烧烤id (选择食物的时间戳) | |||||
UInt8 foodType; //食物类型 | |||||
UInt8 foodRawness; //食物熟度 | |||||
SInt16 targetTemperature_C; //食物目标温度:℃ | |||||
SInt16 targetTemperature_F; //食物目标温度:℉ | |||||
SInt16 ambientMinTemperature_C; //炉温目标下限:℃ | |||||
SInt16 ambientMinTemperature_F; //炉温目标下限:℉ | |||||
SInt16 ambientMaxTemperature_C; //炉温目标上限:℃ | |||||
SInt16 ambientMaxTemperature_F; //炉温目标上限:℉ | |||||
double alarmTemperaturePercent; //提醒温度对目标温度百分比 0~1.0 | |||||
UInt32 timerStart;//计时开始时间戳 | |||||
UInt32 timerEnd;//计时结束时间戳 | |||||
UInt8 currentUnit; //当前温度单位 | |||||
SInt16 alarmTemperature_C; //食物提醒温度:℃ | |||||
SInt16 alarmTemperature_F; //食物提醒温度:℉ | |||||
UInt8 remarkBytes[32]; //UTF-8 编码 | |||||
} ELMeatProbeCustomDataStruct; | |||||
#pragma pack() | |||||
/// | |||||
@interface ELMeatProbeCustomDataModel : NSObject | |||||
@property (nonatomic, assign) ELMeatProbeCustomDataStruct customStruct; | |||||
@property (nonatomic, assign, readonly) NSInteger ver; | |||||
@property (nonatomic, assign, readonly) NSInteger cookingId; | |||||
@property (nonatomic, assign, readonly) NSInteger foodType; | |||||
@property (nonatomic, assign, readonly) NSInteger foodRawness; | |||||
@property (nonatomic, assign) double alarmTemperaturePercent; | |||||
@property (nonatomic, assign, readonly) ELDeviceTemperatureUnit currentUnit; | |||||
+ (instancetype _Nullable)modelWithData:(NSData *)data; | |||||
- (NSData *)dataValue; | |||||
- (NSString *)remark; | |||||
- (NSString *)setRemark:(NSString *)remark; | |||||
+ (Byte)version; | |||||
+ (Byte)modelSize; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// ELMeatProbeCustomDataModel.m | |||||
// AILinkBleSDK | |||||
// | |||||
#import "ELMeatProbeCustomDataModel.h" | |||||
#import <AILinkBleSDK/NSData+AILinkBle.h> | |||||
#import <objc/runtime.h> | |||||
@implementation ELMeatProbeCustomDataModel | |||||
+ (Byte)version { | |||||
return 0x02; | |||||
} | |||||
+ (Byte)modelSize { | |||||
return 128;//sizeof(ELMeatProbeCustomDataStruct); | |||||
} | |||||
+ (instancetype)modelWithData:(NSData *)data { | |||||
if (data.length != self.modelSize) { | |||||
NSLog(@"数据长度错误 data:%@", data); | |||||
return nil; | |||||
} | |||||
ELMeatProbeCustomDataModel *model = [[ELMeatProbeCustomDataModel alloc] initWithData:data]; | |||||
if (model.customStruct.ver != self.version) { | |||||
NSLog(@"数据版本错误 data:%@", data); | |||||
return nil; | |||||
} | |||||
return model; | |||||
} | |||||
- (instancetype)init { | |||||
if (self = [super init]) { | |||||
memset(&_customStruct, 0, sizeof(_customStruct)); | |||||
_customStruct.ver = self.class.version; | |||||
} | |||||
return self; | |||||
} | |||||
- (instancetype)initWithData:(NSData *)data { | |||||
if (self = [self init]) { | |||||
memcpy(&_customStruct, data.bytes, sizeof(_customStruct)); | |||||
} | |||||
return self; | |||||
} | |||||
- (NSData *)dataValue { | |||||
Byte bytes[128] = {0x00}; | |||||
memcpy(bytes, &_customStruct, sizeof(_customStruct)); | |||||
return [NSData dataWithBytes:bytes length:sizeof(bytes)]; | |||||
} | |||||
- (NSString *)remark { | |||||
char *remarkBytes[64] = {0}; | |||||
memcpy(remarkBytes, _customStruct.remarkBytes, sizeof(_customStruct.remarkBytes)); | |||||
NSString *str = [NSString stringWithUTF8String:(const char *)remarkBytes]; | |||||
return str; | |||||
} | |||||
- (NSString *)setRemark:(NSString *)remark { | |||||
NSData *data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
if (data.length > 32) { | |||||
while (data.length > 29) { | |||||
remark = [remark substringToIndex:(remark.length - 1)]; | |||||
data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
} | |||||
remark = [remark stringByAppendingString:@"..."]; | |||||
data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
} | |||||
Byte *bytes = (Byte *)data.bytes; | |||||
NSUInteger total = data.length > 32 ? 32 : data.length; | |||||
memset(_customStruct.remarkBytes, 0, 32); | |||||
memcpy(_customStruct.remarkBytes, bytes, total); | |||||
return [self remark]; | |||||
} | |||||
#pragma mark setter getter | |||||
- (NSInteger)ver { | |||||
return self.customStruct.ver; | |||||
} | |||||
- (NSInteger)cookingId { | |||||
return self.customStruct.cookingId; | |||||
} | |||||
- (NSInteger)foodType { | |||||
return self.customStruct.foodType; | |||||
} | |||||
- (NSInteger)foodRawness { | |||||
return self.customStruct.foodRawness; | |||||
} | |||||
- (double)alarmTemperaturePercent { | |||||
return self.customStruct.alarmTemperaturePercent; | |||||
} | |||||
- (NSInteger)alarmTemperature_C { | |||||
return self.customStruct.alarmTemperature_C; | |||||
} | |||||
- (NSInteger)alarmTemperature_F { | |||||
return self.customStruct.alarmTemperature_F; | |||||
} | |||||
- (void)setAlarmTemperaturePercent:(double)alarmTemperaturePercent { | |||||
_customStruct.alarmTemperaturePercent = alarmTemperaturePercent; | |||||
_customStruct.alarmTemperature_C = _customStruct.targetTemperature_C * alarmTemperaturePercent; | |||||
_customStruct.alarmTemperature_F = _customStruct.targetTemperature_F * alarmTemperaturePercent; | |||||
} | |||||
- (ELDeviceTemperatureUnit)currentUnit { | |||||
return self.customStruct.currentUnit; | |||||
} | |||||
#pragma mark ---- description | |||||
- (NSString *)description { | |||||
NSMutableString *desc = [NSStringFromClass([self class]) stringByAppendingString:@": {\n"].mutableCopy; | |||||
[desc appendString:[NSString stringWithFormat:@"ver: %@,\n", @(self.customStruct.ver)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"cookingId: %@,\n", @(self.customStruct.cookingId)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"foodType: %@,\n", @(self.customStruct.foodType)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"foodRawness: %@,\n", @(self.customStruct.foodRawness)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"targetTemperature_C: %@,\n", @(self.customStruct.targetTemperature_C)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"targetTemperature_F: %@,\n", @(self.customStruct.targetTemperature_F)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"ambientMinTemperature_C: %@,\n", @(self.customStruct.ambientMinTemperature_C)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"ambientMinTemperature_F: %@,\n", @(self.customStruct.ambientMinTemperature_F)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"ambientMaxTemperature_C: %@,\n", @(self.customStruct.ambientMaxTemperature_C)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"ambientMaxTemperature_F: %@,\n", @(self.customStruct.ambientMaxTemperature_F)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"alarmTemperaturePercent: %@,\n", @(self.alarmTemperaturePercent)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"timerStart: %@,\n", @(self.customStruct.timerStart)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"timerEnd: %@,\n", @(self.customStruct.timerEnd)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"alarmTemperature_C: %@,\n", @(self.customStruct.alarmTemperature_C)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"alarmTemperature_F: %@,\n", @(self.customStruct.alarmTemperature_F)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"currentUnit: %@,\n", @(self.customStruct.currentUnit)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"remark: %@,\n", self.remark]]; | |||||
[desc appendString:@"}"]; | |||||
return desc; | |||||
} | |||||
- (NSString *)debugDescription { | |||||
return [self description]; | |||||
} | |||||
@end |
// | |||||
// ELMeatProbeScreenBoxBleBBQParamModel.h | |||||
// AILinkComponentMeatProbe | |||||
// | |||||
// Created by Larry Zhang on 2024/2/26. | |||||
// | |||||
#import <Foundation/Foundation.h> | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
@interface ELMeatProbeScreenBoxBleBBQParamModel : NSObject | |||||
//生成时间 | |||||
@property (nonatomic, assign) NSTimeInterval timestamp; | |||||
@property (nonatomic, strong) NSData *macData; | |||||
@property (nonatomic, copy, readonly) NSString *macString; | |||||
@property (nonatomic, assign) UInt8 state; //State: 0x00:未开始,结束任务时,状态切为未开始,未开始状态时,不需要判定其他参数 0x01:已开始,开始任务时,状态切位已开始 | |||||
@property (nonatomic, assign) UInt8 foodType; //食物类型 | |||||
@property (nonatomic, assign) UInt16 targetTemperatureRaw_C; //食物目标温度:℃ | |||||
@property (nonatomic, assign, readonly) NSInteger targetTemperature_C; | |||||
@property (nonatomic, assign) UInt16 targetTemperatureRaw_F; //食物目标温度:℉ | |||||
@property (nonatomic, assign, readonly) NSInteger targetTemperature_F; | |||||
@property (nonatomic, assign) UInt16 ambientMinTemperatureRaw_C; //炉温目标下限:℃ | |||||
@property (nonatomic, assign, readonly) NSInteger ambientMinTemperature_C; | |||||
@property (nonatomic, assign) UInt16 ambientMinTemperatureRaw_F; //炉温目标下限:℉ | |||||
@property (nonatomic, assign, readonly) NSInteger ambientMinTemperature_F; | |||||
@property (nonatomic, assign) UInt16 ambientMaxTemperatureRaw_C; //炉温目标上限:℃ | |||||
@property (nonatomic, assign, readonly) NSInteger ambientMaxTemperature_C; | |||||
@property (nonatomic, assign) UInt16 ambientMaxTemperatureRaw_F; //炉温目标上限:℉ | |||||
@property (nonatomic, assign, readonly) NSInteger ambientMaxTemperature_F; | |||||
@property (nonatomic, assign) float alarmTemperaturePercent; //提醒温度对目标温度百分比 0~1.0 | |||||
@property (nonatomic, assign) UInt32 cookingId; //CookingID | |||||
@property (nonatomic, assign) UInt32 workTime; //任务已运行时间,单位s | |||||
@property (nonatomic, assign) UInt32 timerCount; //计时剩余时间(秒) | |||||
@property (nonatomic, assign) UInt8 foodRawness; //食物熟度 (maturityID) | |||||
@property (nonatomic, strong) NSData *remarkData; | |||||
- (void)clearAll; | |||||
- (void)cookDone; | |||||
- (NSData *)dataValue; | |||||
- (NSString *)remark; | |||||
- (NSString *)setRemark:(NSString *)remark; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// ELMeatProbeScreenBoxBleBBQParamModel.m | |||||
// AILinkComponentMeatProbe | |||||
// | |||||
// Created by Larry Zhang on 2024/2/26. | |||||
// | |||||
#import "ELMeatProbeScreenBoxBleBBQParamModel.h" | |||||
@implementation ELMeatProbeScreenBoxBleBBQParamModel | |||||
- (NSString *)macString { | |||||
if (self.macData == nil || self.macData.length != 6) { | |||||
return nil; | |||||
} | |||||
Byte *bytes = (Byte *)self.macData.bytes; | |||||
NSString *str = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]]; | |||||
return str; | |||||
} | |||||
- (NSInteger)targetTemperature_C { | |||||
NSInteger value = self.targetTemperatureRaw_C & 0x3FFF; | |||||
if (self.targetTemperatureRaw_C & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)targetTemperature_F { | |||||
NSInteger value = self.targetTemperatureRaw_F & 0x3FFF; | |||||
if (self.targetTemperatureRaw_F & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)ambientMinTemperature_C { | |||||
NSInteger value = self.ambientMinTemperatureRaw_C & 0x3FFF; | |||||
if (self.ambientMinTemperatureRaw_C & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)ambientMinTemperature_F { | |||||
NSInteger value = self.ambientMinTemperatureRaw_F & 0x3FFF; | |||||
if (self.ambientMinTemperatureRaw_F & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)ambientMaxTemperature_C { | |||||
NSInteger value = self.ambientMaxTemperatureRaw_C & 0x3FFF; | |||||
if (self.ambientMaxTemperatureRaw_C & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)ambientMaxTemperature_F { | |||||
NSInteger value = self.ambientMaxTemperatureRaw_F & 0x3FFF; | |||||
if (self.ambientMaxTemperatureRaw_F & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (void)clearAll { | |||||
self.state = 0; //State: 0x00:未开始,结束任务时,状态切为未开始,未开始状态时,不需要判定其他参数 0x01:已开始,开始任务时,状态切位已开始 | |||||
self.foodType = 0xFF; //食物类型 | |||||
self.targetTemperatureRaw_C = 0;//0xFFFF; //食物目标温度:℃// | |||||
self.targetTemperatureRaw_F = 0;//0xFFFF; //食物目标温度:℉// | |||||
self.ambientMaxTemperatureRaw_C = 0;//0xFFFF; //炉温目标上限:℃ | |||||
self.ambientMaxTemperatureRaw_F = 0;//0xFFFF; //炉温目标上限:℉ | |||||
self.ambientMinTemperatureRaw_C = 0;//0xFFFF; //炉温目标下限:℃ | |||||
self.ambientMinTemperatureRaw_F = 0;//0xFFFF; //炉温目标下限:℉ | |||||
self.cookingId = 0; //CookingID | |||||
self.workTime = 0; //任务已运行时间,单位s | |||||
self.timerCount = 0; //计时剩余时间(秒) | |||||
self.alarmTemperaturePercent = 0.95; //提醒温度对目标温度百分比 0~1.0 | |||||
self.foodRawness = 0xFF; //食物熟度 | |||||
Byte bytes[32] = {0}; | |||||
self.remarkData = [NSData dataWithBytes:bytes length:sizeof(bytes)]; | |||||
} | |||||
- (void)cookDone { | |||||
[self clearAll]; | |||||
} | |||||
- (NSData *)dataValue { | |||||
NSMutableData *data = [NSMutableData data]; | |||||
[data appendData:self.macData]; | |||||
UInt32 alarmTemperaturePercent = 0; | |||||
memcpy(&alarmTemperaturePercent, &(_alarmTemperaturePercent), sizeof(float)); | |||||
Byte bytes[] = { self.state, self.foodType, self.targetTemperatureRaw_C, self.targetTemperatureRaw_C >> 8, self.targetTemperatureRaw_F, self.targetTemperatureRaw_F >> 8, self.ambientMaxTemperatureRaw_C, self.ambientMaxTemperatureRaw_C >> 8, self.ambientMaxTemperatureRaw_F, self.ambientMaxTemperatureRaw_F >> 8, self.ambientMinTemperatureRaw_C, self.ambientMinTemperatureRaw_C >> 8, self.ambientMinTemperatureRaw_F, self.ambientMinTemperatureRaw_F >> 8, self.cookingId, self.cookingId >> 8, self.cookingId >> 16, self.cookingId >> 24, self.workTime, self.workTime >> 8, self.workTime >> 16, self.workTime >> 24, self.timerCount, self.timerCount >> 8, self.timerCount >> 16, self.timerCount >> 24, alarmTemperaturePercent, alarmTemperaturePercent >> 8, alarmTemperaturePercent >> 16, alarmTemperaturePercent >> 24, self.foodRawness }; | |||||
[data appendBytes:bytes length:sizeof(bytes)]; | |||||
[data appendData:self.remarkData]; | |||||
return data.copy; | |||||
} | |||||
- (NSString *)setRemark:(NSString *)remark { | |||||
NSData *data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
if (data.length > 32) { | |||||
while (data.length > 29) { | |||||
remark = [remark substringToIndex:(remark.length - 1)]; | |||||
data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
} | |||||
remark = [remark stringByAppendingString:@"..."]; | |||||
data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
} | |||||
Byte *bytes = (Byte *)data.bytes; | |||||
NSUInteger total = data.length > 32 ? 32 : data.length; | |||||
Byte remarkBytes[32] = {0}; | |||||
memset(remarkBytes, 0, 32); | |||||
memcpy(remarkBytes, bytes, total); | |||||
self.remarkData = [NSData dataWithBytes:remarkBytes length:sizeof(remarkBytes)]; | |||||
return [self remark]; | |||||
} | |||||
- (NSString *)remark { | |||||
Byte remarkBytes[64] = {0}; | |||||
[self.remarkData getBytes:remarkBytes length:self.remarkData.length]; | |||||
NSString *str = [NSString stringWithUTF8String:(const char *)remarkBytes]; | |||||
return str; | |||||
} | |||||
@end |
// | |||||
// ELMeatProbeScreenBoxBleCmdTool.h | |||||
// Pods | |||||
// | |||||
// Created by Larry Zhang on 2024/2/26. | |||||
// | |||||
#import <Foundation/Foundation.h> | |||||
#import "ELMeatProbeScreenBoxBleHeader.h" | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
@class ELAILinkBleManager; | |||||
@class ELMeatProbeScreenBoxStatusModel, ELMeatProbeScreenBoxProbeStatusModel, ELMeatProbeScreenBoxBleBBQParamModel; | |||||
@interface ELMeatProbeScreenBoxBleCmdTool : NSObject | |||||
//APP获取设备状态数据(Type:0x01) | |||||
+ (NSData *)requestStatus:(ELAILinkBleManager *)manager; | |||||
//切换单位 | |||||
+ (NSData *)switchUnit:(UInt8)unit manager:(ELAILinkBleManager *)manager; | |||||
//获取设置烧烤任务参数(Type:0x09) | |||||
+ (NSData *)requestParams:(ELAILinkBleManager *)manager; | |||||
+ (NSData *)setupParams:(NSArray <ELMeatProbeScreenBoxBleBBQParamModel *>*)params supportProbe:(UInt8)supportProbe manager:(ELAILinkBleManager *)manager; | |||||
+ (void)requestOTAStatusWithManager:(ELAILinkBleManager *)manager; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// ELMeatProbeScreenBoxBleCmdTool.m | |||||
// Pods | |||||
// | |||||
// Created by Larry Zhang on 2024/2/26. | |||||
// | |||||
#import "ELMeatProbeScreenBoxBleCmdTool.h" | |||||
#import <AILinkBleSDK/ELAILinkBleManager.h> | |||||
#import "ELMeatProbeScreenBoxBleBBQParamModel.h" | |||||
@implementation ELMeatProbeScreenBoxBleCmdTool | |||||
//APP获取设备基础信息 | |||||
+ (NSData *)requestStatus:(ELAILinkBleManager *)manager { | |||||
const Byte cmd = ELMeatProbeScreenBoxCMDAppGetStatus_Type01; | |||||
Byte payloadBytes[] = { cmd, 0x01 }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA7Payload:payloadData]; | |||||
return [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
} | |||||
//切换单位 | |||||
+ (NSData *)switchUnit:(UInt8)unit manager:(ELAILinkBleManager *)manager { | |||||
if (unit > 1) { return nil; } | |||||
const Byte cmd = ELMeatProbeScreenBoxCCMDAppSwitchUnit_Type03; | |||||
Byte payloadBytes[] = { cmd, unit }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA7Payload:payloadData]; | |||||
return [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
} | |||||
+ (NSData *)requestParams:(ELAILinkBleManager *)manager { | |||||
const Byte cmd = ELMeatProbeScreenBoxCMDSetInfo_Type09; | |||||
Byte payloadBytes[] = { cmd, 0x01 }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA7Payload:payloadData]; | |||||
return [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
} | |||||
+ (NSData *)setupParams:(NSArray <ELMeatProbeScreenBoxBleBBQParamModel *>*)params supportProbe:(UInt8)supportProbe manager:(ELAILinkBleManager *)manager { | |||||
const Byte cmd = ELMeatProbeScreenBoxCMDSetInfo_Type09; | |||||
Byte payloadBytes[] = { cmd, 0x00, supportProbe }; | |||||
NSMutableData *payloadData = [NSMutableData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
for (ELMeatProbeScreenBoxBleBBQParamModel *param in params) { | |||||
[payloadData appendData:param.dataValue]; | |||||
} | |||||
[manager sendA7Payload:payloadData.copy]; | |||||
return [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
} | |||||
+ (void)requestOTAStatusWithManager:(ELAILinkBleManager *)manager { | |||||
const Byte ELInetGetCmdTypeSpecialFunc = 0x49, op = 0x01; | |||||
Byte payloadBytes[16] = { ELInetGetCmdTypeSpecialFunc, op }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA6Payload:payloadData.copy]; | |||||
} | |||||
@end |
// | |||||
// ELMeatProbeScreenBoxBleHeader.h | |||||
// Pods | |||||
// | |||||
// Created by Larry Zhang on 2024/2/26. | |||||
// | |||||
#ifndef ELMeatProbeScreenBoxBleHeader_h | |||||
#define ELMeatProbeScreenBoxBleHeader_h | |||||
typedef NS_ENUM(UInt8, ELMeatProbeScreenBoxCMD) { | |||||
ELMeatProbeScreenBoxCMDAppGetStatus_Type01 = 0x01, //0x01:Type:APP 获取设备状态 | |||||
ELMeatProbeScreenBoxCMDMcuUploadStatus_Type02 = 0x02, //0x02:Type:设备上报设备数据 | |||||
ELMeatProbeScreenBoxCCMDAppSwitchUnit_Type03 = 0x03, //0x03:Type:切换单位 | |||||
ELMeatProbeScreenBoxCCMDAppSwitchUnitResponse_Type04 = 0x04, //0x04:Type:切换单位 response | |||||
ELMeatProbeScreenBoxCMDStartAlarmState_Type05 = 0x05, //0x05:Type:发起报警 | |||||
ELMeatProbeScreenBoxCMDStartAlarmStateResponse_Type06 = 0x06, //0x06:Type:发起报警 Response | |||||
ELMeatProbeScreenBoxCMDStoplAlarm_Type07 = 0x07, //0x07:Type:停止报警 | |||||
ELMeatProbeScreenBoxCMDStoplAlarmResponse_Type08 = 0x08, //0x08:Type:停止报警 Response | |||||
ELMeatProbeScreenBoxCMDSetInfo_Type09 = 0x09, //Type:0x09 设置烧烤任务参数 | |||||
ELMeatProbeScreenBoxCMDSetInfoResponse_Type0A = 0x0A, //Type:0x0A 设置烧烤任务参数 Response | |||||
}; | |||||
#endif /* ELMeatProbeScreenBoxBleHeader_h */ |
// | |||||
// ELMeatProbeScreenBoxBleParser.h | |||||
// Pods | |||||
// | |||||
// Created by Larry Zhang on 2024/2/26. | |||||
// | |||||
#import <Foundation/Foundation.h> | |||||
#import <AILinkBleSDK/ELSDKHeader.h> | |||||
#import "ELMeatProbeScreenBoxBleHeader.h" | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
@protocol ELMeatProbeScreenBoxBleParserDelegate; | |||||
@class ELMeatProbeScreenBoxStatusModel, ELMeatProbeScreenBoxProbeStatusModel, ELMeatProbeScreenBoxBleBBQParamModel; | |||||
@interface ELMeatProbeScreenBoxBleParser : NSObject | |||||
@property (nonatomic, copy) NSString *mac; | |||||
@property (nonatomic, assign) NSInteger deviceId; | |||||
@property (nonatomic, weak) id<ELMeatProbeScreenBoxBleParserDelegate> delegate; | |||||
- (void)parseA7Payload:(NSData *)payload; | |||||
@end | |||||
@protocol ELMeatProbeScreenBoxBleParserDelegate <NSObject> | |||||
@optional | |||||
//MCU 上报设备状态数据(Type:02) | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser boxStatus:(ELMeatProbeScreenBoxStatusModel *)boxStatus; | |||||
//切换单位(Type:04) | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser unit:(ELDeviceTemperatureUnit)unit; | |||||
//报警状态数据(Type:06)//state: bit0:食物目标温度到达时置1 | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser startAlarmWithState:(Byte)state macData:(NSData *)macData mac:(NSString *)mac; | |||||
//取消报警(Type:08) | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser stopAlarmWithMacData:(NSData *)macData mac:(NSString *)mac; | |||||
//烧烤任务参数(Type:0A)//Op:0x00:设置任务参数(设置时需要一个针一个针设定任务) 0x01:获取任务参数(返回所有的针任务,如果包长度超MTU时,会分包发) 0x02:结束烧烤任务 | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser option:(UInt8)option supportProbe:(UInt8)supportProbe params:(NSArray <ELMeatProbeScreenBoxBleBBQParamModel *>*)params; | |||||
@end | |||||
@interface ELMeatProbeScreenBoxStatusModel : NSObject | |||||
//设备状态数据协议版本:0x01 | |||||
@property (nonatomic, assign) UInt8 version; | |||||
//支持的探针数量 M | |||||
@property (nonatomic, assign) UInt8 probeMaxCount; | |||||
//当前连接的探针数量 N | |||||
@property (nonatomic, assign) UInt8 probeCount; | |||||
//充电盒电池状态 | |||||
@property (nonatomic, assign) UInt8 batteryStatus; | |||||
@property (nonatomic, assign) UInt8 batteryPercent; | |||||
//温度单位 | |||||
@property (nonatomic, assign) ELDeviceTemperatureUnit unit; | |||||
//生成时间 | |||||
@property (nonatomic, assign) NSTimeInterval timestamp; | |||||
@property (nonatomic, strong) NSArray <ELMeatProbeScreenBoxProbeStatusModel *>*probeStatusArray; | |||||
@end | |||||
@interface ELMeatProbeScreenBoxProbeStatusModel : NSObject | |||||
//探针编号(1-M) 无法确定可连 接探针的编号,上报 0xFF | |||||
@property (nonatomic, assign) UInt8 index; | |||||
//探针 mac 地址 | |||||
@property (nonatomic, strong) NSData *macData; | |||||
@property (nonatomic, copy, readonly) NSString *macString; | |||||
// | |||||
//食物温度 | |||||
@property (nonatomic, assign, readonly) NSInteger internalTemperature_C; | |||||
@property (nonatomic, assign, readonly) NSInteger internalTemperature_F; | |||||
@property (nonatomic, assign, readonly) ELDeviceTemperatureUnit internalTemperatureUnit; | |||||
@property (nonatomic, assign) UInt16 internalTemperatureRaw; | |||||
// | |||||
//环境温度 | |||||
@property (nonatomic, assign, readonly) NSInteger ambientTemperature_C; | |||||
@property (nonatomic, assign, readonly) NSInteger ambientTemperature_F; | |||||
@property (nonatomic, assign, readonly) ELDeviceTemperatureUnit ambientTemperatureUnit; | |||||
@property (nonatomic, assign) UInt16 ambientTemperatureRaw; | |||||
// | |||||
//探针电池状态 | |||||
@property (nonatomic, assign) UInt8 batteryStatus; | |||||
@property (nonatomic, assign) UInt8 batteryPercent; | |||||
@property (nonatomic, assign) UInt8 batteryRaw; | |||||
//探针插入食物状态 | |||||
@property (nonatomic, assign) UInt8 insertStatusRaw; | |||||
//探针连接状态 | |||||
@property (nonatomic, assign) UInt8 connectState; | |||||
//生成时间 | |||||
@property (nonatomic, assign) double timestamp; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// ELMeatProbeScreenBoxBleParser.m | |||||
// Pods | |||||
// | |||||
// Created by Larry Zhang on 2024/2/26. | |||||
// | |||||
#import "ELMeatProbeScreenBoxBleParser.h" | |||||
#import "ELMeatProbeScreenBoxBleBBQParamModel.h" | |||||
@interface ELMeatProbeScreenBoxBleParser() | |||||
@end | |||||
@implementation ELMeatProbeScreenBoxBleParser | |||||
- (void)parseA7Payload:(nonnull NSData *)payload { | |||||
NSLog(@"#### parseA7Payload payload:%@", payload.debugDescription); | |||||
Byte *bytes = (Byte *)payload.bytes; | |||||
Byte cmd = bytes[0]; | |||||
switch (cmd) { | |||||
case ELMeatProbeScreenBoxCMDMcuUploadStatus_Type02: | |||||
[self parseStatusData:payload]; | |||||
break; | |||||
case ELMeatProbeScreenBoxCCMDAppSwitchUnit_Type03: | |||||
{ | |||||
UInt8 unit = bytes[1]; | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeScreenBoxBleParser:unit:)]) { | |||||
[self.delegate meatProbeScreenBoxBleParser:self unit:unit]; | |||||
} | |||||
} | |||||
break; | |||||
// case ELMeatProbeScreenBoxCCMDAppSwitchUnitResponse_Type04: | |||||
// break; | |||||
case ELMeatProbeScreenBoxCMDStartAlarmState_Type05: { | |||||
Byte i = 1; | |||||
Byte macBytes[6] = { bytes[i+5], bytes[i+4], bytes[i+3], bytes[i+2], bytes[i+1], bytes[i] }; | |||||
NSData *macData = [NSData dataWithBytes:macBytes length:6]; | |||||
i += 6; | |||||
Byte state = bytes[i]; | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeScreenBoxBleParser:startAlarmWithState:macData:mac:)]) { | |||||
[self.delegate meatProbeScreenBoxBleParser:self startAlarmWithState:state macData:macData mac:[self macDataToString:macData]]; | |||||
} | |||||
} | |||||
break; | |||||
// case ELMeatProbeScreenBoxCMDStartAlarmStateResponse_Type06: | |||||
// break; | |||||
case ELMeatProbeScreenBoxCMDStoplAlarm_Type07: { | |||||
Byte i = 1; | |||||
Byte macBytes[6] = { bytes[i+5], bytes[i+4], bytes[i+3], bytes[i+2], bytes[i+1], bytes[i] }; | |||||
NSData *macData = [NSData dataWithBytes:macBytes length:6]; | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeScreenBoxBleParser:stopAlarmWithMacData:mac:)]) { | |||||
[self.delegate meatProbeScreenBoxBleParser:self stopAlarmWithMacData:macData mac:[self macDataToString:macData]]; | |||||
} | |||||
} | |||||
break; | |||||
// case ELMeatProbeScreenBoxCMDStoplAlarmResponse_Type08: | |||||
// break; | |||||
case ELMeatProbeScreenBoxCMDSetInfo_Type09: | |||||
case ELMeatProbeScreenBoxCMDSetInfoResponse_Type0A: { | |||||
[self parseSetInfoParamData:payload]; | |||||
} | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
- (NSString *)macDataToString:(NSData *)macData { | |||||
if (macData == nil || macData.length != 6) { | |||||
return nil; | |||||
} | |||||
Byte *bytes = (Byte *)macData.bytes; | |||||
NSString *str = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]]; | |||||
return str; | |||||
} | |||||
- (void)parseSetInfoParamData:(NSData *)payload { | |||||
NSLog(@"##### parseSetInfoParamData payload:%@", payload.debugDescription); | |||||
if (payload.length != 72) { | |||||
return; | |||||
} | |||||
Byte *bytes = (Byte *)payload.bytes; | |||||
Byte i = 1; | |||||
Byte option = bytes[i]; | |||||
i = 2; | |||||
Byte supportProbe = bytes[i]; | |||||
i = 3; | |||||
NSMutableArray *arr = [NSMutableArray array]; | |||||
while (i < payload.length) { | |||||
//探针 1 | |||||
ELMeatProbeScreenBoxBleBBQParamModel *param = [[ELMeatProbeScreenBoxBleBBQParamModel alloc] init]; | |||||
param.timestamp = [NSDate date].timeIntervalSince1970; | |||||
param.macData = [payload subdataWithRange:NSMakeRange(i, 6)]; | |||||
i += 6; | |||||
param.state = bytes[i]; | |||||
i += 1; | |||||
param.foodType = bytes[i];//if (param.foodType == 0xFF) param.foodType = 0xFE; | |||||
i += 1; | |||||
param.targetTemperatureRaw_C = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.targetTemperatureRaw_F = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.ambientMaxTemperatureRaw_C = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.ambientMaxTemperatureRaw_F = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.ambientMinTemperatureRaw_C = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.ambientMinTemperatureRaw_F = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.cookingId = (bytes[i] << 0) | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); | |||||
i += 4; | |||||
param.workTime = (bytes[i] << 0) | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); | |||||
i += 4; | |||||
param.timerCount = (bytes[i] << 0) | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); | |||||
i += 4; | |||||
UInt32 alarmTemperaturePercentU32 = (bytes[i] << 0) | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); | |||||
float alarmTemperaturePercent = 0; | |||||
memcpy(&alarmTemperaturePercent, &alarmTemperaturePercentU32, sizeof(UInt32)); | |||||
param.alarmTemperaturePercent = alarmTemperaturePercent; | |||||
i += 4; | |||||
param.foodRawness = bytes[i]; | |||||
i += 1; | |||||
param.remarkData = [payload subdataWithRange:NSMakeRange(i, 32)]; | |||||
i += 32; | |||||
if (param.state == 0) { | |||||
[param clearAll]; | |||||
} | |||||
[arr addObject:param]; | |||||
} | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeScreenBoxBleParser:option:supportProbe:params:)]) { | |||||
[self.delegate meatProbeScreenBoxBleParser:self option:option supportProbe:supportProbe params:arr.copy]; | |||||
} | |||||
} | |||||
- (void)parseStatusData:(NSData *)payload { | |||||
if (payload.length != 25) { | |||||
return; | |||||
} | |||||
Byte *bytes = (Byte *)payload.bytes; | |||||
ELMeatProbeScreenBoxStatusModel *boxStatus = [[ELMeatProbeScreenBoxStatusModel alloc] init]; | |||||
boxStatus.timestamp = [NSDate date].timeIntervalSince1970; | |||||
Byte i = 1; | |||||
boxStatus.version = bytes[i]; | |||||
i = 2; | |||||
boxStatus.probeMaxCount = bytes[i]; | |||||
i = 3; | |||||
boxStatus.probeCount = bytes[i]; | |||||
i = 4; | |||||
boxStatus.batteryStatus = bytes[i] >> 7; | |||||
boxStatus.batteryPercent = bytes[i] & 0x7F; | |||||
i = 5; | |||||
boxStatus.unit = bytes[i]; | |||||
i = 9; | |||||
NSMutableArray *arr = [NSMutableArray array]; | |||||
{ | |||||
ELMeatProbeScreenBoxProbeStatusModel *probeStatus = [[ELMeatProbeScreenBoxProbeStatusModel alloc] init]; | |||||
probeStatus.timestamp = boxStatus.timestamp; | |||||
probeStatus.index = bytes[i]; | |||||
i += 1; | |||||
NSData *macData = [payload subdataWithRange:NSMakeRange(i, 6)]; | |||||
probeStatus.macData = macData; | |||||
i += 6; | |||||
probeStatus.internalTemperatureRaw = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
probeStatus.ambientTemperatureRaw = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
// 凸(艹皿艹 ) //0x639F (25503) | |||||
if (probeStatus.ambientTemperatureRaw == 25503) { | |||||
probeStatus.ambientTemperatureRaw = 0xFFFF; | |||||
} | |||||
i += 2; | |||||
probeStatus.batteryStatus = bytes[i] >> 7; | |||||
probeStatus.batteryPercent = bytes[i] & 0x7F; | |||||
probeStatus.batteryRaw = bytes[i]; | |||||
i += 1; | |||||
probeStatus.insertStatusRaw = bytes[i]; | |||||
i += 1; | |||||
probeStatus.connectState = bytes[i]; | |||||
i += 3; | |||||
[arr addObject:probeStatus]; | |||||
} | |||||
boxStatus.probeStatusArray = arr.copy; | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeScreenBoxBleParser:boxStatus:)]) { | |||||
[self.delegate meatProbeScreenBoxBleParser:self boxStatus:boxStatus]; | |||||
} | |||||
} | |||||
@end | |||||
@implementation ELMeatProbeScreenBoxStatusModel | |||||
@end | |||||
@implementation ELMeatProbeScreenBoxProbeStatusModel | |||||
- (NSString *)macString { | |||||
if (self.macData == nil || self.macData.length != 6) { | |||||
return nil; | |||||
} | |||||
Byte *bytes = (Byte *)self.macData.bytes; | |||||
NSString *str = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]]; | |||||
return str; | |||||
} | |||||
- (NSInteger)internalTemperature_C { | |||||
if (self.internalTemperatureRaw == 0xFFFF) { | |||||
return 0xFFFF; | |||||
} | |||||
if (self.internalTemperatureUnit == ELDeviceTemperatureUnit_C) { | |||||
return self.internalTemperature; | |||||
} | |||||
return [self convertF2C:self.internalTemperature]; | |||||
} | |||||
- (NSInteger)internalTemperature_F { | |||||
if (self.internalTemperatureRaw == 0xFFFF) { | |||||
return 0xFFFF; | |||||
} | |||||
if (self.internalTemperatureUnit == ELDeviceTemperatureUnit_F) { | |||||
return self.internalTemperature; | |||||
} | |||||
return [self convertC2F:self.internalTemperature]; | |||||
} | |||||
- (NSInteger)internalTemperature { | |||||
NSInteger value = self.internalTemperatureRaw & 0x3FFF; | |||||
if (self.internalTemperatureRaw & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (ELDeviceTemperatureUnit)internalTemperatureUnit { | |||||
return self.internalTemperatureRaw >> 15; | |||||
} | |||||
- (NSInteger)ambientTemperature_C { | |||||
if (self.ambientTemperatureRaw == 0xFFFF) { | |||||
return 0xFFFF; | |||||
} | |||||
if (self.ambientTemperatureUnit == ELDeviceTemperatureUnit_C) { | |||||
return self.ambientTemperature; | |||||
} | |||||
return [self convertF2C:self.ambientTemperature]; | |||||
} | |||||
- (NSInteger)ambientTemperature_F { | |||||
if (self.ambientTemperatureRaw == 0xFFFF) { | |||||
return 0xFFFF; | |||||
} | |||||
if (self.ambientTemperatureUnit == ELDeviceTemperatureUnit_F) { | |||||
return self.ambientTemperature; | |||||
} | |||||
return [self convertC2F:self.ambientTemperature]; | |||||
} | |||||
- (NSInteger)ambientTemperature { | |||||
NSInteger value = self.ambientTemperatureRaw & 0x3FFF; | |||||
if (self.ambientTemperatureRaw & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (ELDeviceTemperatureUnit)ambientTemperatureUnit { | |||||
return self.ambientTemperatureRaw >> 15; | |||||
} | |||||
//温度换算 | |||||
- (float)convertF2C:(float)fahrenheit { | |||||
return round((fahrenheit - 32) / 1.8); | |||||
} | |||||
- (float)convertC2F:(float)celsius { | |||||
return round(celsius * 1.8 + 32); | |||||
} | |||||
@end |
// | |||||
// MeatProbeScreenBoxVC.h | |||||
// AILinkBleSDK_Example | |||||
// | |||||
// Created by LarryZhang on 2024/9/7. | |||||
// Copyright © 2024 zhengzida. All rights reserved. | |||||
// | |||||
#import <UIKit/UIKit.h> | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
@class ELAILinkPeripheral; | |||||
@interface MeatProbeScreenBoxVC : UIViewController | |||||
@property (nonatomic, strong) ELAILinkPeripheral *per; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// MeatProbeScreenBoxVC.m | |||||
// AILinkBleSDK_Example | |||||
// | |||||
// Created by LarryZhang on 2024/9/7. | |||||
// Copyright © 2024 zhengzida. All rights reserved. | |||||
// | |||||
#import "MeatProbeScreenBoxVC.h" | |||||
#import <AILinkBleSDK/ELAILinkBleManager.h> | |||||
#import <AILinkBleSDK/NSData+AILinkBle.h> | |||||
#import "ELMeatProbeScreenBoxBleCmdTool.h" | |||||
#import "ELMeatProbeScreenBoxBleParser.h" | |||||
#import "ELMeatProbeScreenBoxBleBBQParamModel.h" | |||||
@interface MeatProbeScreenBoxVC () <ELAILinkBleManagerDelegate, ELMeatProbeScreenBoxBleParserDelegate> | |||||
@property (weak, nonatomic) IBOutlet UILabel *bleStatusLabel; | |||||
@property (weak, nonatomic) IBOutlet UITextView *logTextView; | |||||
@property (nonatomic, strong) ELAILinkBleManager *bleManager; | |||||
@property (nonatomic, assign) NELBleManagerConnectState bleConnectState; | |||||
@property (nonatomic, strong) ELMeatProbeScreenBoxBleParser *bleParser; | |||||
@property (nonatomic, strong) ELMeatProbeScreenBoxStatusModel *boxStatus; | |||||
@property (nonatomic, strong) ELMeatProbeScreenBoxBleBBQParamModel *param; | |||||
@end | |||||
@implementation MeatProbeScreenBoxVC | |||||
- (void)viewDidLoad { | |||||
[super viewDidLoad]; | |||||
// Do any additional setup after loading the view from its nib. | |||||
[self initBle]; | |||||
} | |||||
- (void)dealloc { | |||||
[self deinitBle]; | |||||
} | |||||
#pragma mark - Action | |||||
- (IBAction)requestParamsAction:(id)sender { | |||||
NSData *payload = [ELMeatProbeScreenBoxBleCmdTool requestParams:self.bleManager]; | |||||
NSString *log = [NSString stringWithFormat:@"发: payload: %@", payload]; | |||||
[self addLog:log]; | |||||
} | |||||
- (IBAction)setupParamsAction:(id)sender { | |||||
if (self.param == nil) { | |||||
return; | |||||
} | |||||
ELMeatProbeScreenBoxBleBBQParamModel *param = self.param; | |||||
param.foodType = 1; | |||||
param.targetTemperatureRaw_C = 70; | |||||
param.targetTemperatureRaw_F = 212; | |||||
param.foodRawness = 1; | |||||
param.alarmTemperaturePercent = 0.95; | |||||
param.cookingId = [NSDate date].timeIntervalSince1970; | |||||
NSData *payload = [ELMeatProbeScreenBoxBleCmdTool setupParams:@[param] supportProbe:1 manager:self.bleManager]; | |||||
NSString *log = [NSString stringWithFormat:@"发: payload: %@", payload]; | |||||
[self addLog:log]; | |||||
} | |||||
- (IBAction)switchUnitAction:(id)sender { | |||||
if (self.boxStatus.unit == 1) { | |||||
NSData *payload = [ELMeatProbeScreenBoxBleCmdTool switchUnit:0 manager:self.bleManager]; | |||||
NSString *log = [NSString stringWithFormat:@"发: payload: %@ -- 切换单位 to ℃", payload]; | |||||
[self addLog:log]; | |||||
} else { | |||||
NSData *payload = [ELMeatProbeScreenBoxBleCmdTool switchUnit:1 manager:self.bleManager]; | |||||
NSString *log = [NSString stringWithFormat:@"发: payload: %@ -- 切换单位 to ℉", payload]; | |||||
[self addLog:log]; | |||||
} | |||||
} | |||||
- (IBAction)clearAction:(id)sender { | |||||
self.logTextView.text = @""; | |||||
} | |||||
- (IBAction)shareLogAction:(id)sender { | |||||
} | |||||
#pragma mark - ELAILinkBleManagerDelegate | |||||
- (void)initBle { | |||||
self.bleManager = [[ELAILinkBleManager alloc] init]; | |||||
self.bleManager.ailinkDelegate = self; | |||||
self.bleParser = [[ELMeatProbeScreenBoxBleParser alloc] init]; | |||||
self.bleParser.delegate = self; | |||||
self.bleParser.mac = self.per.macAddressString; | |||||
} | |||||
- (void)scanBle { | |||||
[self.bleManager scanFilterWithCidArray:@[@(self.per.cid)]]; | |||||
} | |||||
- (void)connect:(ELAILinkPeripheral *)peripheral { | |||||
[self.bleManager connectAILinkPeripheral:peripheral]; | |||||
[self updateBleStatusView:NELBleManagerConnectStateConnecting]; | |||||
} | |||||
- (void)deinitBle { | |||||
[self.bleManager stopScan]; | |||||
self.bleManager.ailinkDelegate = nil; | |||||
[self.bleManager disconnectPeripheral]; | |||||
} | |||||
- (void)updateBleStatusView:(NELBleManagerConnectState)state { | |||||
if (self.bleManager.central.state == CBManagerStatePoweredOff) { | |||||
self.bleStatusLabel.text = @"蓝牙关闭"; | |||||
[self addLog:self.bleStatusLabel.text]; | |||||
return; | |||||
} | |||||
switch (state) { | |||||
case NELBleManagerConnectStateDisconnected: | |||||
self.bleStatusLabel.text = @"断开连接"; | |||||
break; | |||||
case NELBleManagerConnectStateFailed: | |||||
case NELBleManagerConnectStateFailedValidation: | |||||
self.bleStatusLabel.text = @"连接失败"; | |||||
break; | |||||
case NELBleManagerConnectStateConnecting: | |||||
self.bleStatusLabel.text = @"正在连接..."; | |||||
break; | |||||
case NELBleManagerConnectStatePassed: | |||||
self.bleStatusLabel.text = @"连接成功"; | |||||
[self requestDeviceData]; | |||||
// read RSSI | |||||
// [self readRSSI]; | |||||
break; | |||||
case NELBleManagerConnectStateCentralScanning: | |||||
self.bleStatusLabel.text = @"正在扫描..."; | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
[self addLog:self.bleStatusLabel.text]; | |||||
} | |||||
- (void)requestDeviceData { | |||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0), dispatch_get_main_queue(), ^{ | |||||
}); | |||||
} | |||||
// 设备状态变更 | |||||
- (void)managerDidUpdateState:(CBCentralManager *)central { | |||||
NSLog(@"%s state:%@", __func__, @(central.state)); | |||||
if (central.state == CBManagerStatePoweredOn) { | |||||
[self scanBle]; | |||||
} else if (central.state == CBManagerStatePoweredOff) { | |||||
self.bleConnectState = NELBleManagerConnectStateCentralPowerOff; | |||||
[self updateBleStatusView:NELBleManagerConnectStateCentralPowerOff]; | |||||
} | |||||
} | |||||
- (void)managerScanState:(BOOL)scanning { | |||||
NSLog(@"%s scanning:%@", __func__, @(scanning)); | |||||
if (scanning) { | |||||
[self updateBleStatusView:NELBleManagerConnectStateCentralScanning]; | |||||
} | |||||
} | |||||
// 扫描到设备 | |||||
- (void)managerDidDiscoverPeripheral:(ELAILinkPeripheral *)peripheral { | |||||
NSLog(@"managerDidDiscoverPeripheral cid:%02x vid:%02x pid:%02x mac:%@", peripheral.cid, peripheral.vid, peripheral.pid, peripheral.macAddressString); | |||||
if ([peripheral.macAddressString isEqualToString:self.per.macAddressString]) { | |||||
[self.bleManager stopScan]; | |||||
[self connect:peripheral]; | |||||
} | |||||
} | |||||
- (void)managerDidUpdateConnect:(NELBleManagerConnectState)state { | |||||
NSLog(@"%s NELBleManagerConnectState:%@", __func__, @(state)); | |||||
[self updateBleStatusView:state]; | |||||
} | |||||
//A7数据 | |||||
- (void)aiLinkBleReceiveA7Data:(NSData *)payload { | |||||
NSLog(@"%s #### payload:%@", __func__, payload.elHexString); | |||||
NSString *log = [NSString stringWithFormat:@"收: payload: %@", payload.elHexString]; | |||||
[self addLog:log]; | |||||
[self.bleParser parseA7Payload:payload]; | |||||
} | |||||
//A6数据 | |||||
- (void)aiLinkBleReceiveA6Data:(NSData *)packet { | |||||
NSLog(@"%s ##### packet:%@", __func__, packet.elHexString); | |||||
Byte *bytes = (Byte *)packet.bytes; | |||||
Byte cmd = bytes[2]; | |||||
if (cmd == ELInetGetCmdTypeGetBMVersion) { | |||||
NSString *bmVersion = self.bleManager.bmVersion; | |||||
NSLog(@"##### bmVersion: %@", bmVersion); | |||||
} | |||||
if (cmd == ELInetGetCmdTypeGetBMVersionPro) { | |||||
NSString *bmVersionPro = self.bleManager.bmVersionPro; | |||||
NSLog(@"##### bmVersionPro: %@", bmVersionPro); | |||||
} | |||||
} | |||||
#pragma mark - ELMeatProbeScreenBoxBleParser | |||||
//MCU 上报设备状态数据(Type:02) | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser boxStatus:(ELMeatProbeScreenBoxStatusModel *)boxStatus { | |||||
NSLog(@"##### boxStatus(): %@ ", boxStatus.debugDescription); | |||||
self.boxStatus = boxStatus; | |||||
NSString *log = [NSString stringWithFormat:@"boxStatus: { mac:%@, probeMaxCount:%hhu, probeCount:%hhu, batteryStatus:%hhu batteryPercent:%hhu, unit:%ld }", parser.mac, boxStatus.probeMaxCount, boxStatus.probeCount, boxStatus.batteryStatus, boxStatus.batteryPercent, boxStatus.unit]; | |||||
[self addLog:log]; | |||||
ELMeatProbeScreenBoxProbeStatusModel *probeStatus = boxStatus.probeStatusArray.firstObject; | |||||
NSString *log2 = [NSString stringWithFormat:@"probeStatus: { connectState:%@ macString:%hhu, internalTemperature_C:%ld ℃, ambientTemperature_C:%ld ℃ batteryStatus:%hhu batteryPercent:%hhu }", probeStatus.macString, probeStatus.connectState, probeStatus.internalTemperature_C, probeStatus.ambientTemperature_C, probeStatus.batteryStatus, probeStatus.batteryPercent]; | |||||
[self addLog:log2]; | |||||
} | |||||
//切换单位(Type:04) | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser unit:(ELDeviceTemperatureUnit)unit { | |||||
NSLog(@"##### unit(): %@", @(unit)); | |||||
NSString *log = [NSString stringWithFormat:@"unit(): %@", unit == 0 ? @"℃" : @"°F"]; | |||||
[self addLog:log]; | |||||
} | |||||
//报警状态数据(Type:06)//state: bit0:食物目标温度到达时置1 | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser startAlarmWithState:(Byte)state macData:(NSData *)macData mac:(NSString *)mac { | |||||
NSLog(@"##### box:%@ startAlarmWithState(): probe:%@ state:%@", parser.mac, mac, @(state)); | |||||
NSString *log = [NSString stringWithFormat:@"box:%@ startAlarmWithState(): probe:%@ state:%@", parser.mac, mac, @(state)]; | |||||
[self addLog:log]; | |||||
} | |||||
//取消报警(Type:08) | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser stopAlarmWithMacData:(NSData *)macData mac:(NSString *)mac { | |||||
NSLog(@"##### box:%@ stopAlarmWithMacData(): probe:%@ ", parser.mac, mac); | |||||
NSString *log = [NSString stringWithFormat:@"box:%@ stopAlarmWithMacData(): probe:%@ ", parser.mac, mac]; | |||||
[self addLog:log]; | |||||
} | |||||
//烧烤任务参数(Type:0A)//Op:0x00:设置任务参数(设置时需要一个针一个针设定任务) 0x01:获取任务参数(返回所有的针任务,如果包长度超MTU时,会分包发) 0x02:结束烧烤任务 | |||||
- (void)meatProbeScreenBoxBleParser:(ELMeatProbeScreenBoxBleParser *)parser option:(UInt8)option supportProbe:(UInt8)supportProbe params:(NSArray <ELMeatProbeScreenBoxBleBBQParamModel *>*)params { | |||||
NSLog(@"##### box:%@ meatProbeScreenBoxBleParser(): option:%@ supportProbe:%@ ", parser.mac, @(option), @(supportProbe)); | |||||
ELMeatProbeScreenBoxBleBBQParamModel *param = params.firstObject; | |||||
NSLog(@"##### param:%@ state:%@ foodType:%@", param.macString, @(param.state), @(param.foodType)); | |||||
self.param = param; | |||||
NSString *log = [NSString stringWithFormat:@"box:%@ meatProbeScreenBoxBleParser(): option:%@ supportProbe:%@ ", parser.mac, @(option), @(supportProbe)]; | |||||
NSString *log2 = [NSString stringWithFormat:@"param:%@ state:%@ foodType:%@", param.macString, @(param.state), @(param.foodType)]; | |||||
[self addLog:log]; | |||||
[self addLog:log2]; | |||||
} | |||||
- (void)peripheralDidReadRSSI:(nonnull NSNumber *)RSSI { | |||||
NSLog(@"%s peripheralDidReadRSSI: %@", __FUNCTION__, RSSI); | |||||
// main thread | |||||
dispatch_async(dispatch_get_main_queue(), ^{ | |||||
[self addLog:[NSString stringWithFormat:@"peripheralDidReadRSSI: %@", RSSI]]; | |||||
}); | |||||
[self readRSSI]; | |||||
} | |||||
- (void)readRSSI { | |||||
// delay | |||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |||||
// Read RSSI | |||||
[self.bleManager readRSSI]; | |||||
}); | |||||
} | |||||
#pragma mark - addLog | |||||
- (void)addLog:(NSString *)log { | |||||
[self addLog:log newline:YES]; | |||||
} | |||||
- (void)addWithoutNewlineLog:(NSString *)log { | |||||
[self addLog:log newline:NO]; | |||||
} | |||||
- (void)addLog:(NSString *)log newline:(BOOL)newline { | |||||
NSDateFormatter *format = [[NSDateFormatter alloc] init]; | |||||
format.dateFormat = @"HH:mm:ss.SSS"; | |||||
NSString *time = [format stringFromDate:[NSDate date]]; | |||||
if (newline) { | |||||
self.logTextView.text = [self.logTextView.text stringByAppendingFormat:@"%@ %@\n", time, log]; | |||||
} else { | |||||
self.logTextView.text = [self.logTextView.text stringByAppendingFormat:@"%@ %@", time, log]; | |||||
} | |||||
[self.logTextView scrollRangeToVisible:NSMakeRange(self.logTextView.text.length, 1)]; | |||||
} | |||||
@end |
<?xml version="1.0" encoding="UTF-8"?> | |||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> | |||||
<device id="retina6_12" orientation="portrait" appearance="light"/> | |||||
<dependencies> | |||||
<deployment identifier="iOS"/> | |||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/> | |||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/> | |||||
<capability name="System colors in document resources" minToolsVersion="11.0"/> | |||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | |||||
</dependencies> | |||||
<objects> | |||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MeatProbeScreenBoxVC"> | |||||
<connections> | |||||
<outlet property="bleStatusLabel" destination="lTu-0Z-Tge" id="aaN-iq-CUB"/> | |||||
<outlet property="logTextView" destination="QAW-Ww-9FQ" id="jSk-nf-wNh"/> | |||||
<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="393" height="852"/> | |||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | |||||
<subviews> | |||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stauts" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="lTu-0Z-Tge"> | |||||
<rect key="frame" x="0.0" y="59" width="393" height="21"/> | |||||
<fontDescription key="fontDescription" type="system" pointSize="17"/> | |||||
<nil key="textColor"/> | |||||
<nil key="highlightedColor"/> | |||||
</label> | |||||
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="BL3-Qk-9Hg"> | |||||
<rect key="frame" x="8" y="380" width="377" height="438"/> | |||||
<subviews> | |||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" indicatorStyle="white" editable="NO" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="QAW-Ww-9FQ"> | |||||
<rect key="frame" x="0.0" y="0.0" width="377" height="438"/> | |||||
<color key="backgroundColor" systemColor="labelColor"/> | |||||
<color key="textColor" systemColor="opaqueSeparatorColor"/> | |||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="10"/> | |||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> | |||||
</textView> | |||||
</subviews> | |||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/> | |||||
<constraints> | |||||
<constraint firstAttribute="trailing" secondItem="QAW-Ww-9FQ" secondAttribute="trailing" id="18q-Eb-y4q"/> | |||||
<constraint firstItem="QAW-Ww-9FQ" firstAttribute="leading" secondItem="BL3-Qk-9Hg" secondAttribute="leading" id="APS-gg-hbg"/> | |||||
<constraint firstAttribute="bottom" secondItem="QAW-Ww-9FQ" secondAttribute="bottom" id="Dz9-Nx-gZg"/> | |||||
<constraint firstItem="QAW-Ww-9FQ" firstAttribute="top" secondItem="BL3-Qk-9Hg" secondAttribute="top" id="HfL-Mt-VYw"/> | |||||
</constraints> | |||||
<userDefinedRuntimeAttributes> | |||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> | |||||
<real key="value" value="8"/> | |||||
</userDefinedRuntimeAttribute> | |||||
</userDefinedRuntimeAttributes> | |||||
</view> | |||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Qs9-zC-31a"> | |||||
<rect key="frame" x="354" y="342" width="31" height="30"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="分享"/> | |||||
<connections> | |||||
<action selector="shareLogAction:" destination="-1" eventType="touchUpInside" id="O10-vI-2uq"/> | |||||
</connections> | |||||
</button> | |||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="9po-bu-c16"> | |||||
<rect key="frame" x="8" y="342" width="31" height="30"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="清空"/> | |||||
<connections> | |||||
<action selector="clearAction:" destination="-1" eventType="touchUpInside" id="MJ3-27-vjh"/> | |||||
</connections> | |||||
</button> | |||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Crb-qO-me7"> | |||||
<rect key="frame" x="16" y="96" width="128" height="35"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="Button"/> | |||||
<buttonConfiguration key="configuration" style="filled" title="请求烧烤参数"/> | |||||
<connections> | |||||
<action selector="requestParamsAction:" destination="-1" eventType="touchUpInside" id="ihu-lG-9Zg"/> | |||||
</connections> | |||||
</button> | |||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="bId-6O-Ndu"> | |||||
<rect key="frame" x="176" y="96" width="128" height="35"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="Button"/> | |||||
<buttonConfiguration key="configuration" style="filled" title="设置烧烤参数"/> | |||||
<connections> | |||||
<action selector="setupParamsAction:" destination="-1" eventType="touchUpInside" id="o7Z-30-SJV"/> | |||||
</connections> | |||||
</button> | |||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="Cgo-YJ-V1h"> | |||||
<rect key="frame" x="16" y="147" width="93.333333333333329" height="35"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="Button"/> | |||||
<buttonConfiguration key="configuration" style="filled" title="单位切换"/> | |||||
<connections> | |||||
<action selector="switchUnitAction:" destination="-1" eventType="touchUpInside" id="YRG-hs-YTh"/> | |||||
</connections> | |||||
</button> | |||||
</subviews> | |||||
<viewLayoutGuide key="safeArea" id="Q5M-cg-NOt"/> | |||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/> | |||||
<constraints> | |||||
<constraint firstItem="Q5M-cg-NOt" firstAttribute="bottom" secondItem="BL3-Qk-9Hg" secondAttribute="bottom" id="3vZ-eL-8ye"/> | |||||
<constraint firstItem="bId-6O-Ndu" firstAttribute="top" secondItem="Crb-qO-me7" secondAttribute="top" id="Adu-Nt-6GA"/> | |||||
<constraint firstItem="bId-6O-Ndu" firstAttribute="leading" secondItem="Crb-qO-me7" secondAttribute="trailing" constant="32" id="GgJ-IF-Lyh"/> | |||||
<constraint firstItem="Q5M-cg-NOt" firstAttribute="trailing" secondItem="BL3-Qk-9Hg" secondAttribute="trailing" constant="8" id="Hvr-Qw-Sfd"/> | |||||
<constraint firstItem="lTu-0Z-Tge" firstAttribute="top" secondItem="Q5M-cg-NOt" secondAttribute="top" id="J1z-u5-gvv"/> | |||||
<constraint firstItem="lTu-0Z-Tge" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" id="OLV-Lf-DKV"/> | |||||
<constraint firstItem="9po-bu-c16" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="8" id="QjW-lL-FtU"/> | |||||
<constraint firstItem="BL3-Qk-9Hg" firstAttribute="top" secondItem="9po-bu-c16" secondAttribute="bottom" constant="8" symbolic="YES" id="RtA-G5-d6U"/> | |||||
<constraint firstItem="BL3-Qk-9Hg" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="8" id="SNc-kd-Xyj"/> | |||||
<constraint firstItem="BL3-Qk-9Hg" firstAttribute="top" secondItem="lTu-0Z-Tge" secondAttribute="bottom" constant="300" id="SSt-fZ-CNI"/> | |||||
<constraint firstItem="lTu-0Z-Tge" firstAttribute="trailing" secondItem="Q5M-cg-NOt" secondAttribute="trailing" id="YG3-5g-z3J"/> | |||||
<constraint firstItem="Crb-qO-me7" firstAttribute="leading" secondItem="Q5M-cg-NOt" secondAttribute="leading" constant="16" id="a7S-pR-2xD"/> | |||||
<constraint firstItem="BL3-Qk-9Hg" firstAttribute="top" secondItem="Qs9-zC-31a" secondAttribute="bottom" constant="8" symbolic="YES" id="cR7-NU-eXL"/> | |||||
<constraint firstItem="Cgo-YJ-V1h" firstAttribute="leading" secondItem="Crb-qO-me7" secondAttribute="leading" id="hXk-fs-S6Y"/> | |||||
<constraint firstItem="Crb-qO-me7" firstAttribute="top" secondItem="lTu-0Z-Tge" secondAttribute="bottom" constant="16" id="kC5-sR-XD2"/> | |||||
<constraint firstItem="Q5M-cg-NOt" firstAttribute="trailing" secondItem="Qs9-zC-31a" secondAttribute="trailing" constant="8" id="oJa-9R-5R5"/> | |||||
<constraint firstItem="Cgo-YJ-V1h" firstAttribute="top" secondItem="Crb-qO-me7" secondAttribute="bottom" constant="16" id="vTs-18-bkM"/> | |||||
</constraints> | |||||
<point key="canvasLocation" x="139" y="21"/> | |||||
</view> | |||||
</objects> | |||||
<resources> | |||||
<systemColor name="labelColor"> | |||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | |||||
</systemColor> | |||||
<systemColor name="opaqueSeparatorColor"> | |||||
<color red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |||||
</systemColor> | |||||
<systemColor name="systemBackgroundColor"> | |||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | |||||
</systemColor> | |||||
</resources> | |||||
</document> |
// | |||||
// ELMeatProbeBoxMultipleBleBBQParamModel.h | |||||
// AILinkComponentMeatProbe | |||||
// | |||||
#import <Foundation/Foundation.h> | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
@interface ELMeatProbeBoxMultipleBleBBQParamModel : NSObject | |||||
//生成时间 | |||||
@property (nonatomic, assign) NSTimeInterval timestamp; | |||||
@property (nonatomic, strong) NSData *macData; | |||||
@property (nonatomic, copy, readonly) NSString *macString; | |||||
@property (nonatomic, assign) UInt8 state; //State: 0x00:未开始,结束任务时,状态切为未开始,未开始状态时,不需要判定其他参数 0x01:已开始,开始任务时,状态切位已开始 | |||||
@property (nonatomic, assign) UInt8 foodType; //食物类型 | |||||
@property (nonatomic, assign) UInt16 targetTemperatureRaw_C; //食物目标温度:℃ | |||||
@property (nonatomic, assign, readonly) NSInteger targetTemperature_C; | |||||
@property (nonatomic, assign) UInt16 targetTemperatureRaw_F; //食物目标温度:℉ | |||||
@property (nonatomic, assign, readonly) NSInteger targetTemperature_F; | |||||
@property (nonatomic, assign) UInt16 ambientMinTemperatureRaw_C; //炉温目标下限:℃ | |||||
@property (nonatomic, assign, readonly) NSInteger ambientMinTemperature_C; | |||||
@property (nonatomic, assign) UInt16 ambientMinTemperatureRaw_F; //炉温目标下限:℉ | |||||
@property (nonatomic, assign, readonly) NSInteger ambientMinTemperature_F; | |||||
@property (nonatomic, assign) UInt16 ambientMaxTemperatureRaw_C; //炉温目标上限:℃ | |||||
@property (nonatomic, assign, readonly) NSInteger ambientMaxTemperature_C; | |||||
@property (nonatomic, assign) UInt16 ambientMaxTemperatureRaw_F; //炉温目标上限:℉ | |||||
@property (nonatomic, assign, readonly) NSInteger ambientMaxTemperature_F; | |||||
@property (nonatomic, assign) float alarmTemperaturePercent; //提醒温度对目标温度百分比 0~1.0 | |||||
@property (nonatomic, assign) UInt32 cookingId; //CookingID | |||||
@property (nonatomic, assign) UInt32 workTime; //任务已运行时间,单位s | |||||
@property (nonatomic, assign) UInt32 timerCount; //计时剩余时间(秒) | |||||
@property (nonatomic, assign) UInt8 foodRawness; //食物熟度 (maturityID) | |||||
@property (nonatomic, strong) NSData *remarkData; | |||||
- (void)clearAll; | |||||
- (void)cookDone; | |||||
- (NSData *)dataValue; | |||||
- (NSString *)remark; | |||||
- (NSString *)setRemark:(NSString *)remark; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// ELMeatProbeBoxMultipleBleBBQParamModel.m | |||||
// AILinkComponentMeatProbe | |||||
// | |||||
#import "ELMeatProbeBoxMultipleBleBBQParamModel.h" | |||||
@implementation ELMeatProbeBoxMultipleBleBBQParamModel | |||||
- (NSString *)macString { | |||||
if (self.macData == nil || self.macData.length != 6) { | |||||
return nil; | |||||
} | |||||
Byte *bytes = (Byte *)self.macData.bytes; | |||||
NSString *str = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]]; | |||||
return str; | |||||
} | |||||
- (NSInteger)targetTemperature_C { | |||||
NSInteger value = self.targetTemperatureRaw_C & 0x3FFF; | |||||
if (self.targetTemperatureRaw_C & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)targetTemperature_F { | |||||
NSInteger value = self.targetTemperatureRaw_F & 0x3FFF; | |||||
if (self.targetTemperatureRaw_F & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)ambientMinTemperature_C { | |||||
NSInteger value = self.ambientMinTemperatureRaw_C & 0x3FFF; | |||||
if (self.ambientMinTemperatureRaw_C & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)ambientMinTemperature_F { | |||||
NSInteger value = self.ambientMinTemperatureRaw_F & 0x3FFF; | |||||
if (self.ambientMinTemperatureRaw_F & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)ambientMaxTemperature_C { | |||||
NSInteger value = self.ambientMaxTemperatureRaw_C & 0x3FFF; | |||||
if (self.ambientMaxTemperatureRaw_C & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (NSInteger)ambientMaxTemperature_F { | |||||
NSInteger value = self.ambientMaxTemperatureRaw_F & 0x3FFF; | |||||
if (self.ambientMaxTemperatureRaw_F & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (void)clearAll { | |||||
self.state = 0; //State: 0x00:未开始,结束任务时,状态切为未开始,未开始状态时,不需要判定其他参数 0x01:已开始,开始任务时,状态切位已开始 | |||||
self.foodType = 0xFF; //食物类型 | |||||
self.targetTemperatureRaw_C = 0;//0xFFFF; //食物目标温度:℃// | |||||
self.targetTemperatureRaw_F = 0;//0xFFFF; //食物目标温度:℉// | |||||
self.ambientMaxTemperatureRaw_C = 0;//0xFFFF; //炉温目标上限:℃ | |||||
self.ambientMaxTemperatureRaw_F = 0;//0xFFFF; //炉温目标上限:℉ | |||||
self.ambientMinTemperatureRaw_C = 0;//0xFFFF; //炉温目标下限:℃ | |||||
self.ambientMinTemperatureRaw_F = 0;//0xFFFF; //炉温目标下限:℉ | |||||
self.cookingId = 0; //CookingID | |||||
self.workTime = 0; //任务已运行时间,单位s | |||||
self.timerCount = 0; //计时剩余时间(秒) | |||||
self.alarmTemperaturePercent = 0.95; //提醒温度对目标温度百分比 0~1.0 | |||||
self.foodRawness = 0xFF; //食物熟度 | |||||
Byte bytes[32] = {0}; | |||||
self.remarkData = [NSData dataWithBytes:bytes length:sizeof(bytes)]; | |||||
} | |||||
- (void)cookDone { | |||||
[self clearAll]; | |||||
} | |||||
- (NSData *)dataValue { | |||||
NSMutableData *data = [NSMutableData data]; | |||||
[data appendData:self.macData]; | |||||
UInt32 alarmTemperaturePercent = 0; | |||||
memcpy(&alarmTemperaturePercent, &(_alarmTemperaturePercent), sizeof(float)); | |||||
Byte bytes[] = { self.state, self.foodType, self.targetTemperatureRaw_C, self.targetTemperatureRaw_C >> 8, self.targetTemperatureRaw_F, self.targetTemperatureRaw_F >> 8, self.ambientMaxTemperatureRaw_C, self.ambientMaxTemperatureRaw_C >> 8, self.ambientMaxTemperatureRaw_F, self.ambientMaxTemperatureRaw_F >> 8, self.ambientMinTemperatureRaw_C, self.ambientMinTemperatureRaw_C >> 8, self.ambientMinTemperatureRaw_F, self.ambientMinTemperatureRaw_F >> 8, self.cookingId, self.cookingId >> 8, self.cookingId >> 16, self.cookingId >> 24, self.workTime, self.workTime >> 8, self.workTime >> 16, self.workTime >> 24, self.timerCount, self.timerCount >> 8, self.timerCount >> 16, self.timerCount >> 24, alarmTemperaturePercent, alarmTemperaturePercent >> 8, alarmTemperaturePercent >> 16, alarmTemperaturePercent >> 24, self.foodRawness }; | |||||
[data appendBytes:bytes length:sizeof(bytes)]; | |||||
[data appendData:self.remarkData]; | |||||
return data.copy; | |||||
} | |||||
- (NSString *)setRemark:(NSString *)remark { | |||||
NSData *data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
if (data.length > 32) { | |||||
while (data.length > 29) { | |||||
remark = [remark substringToIndex:(remark.length - 1)]; | |||||
data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
} | |||||
remark = [remark stringByAppendingString:@"..."]; | |||||
data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
} | |||||
Byte *bytes = (Byte *)data.bytes; | |||||
NSUInteger total = data.length > 32 ? 32 : data.length; | |||||
Byte remarkBytes[32] = {0}; | |||||
memset(remarkBytes, 0, 32); | |||||
memcpy(remarkBytes, bytes, total); | |||||
self.remarkData = [NSData dataWithBytes:remarkBytes length:sizeof(remarkBytes)]; | |||||
return [self remark]; | |||||
} | |||||
- (NSString *)remark { | |||||
Byte remarkBytes[64] = {0}; | |||||
[self.remarkData getBytes:remarkBytes length:self.remarkData.length]; | |||||
NSString *str = [NSString stringWithUTF8String:(const char *)remarkBytes]; | |||||
return str; | |||||
} | |||||
@end |
// | |||||
// ELMeatProbeBoxMultipleBleCmdTool.h | |||||
// Pods | |||||
// | |||||
#import <Foundation/Foundation.h> | |||||
#import "ELMeatProbeBoxMultipleBleHeader.h" | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
@class ELAILinkBleManager; | |||||
@class ELMeatProbeBoxMultipleStatusModel, ELMeatProbeBoxMultipleProbeStatusModel, ELMeatProbeBoxMultipleBleBBQParamModel; | |||||
@interface ELMeatProbeBoxMultipleBleCmdTool : NSObject | |||||
//APP获取设备状态数据(Type:0x01) | |||||
+ (NSData *)requestStatus:(ELAILinkBleManager *)manager; | |||||
//切换单位 | |||||
+ (NSData *)switchUnit:(UInt8)unit manager:(ELAILinkBleManager *)manager; | |||||
//获取设置烧烤任务参数(Type:0x09) | |||||
+ (NSData *)requestParams:(ELAILinkBleManager *)manager; | |||||
+ (NSData *)setupParam:(ELMeatProbeBoxMultipleBleBBQParamModel *)param supportProbe:(UInt8)supportProbe manager:(ELAILinkBleManager *)manager; | |||||
+ (void)requestIColornfoWithManager:(ELAILinkBleManager *)manager; | |||||
+ (void)requestOTAStatusWithManager:(ELAILinkBleManager *)manager; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// ELMeatProbeBoxMultipleBleCmdTool.m | |||||
// Pods | |||||
// | |||||
#import "ELMeatProbeBoxMultipleBleCmdTool.h" | |||||
#import <AILinkBleSDK/ELAILinkBleManager.h> | |||||
#import "ELMeatProbeBoxMultipleBleBBQParamModel.h" | |||||
@implementation ELMeatProbeBoxMultipleBleCmdTool | |||||
//APP获取设备基础信息 | |||||
+ (NSData *)requestStatus:(ELAILinkBleManager *)manager { | |||||
const Byte cmd = ELMeatProbeBoxMultipleCMDAppGetStatus_Type01; | |||||
Byte payloadBytes[] = { cmd, 0x01 }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA7Payload:payloadData]; | |||||
return [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
} | |||||
//切换单位 | |||||
+ (NSData *)switchUnit:(UInt8)unit manager:(ELAILinkBleManager *)manager { | |||||
if (unit > 1) { return nil; } | |||||
const Byte cmd = ELMeatProbeBoxMultipleCCMDAppSwitchUnit_Type03; | |||||
Byte payloadBytes[] = { cmd, unit }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA7Payload:payloadData]; | |||||
return [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
} | |||||
+ (NSData *)requestParams:(ELAILinkBleManager *)manager { | |||||
const Byte cmd = ELMeatProbeBoxMultipleCMDSetInfo_Type09; | |||||
Byte payloadBytes[] = { cmd, 0x01 }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA7Payload:payloadData]; | |||||
return [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
} | |||||
+ (NSData *)setupParam:(ELMeatProbeBoxMultipleBleBBQParamModel *)param supportProbe:(UInt8)supportProbe manager:(ELAILinkBleManager *)manager { | |||||
const Byte cmd = ELMeatProbeBoxMultipleCMDSetInfo_Type09; | |||||
Byte payloadBytes[] = { cmd, 0x00, supportProbe }; | |||||
NSMutableData *payloadData = [NSMutableData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[payloadData appendData:param.dataValue]; | |||||
[manager sendA7Payload:payloadData.copy]; | |||||
return [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
} | |||||
+ (void)requestIColornfoWithManager:(ELAILinkBleManager *)manager { | |||||
const Byte read = 0x00; | |||||
Byte payloadBytes[] = { ELMeatProbeBoxMultipleCMDColorInfoRequest_Type0B, read }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA7Payload:payloadData.copy]; | |||||
} | |||||
+ (void)requestOTAStatusWithManager:(ELAILinkBleManager *)manager { | |||||
const Byte ELInetGetCmdTypeSpecialFunc = 0x49, op = 0x01; | |||||
Byte payloadBytes[16] = { ELInetGetCmdTypeSpecialFunc, op }; | |||||
NSData *payloadData = [NSData dataWithBytes:payloadBytes length:sizeof(payloadBytes)]; | |||||
[manager sendA6Payload:payloadData.copy]; | |||||
} | |||||
@end |
// | |||||
// ELMeatProbeBoxMultipleBleHeader.h | |||||
// Pods | |||||
// | |||||
#ifndef ELMeatProbeBoxMultipleBleHeader_h | |||||
#define ELMeatProbeBoxMultipleBleHeader_h | |||||
typedef NS_ENUM(UInt8, ELMeatProbeBoxMultipleCMD) { | |||||
ELMeatProbeBoxMultipleCMDAppGetStatus_Type01 = 0x01, //0x01:Type:APP 获取设备状态 | |||||
ELMeatProbeBoxMultipleCMDMcuUploadStatus_Type02 = 0x02, //0x02:Type:设备上报设备数据 | |||||
ELMeatProbeBoxMultipleCCMDAppSwitchUnit_Type03 = 0x03, //0x03:Type:切换单位 | |||||
ELMeatProbeBoxMultipleCCMDAppSwitchUnitResponse_Type04 = 0x04, //0x04:Type:切换单位 response | |||||
ELMeatProbeBoxMultipleCMDStartAlarmState_Type05 = 0x05, //0x05:Type:发起报警 | |||||
ELMeatProbeBoxMultipleCMDStartAlarmStateResponse_Type06 = 0x06, //0x06:Type:发起报警 Response | |||||
ELMeatProbeBoxMultipleCMDStoplAlarm_Type07 = 0x07, //0x07:Type:停止报警 | |||||
ELMeatProbeBoxMultipleCMDStoplAlarmResponse_Type08 = 0x08, //0x08:Type:停止报警 Response | |||||
ELMeatProbeBoxMultipleCMDSetInfo_Type09 = 0x09, //Type:0x09 设置烧烤任务参数 | |||||
ELMeatProbeBoxMultipleCMDSetInfoResponse_Type0A = 0x0A, //Type:0x0A 设置烧烤任务参数 Response | |||||
ELMeatProbeBoxMultipleCMDColorInfoRequest_Type0B = 0x0B, | |||||
ELMeatProbeBoxMultipleCMDColorInfoResponse_Type0C = 0x0C, | |||||
}; | |||||
#endif /* ELMeatProbeBoxMultipleBleHeader_h */ |
// | |||||
// ELMeatProbeBoxMultipleBleParser.h | |||||
// Pods | |||||
// | |||||
#import <Foundation/Foundation.h> | |||||
#import <AILinkBleSDK/ELSDKHeader.h> | |||||
#import "ELMeatProbeBoxMultipleBleHeader.h" | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
@protocol ELMeatProbeBoxMultipleBleParserDelegate; | |||||
@class ELMeatProbeBoxMultipleStatusModel, ELMeatProbeBoxMultipleProbeStatusModel, ELMeatProbeBoxMultipleBleBBQParamModel, ELMeatProbeBoxMultipleColorInfoModel; | |||||
@interface ELMeatProbeBoxMultipleBleParser : NSObject | |||||
@property (nonatomic, copy) NSString *mac; | |||||
@property (nonatomic, assign) NSInteger deviceId; | |||||
@property (nonatomic, weak) id<ELMeatProbeBoxMultipleBleParserDelegate> delegate; | |||||
- (void)parseA7Payload:(NSData *)payload; | |||||
@end | |||||
@protocol ELMeatProbeBoxMultipleBleParserDelegate <NSObject> | |||||
@optional | |||||
//MCU 上报设备状态数据(Type:02) | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser boxStatus:(ELMeatProbeBoxMultipleStatusModel *)boxStatus; | |||||
//切换单位(Type:04) | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser unit:(ELDeviceTemperatureUnit)unit; | |||||
//报警状态数据(Type:06)//state: bit0:食物目标温度到达时置1 | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser startAlarmWithState:(Byte)state macData:(NSData *)macData mac:(NSString *)mac; | |||||
//取消报警(Type:08) | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser stopAlarmWithMacData:(NSData *)macData mac:(NSString *)mac; | |||||
//烧烤任务参数(Type:0A)//Op:0x00:设置任务参数(设置时需要一个针一个针设定任务) 0x01:获取任务参数(返回所有的针任务,如果包长度超MTU时,会分包发) 0x02:结束烧烤任务 | |||||
//- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser option:(UInt8)option supportProbe:(UInt8)supportProbe params:(NSArray <ELMeatProbeBoxMultipleBleBBQParamModel *>*)params; | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser option:(UInt8)option supportProbe:(UInt8)supportProbe param:(ELMeatProbeBoxMultipleBleBBQParamModel *)param; | |||||
//color info | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser colorInfos:(NSArray<ELMeatProbeBoxMultipleColorInfoModel *> *)colorInfos; | |||||
@end | |||||
@interface ELMeatProbeBoxMultipleStatusModel : NSObject | |||||
//设备状态数据协议版本:0x01 | |||||
@property (nonatomic, assign) UInt8 version; | |||||
//支持的探针数量 M | |||||
@property (nonatomic, assign) UInt8 probeMaxCount; | |||||
//当前连接的探针数量 N | |||||
@property (nonatomic, assign) UInt8 probeCount; | |||||
//充电盒电池状态 | |||||
@property (nonatomic, assign) UInt8 batteryStatus; | |||||
@property (nonatomic, assign) UInt8 batteryPercent; | |||||
//温度单位 | |||||
@property (nonatomic, assign) ELDeviceTemperatureUnit unit; | |||||
//生成时间 | |||||
@property (nonatomic, assign) NSTimeInterval timestamp; | |||||
@property (nonatomic, strong) NSArray <ELMeatProbeBoxMultipleProbeStatusModel *>*probeStatusArray; | |||||
//盒子 mac 地址 | |||||
@property (nonatomic, copy) NSString *boxMacString; | |||||
@end | |||||
@interface ELMeatProbeBoxMultipleProbeStatusModel : NSObject | |||||
//探针编号(1-M) 无法确定可连 接探针的编号,上报 0xFF | |||||
@property (nonatomic, assign) UInt8 index; | |||||
//探针 mac 地址 | |||||
@property (nonatomic, strong) NSData *macData; | |||||
@property (nonatomic, copy, readonly) NSString *macString; | |||||
// | |||||
//食物温度 | |||||
@property (nonatomic, assign, readonly) NSInteger internalTemperature_C; | |||||
@property (nonatomic, assign, readonly) NSInteger internalTemperature_F; | |||||
//@property (nonatomic, assign, readonly) NSInteger internalTemperature; | |||||
@property (nonatomic, assign, readonly) ELDeviceTemperatureUnit internalTemperatureUnit; | |||||
@property (nonatomic, assign) UInt16 internalTemperatureRaw; | |||||
// | |||||
//环境温度 | |||||
@property (nonatomic, assign, readonly) NSInteger ambientTemperature_C; | |||||
@property (nonatomic, assign, readonly) NSInteger ambientTemperature_F; | |||||
//@property (nonatomic, assign, readonly) NSInteger ambientTemperature; | |||||
@property (nonatomic, assign, readonly) ELDeviceTemperatureUnit ambientTemperatureUnit; | |||||
@property (nonatomic, assign) UInt16 ambientTemperatureRaw; | |||||
// | |||||
//探针电池状态 | |||||
@property (nonatomic, assign) UInt8 batteryStatus; | |||||
@property (nonatomic, assign) UInt8 batteryPercent; | |||||
@property (nonatomic, assign) UInt8 batteryRaw; | |||||
//探针插入食物状态 | |||||
@property (nonatomic, assign) UInt8 insertStatusRaw; | |||||
//探针连接状态 | |||||
@property (nonatomic, assign) UInt8 connectState; | |||||
//生成时间 | |||||
@property (nonatomic, assign) double timestamp; | |||||
@end | |||||
@interface ELMeatProbeBoxMultipleColorInfoModel : NSObject | |||||
@property (nonatomic, assign) UInt8 probeIndex; | |||||
@property (nonatomic, assign) UInt8 colorIndex; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// ELMeatProbeBoxMultipleBleParser.m | |||||
// Pods | |||||
// | |||||
#import "ELMeatProbeBoxMultipleBleParser.h" | |||||
#import "ELMeatProbeBoxMultipleBleBBQParamModel.h" | |||||
@interface ELMeatProbeBoxMultipleBleParser() | |||||
//@property (nonatomic, strong) ELMeatProbeBoxMultipleStatusModel *boxStatus; | |||||
@end | |||||
@implementation ELMeatProbeBoxMultipleBleParser | |||||
- (void)parseA7Payload:(nonnull NSData *)payload { | |||||
NSLog(@"#### parseA7Payload payload:%@", payload.debugDescription); | |||||
Byte *bytes = (Byte *)payload.bytes; | |||||
Byte cmd = bytes[0]; | |||||
switch (cmd) { | |||||
case ELMeatProbeBoxMultipleCMDMcuUploadStatus_Type02: | |||||
[self parseStatusData:payload]; | |||||
break; | |||||
case ELMeatProbeBoxMultipleCCMDAppSwitchUnit_Type03: | |||||
{ | |||||
UInt8 unit = bytes[1]; | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeBoxMultipleBleParser:unit:)]) { | |||||
[self.delegate meatProbeBoxMultipleBleParser:self unit:unit]; | |||||
} | |||||
} | |||||
break; | |||||
// case ELMeatProbeBoxMultipleCCMDAppSwitchUnitResponse_Type04: | |||||
// break; | |||||
case ELMeatProbeBoxMultipleCMDStartAlarmState_Type05: { | |||||
Byte i = 1; | |||||
NSData *macData = [payload subdataWithRange:NSMakeRange(i, 6)]; | |||||
i += 6; | |||||
Byte state = bytes[i]; | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeBoxMultipleBleParser:startAlarmWithState:macData:mac:)]) { | |||||
[self.delegate meatProbeBoxMultipleBleParser:self startAlarmWithState:state macData:macData mac:[self macDataToString:macData]]; | |||||
} | |||||
} | |||||
break; | |||||
// case ELMeatProbeBoxMultipleCMDStartAlarmStateResponse_Type06: | |||||
// break; | |||||
case ELMeatProbeBoxMultipleCMDStoplAlarm_Type07: { | |||||
Byte i = 1; | |||||
NSData *macData = [payload subdataWithRange:NSMakeRange(i, 6)]; | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeBoxMultipleBleParser:stopAlarmWithMacData:mac:)]) { | |||||
[self.delegate meatProbeBoxMultipleBleParser:self stopAlarmWithMacData:macData mac:[self macDataToString:macData]]; | |||||
} | |||||
} | |||||
break; | |||||
// case ELMeatProbeBoxMultipleCMDStoplAlarmResponse_Type08: | |||||
// break; | |||||
case ELMeatProbeBoxMultipleCMDSetInfo_Type09: | |||||
case ELMeatProbeBoxMultipleCMDSetInfoResponse_Type0A: { | |||||
[self parseSetInfoParamData:payload]; | |||||
} | |||||
break; | |||||
case ELMeatProbeBoxMultipleCMDColorInfoResponse_Type0C: { | |||||
NSMutableArray *arr = [NSMutableArray array]; | |||||
if (payload.length < 4) break; | |||||
for (int i=2; i<payload.length; i+=2) { | |||||
UInt8 probeIndex = bytes[i]; | |||||
UInt8 colorIndex = bytes[i+1]; | |||||
ELMeatProbeBoxMultipleColorInfoModel *color = [[ELMeatProbeBoxMultipleColorInfoModel alloc] init]; | |||||
color.probeIndex = probeIndex; | |||||
color.colorIndex = colorIndex; | |||||
[arr addObject:color]; | |||||
} | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeBoxMultipleBleParser:colorInfos:)]) { | |||||
[self.delegate meatProbeBoxMultipleBleParser:self colorInfos:arr.copy]; | |||||
} | |||||
} | |||||
default: | |||||
break; | |||||
} | |||||
} | |||||
- (NSString *)macDataToString:(NSData *)macData { | |||||
if (macData == nil || macData.length != 6) { | |||||
return nil; | |||||
} | |||||
Byte *bytes = (Byte *)macData.bytes; | |||||
NSString *str = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]]; | |||||
return str; | |||||
} | |||||
- (void)parseSetInfoParamData:(NSData *)payload { | |||||
NSLog(@"##### parseSetInfoParamData payload:%@", payload.debugDescription); | |||||
if (payload.length != 72 && payload.length != 140) { | |||||
return; | |||||
} | |||||
Byte *bytes = (Byte *)payload.bytes; | |||||
Byte i = 1; | |||||
Byte option = bytes[i]; | |||||
i = 2; | |||||
Byte supportProbe = bytes[i]; | |||||
i = 3; | |||||
// NSMutableArray *arr = [NSMutableArray array]; | |||||
// | |||||
// while (i < payload.length) { | |||||
//探针 1 | |||||
ELMeatProbeBoxMultipleBleBBQParamModel *param = [[ELMeatProbeBoxMultipleBleBBQParamModel alloc] init]; | |||||
param.timestamp = [NSDate date].timeIntervalSince1970; | |||||
param.macData = [payload subdataWithRange:NSMakeRange(i, 6)]; | |||||
i += 6; | |||||
param.state = bytes[i]; | |||||
i += 1; | |||||
param.foodType = bytes[i];//if (param.foodType == 0xFF) param.foodType = 0xFE; | |||||
i += 1; | |||||
param.targetTemperatureRaw_C = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.targetTemperatureRaw_F = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.ambientMaxTemperatureRaw_C = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.ambientMaxTemperatureRaw_F = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.ambientMinTemperatureRaw_C = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.ambientMinTemperatureRaw_F = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
i += 2; | |||||
param.cookingId = (bytes[i] << 0) | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); | |||||
i += 4; | |||||
param.workTime = (bytes[i] << 0) | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); | |||||
i += 4; | |||||
param.timerCount = (bytes[i] << 0) | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); | |||||
i += 4; | |||||
UInt32 alarmTemperaturePercentU32 = (bytes[i] << 0) | (bytes[i+1] << 8) | (bytes[i+2] << 16) | (bytes[i+3] << 24); | |||||
float alarmTemperaturePercent = 0; | |||||
memcpy(&alarmTemperaturePercent, &alarmTemperaturePercentU32, sizeof(UInt32)); | |||||
param.alarmTemperaturePercent = alarmTemperaturePercent; | |||||
i += 4; | |||||
param.foodRawness = bytes[i]; | |||||
i += 1; | |||||
param.remarkData = [payload subdataWithRange:NSMakeRange(i, 32)]; | |||||
i += 32; | |||||
if (param.state == 0) { | |||||
[param clearAll]; | |||||
} | |||||
// [arr addObject:param]; | |||||
// } | |||||
// if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeBoxMultipleBleParser:option:supportProbe:params:)]) { | |||||
// [self.delegate meatProbeBoxMultipleBleParser:self option:option supportProbe:supportProbe params:arr.copy]; | |||||
// } | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeBoxMultipleBleParser:option:supportProbe:param:)]) { | |||||
[self.delegate meatProbeBoxMultipleBleParser:self option:option supportProbe:supportProbe param:param]; | |||||
} | |||||
} | |||||
- (void)parseStatusData:(NSData *)payload { | |||||
if (payload.length != 25 && payload.length != 41) { | |||||
return; | |||||
} | |||||
Byte *bytes = (Byte *)payload.bytes; | |||||
ELMeatProbeBoxMultipleStatusModel *boxStatus = [[ELMeatProbeBoxMultipleStatusModel alloc] init]; | |||||
boxStatus.timestamp = [NSDate date].timeIntervalSince1970; | |||||
boxStatus.boxMacString = self.mac; | |||||
Byte i = 1; | |||||
boxStatus.version = bytes[i]; | |||||
i = 2; | |||||
boxStatus.probeMaxCount = bytes[i]; | |||||
i = 3; | |||||
boxStatus.probeCount = bytes[i]; | |||||
i = 4; | |||||
boxStatus.batteryStatus = bytes[i] >> 7; | |||||
boxStatus.batteryPercent = bytes[i] & 0x7F; | |||||
i = 5; | |||||
boxStatus.unit = bytes[i]; | |||||
i = 9; | |||||
NSMutableArray *arr = [NSMutableArray array]; | |||||
while (i < payload.length) { | |||||
ELMeatProbeBoxMultipleProbeStatusModel *probeStatus = [[ELMeatProbeBoxMultipleProbeStatusModel alloc] init]; | |||||
probeStatus.timestamp = boxStatus.timestamp; | |||||
probeStatus.index = bytes[i]; | |||||
i += 1; | |||||
NSData *macData = [payload subdataWithRange:NSMakeRange(i, 6)]; | |||||
probeStatus.macData = macData; | |||||
i += 6; | |||||
probeStatus.internalTemperatureRaw = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
// 凸(艹皿艹 ) //0x639F (25503) | |||||
if (probeStatus.internalTemperatureRaw == 25503) { | |||||
probeStatus.internalTemperatureRaw = 0xFFFF; | |||||
} | |||||
i += 2; | |||||
probeStatus.ambientTemperatureRaw = (bytes[i] << 0) | (bytes[i+1] << 8); | |||||
// 凸(艹皿艹 ) //0x639F (25503) | |||||
if (probeStatus.ambientTemperatureRaw == 25503) { | |||||
probeStatus.ambientTemperatureRaw = 0xFFFF; | |||||
} | |||||
i += 2; | |||||
probeStatus.batteryStatus = bytes[i] >> 7; | |||||
probeStatus.batteryPercent = bytes[i] & 0x7F; | |||||
probeStatus.batteryRaw = bytes[i]; | |||||
i += 1; | |||||
probeStatus.insertStatusRaw = bytes[i]; | |||||
i += 1; | |||||
probeStatus.connectState = bytes[i]; | |||||
i += 3; | |||||
[arr addObject:probeStatus]; | |||||
} | |||||
boxStatus.probeStatusArray = arr.copy; | |||||
if (self.delegate && [self.delegate respondsToSelector:@selector(meatProbeBoxMultipleBleParser:boxStatus:)]) { | |||||
[self.delegate meatProbeBoxMultipleBleParser:self boxStatus:boxStatus]; | |||||
} | |||||
} | |||||
@end | |||||
@implementation ELMeatProbeBoxMultipleStatusModel | |||||
@end | |||||
@implementation ELMeatProbeBoxMultipleProbeStatusModel | |||||
- (NSString *)macString { | |||||
if (self.macData == nil || self.macData.length != 6) { | |||||
return nil; | |||||
} | |||||
Byte *bytes = (Byte *)self.macData.bytes; | |||||
NSString *str = [NSString stringWithFormat:@"%02X:%02X:%02X:%02X:%02X:%02X", bytes[5], bytes[4], bytes[3], bytes[2], bytes[1], bytes[0]]; | |||||
return str; | |||||
} | |||||
- (NSInteger)internalTemperature_C { | |||||
if (self.internalTemperatureRaw == 0xFFFF) { | |||||
return 0xFFFF; | |||||
} | |||||
if (self.internalTemperatureUnit == ELDeviceTemperatureUnit_C) { | |||||
return self.internalTemperature; | |||||
} | |||||
return [self convertF2C:self.internalTemperature]; | |||||
} | |||||
- (NSInteger)internalTemperature_F { | |||||
if (self.internalTemperatureRaw == 0xFFFF) { | |||||
return 0xFFFF; | |||||
} | |||||
if (self.internalTemperatureUnit == ELDeviceTemperatureUnit_F) { | |||||
return self.internalTemperature; | |||||
} | |||||
return [self convertC2F:self.internalTemperature]; | |||||
} | |||||
- (NSInteger)internalTemperature { | |||||
NSInteger value = self.internalTemperatureRaw & 0x3FFF; | |||||
if (self.internalTemperatureRaw & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (ELDeviceTemperatureUnit)internalTemperatureUnit { | |||||
return self.internalTemperatureRaw >> 15; | |||||
} | |||||
- (NSInteger)ambientTemperature_C { | |||||
if (self.ambientTemperatureRaw == 0xFFFF) { | |||||
return 0xFFFF; | |||||
} | |||||
if (self.ambientTemperatureUnit == ELDeviceTemperatureUnit_C) { | |||||
return self.ambientTemperature; | |||||
} | |||||
return [self convertF2C:self.ambientTemperature]; | |||||
} | |||||
- (NSInteger)ambientTemperature_F { | |||||
if (self.ambientTemperatureRaw == 0xFFFF) { | |||||
return 0xFFFF; | |||||
} | |||||
if (self.ambientTemperatureUnit == ELDeviceTemperatureUnit_F) { | |||||
return self.ambientTemperature; | |||||
} | |||||
return [self convertC2F:self.ambientTemperature]; | |||||
} | |||||
- (NSInteger)ambientTemperature { | |||||
NSInteger value = self.ambientTemperatureRaw & 0x3FFF; | |||||
if (self.ambientTemperatureRaw & 0x4000) { | |||||
value = -value; | |||||
} | |||||
return value; | |||||
} | |||||
- (ELDeviceTemperatureUnit)ambientTemperatureUnit { | |||||
return self.ambientTemperatureRaw >> 15; | |||||
} | |||||
//温度换算 | |||||
- (float)convertF2C:(float)fahrenheit { | |||||
return round((fahrenheit - 32) / 1.8); | |||||
} | |||||
- (float)convertC2F:(float)celsius { | |||||
return round(celsius * 1.8 + 32); | |||||
} | |||||
@end | |||||
@implementation ELMeatProbeBoxMultipleColorInfoModel | |||||
@end |
// | |||||
// MultipleMeatProbeBoxVC.h | |||||
// AILinkBleSDK_Example | |||||
// | |||||
// Created by LarryZhang on 2024/9/7. | |||||
// Copyright © 2024 zhengzida. All rights reserved. | |||||
// | |||||
#import <UIKit/UIKit.h> | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
@class ELAILinkPeripheral; | |||||
@interface MultipleMeatProbeBoxVC : UIViewController | |||||
@property (nonatomic, strong) ELAILinkPeripheral *per; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// MultipleMeatProbeBoxVC.m | |||||
// AILinkBleSDK_Example | |||||
// | |||||
// Created by LarryZhang on 2024/9/7. | |||||
// Copyright © 2024 zhengzida. All rights reserved. | |||||
// | |||||
#import "MultipleMeatProbeBoxVC.h" | |||||
#import <AILinkBleSDK/ELAILinkBleManager.h> | |||||
#import <AILinkBleSDK/NSData+AILinkBle.h> | |||||
#import "ELMeatProbeBoxMultipleBleParser.h" | |||||
#import "ELMeatProbeBoxMultipleBleCmdTool.h" | |||||
#import "ELMeatProbeBoxMultipleBleBBQParamModel.h" | |||||
@interface MultipleMeatProbeBoxVC () <ELAILinkBleManagerDelegate, ELMeatProbeBoxMultipleBleParserDelegate> | |||||
@property (weak, nonatomic) IBOutlet UILabel *bleStatusLabel; | |||||
@property (weak, nonatomic) IBOutlet UITextView *logTextView; | |||||
@property (nonatomic, strong) ELAILinkBleManager *bleManager; | |||||
@property (nonatomic, assign) NELBleManagerConnectState bleConnectState; | |||||
@property (nonatomic, strong) ELMeatProbeBoxMultipleBleParser *bleParser; | |||||
@property (nonatomic, strong) ELMeatProbeBoxMultipleStatusModel *boxStatus; | |||||
@property (nonatomic, strong) NSMutableDictionary<NSString *, ELMeatProbeBoxMultipleBleBBQParamModel *> *paramDic; | |||||
@end | |||||
@implementation MultipleMeatProbeBoxVC | |||||
- (void)viewDidLoad { | |||||
[super viewDidLoad]; | |||||
// Do any additional setup after loading the view from its nib. | |||||
self.paramDic = [NSMutableDictionary dictionary]; | |||||
[self initBle]; | |||||
} | |||||
- (void)dealloc { | |||||
[self deinitBle]; | |||||
} | |||||
#pragma mark - Action | |||||
- (IBAction)requestParamsAction:(id)sender { | |||||
NSData *payload = [ELMeatProbeBoxMultipleBleCmdTool requestParams:self.bleManager]; | |||||
NSString *log = [NSString stringWithFormat:@"发: payload: %@", payload]; | |||||
[self addLog:log]; | |||||
} | |||||
- (IBAction)setupParamsAction:(id)sender { | |||||
if (self.boxStatus == nil) { | |||||
return; | |||||
} | |||||
if (self.boxStatus.probeStatusArray == nil || self.boxStatus.probeStatusArray.count != 2) { | |||||
return; | |||||
} | |||||
ELMeatProbeBoxMultipleProbeStatusModel *status = self.boxStatus.probeStatusArray.firstObject; | |||||
if (status == nil) { | |||||
return; | |||||
} | |||||
ELMeatProbeBoxMultipleBleBBQParamModel *param = self.paramDic[status.macString]; | |||||
if (param == nil) { | |||||
return; | |||||
} | |||||
param.foodType = 1; | |||||
param.targetTemperatureRaw_C = 70; | |||||
param.targetTemperatureRaw_F = 212; | |||||
param.foodRawness = 1; | |||||
param.alarmTemperaturePercent = 0.95; | |||||
param.cookingId = [NSDate date].timeIntervalSince1970; | |||||
NSData *payload = [ELMeatProbeBoxMultipleBleCmdTool setupParam:param supportProbe:1 manager:self.bleManager]; | |||||
NSString *log = [NSString stringWithFormat:@"发: payload: %@", payload]; | |||||
[self addLog:log]; | |||||
} | |||||
- (IBAction)switchUnitAction:(id)sender { | |||||
if (self.boxStatus.unit == 1) { | |||||
NSData *payload = [ELMeatProbeBoxMultipleBleCmdTool switchUnit:0 manager:self.bleManager]; | |||||
NSString *log = [NSString stringWithFormat:@"发: payload: %@ -- 切换单位 to ℃", payload]; | |||||
[self addLog:log]; | |||||
} else { | |||||
NSData *payload = [ELMeatProbeBoxMultipleBleCmdTool switchUnit:1 manager:self.bleManager]; | |||||
NSString *log = [NSString stringWithFormat:@"发: payload: %@ -- 切换单位 to ℉", payload]; | |||||
[self addLog:log]; | |||||
} | |||||
} | |||||
- (IBAction)clearAction:(id)sender { | |||||
self.logTextView.text = @""; | |||||
} | |||||
- (IBAction)shareLogAction:(id)sender { | |||||
} | |||||
#pragma mark - ELAILinkBleManagerDelegate | |||||
- (void)initBle { | |||||
self.bleManager = [[ELAILinkBleManager alloc] init]; | |||||
self.bleManager.ailinkDelegate = self; | |||||
self.bleParser = [[ELMeatProbeBoxMultipleBleParser alloc] init]; | |||||
self.bleParser.delegate = self; | |||||
self.bleParser.mac = self.per.macAddressString; | |||||
} | |||||
- (void)scanBle { | |||||
[self.bleManager scanFilterWithCidArray:@[@(self.per.cid)]]; | |||||
} | |||||
- (void)connect:(ELAILinkPeripheral *)peripheral { | |||||
[self.bleManager connectAILinkPeripheral:peripheral]; | |||||
[self updateBleStatusView:NELBleManagerConnectStateConnecting]; | |||||
} | |||||
- (void)deinitBle { | |||||
[self.bleManager stopScan]; | |||||
self.bleManager.ailinkDelegate = nil; | |||||
[self.bleManager disconnectPeripheral]; | |||||
} | |||||
- (void)updateBleStatusView:(NELBleManagerConnectState)state { | |||||
if (self.bleManager.central.state == CBManagerStatePoweredOff) { | |||||
self.bleStatusLabel.text = @"蓝牙关闭"; | |||||
[self addLog:self.bleStatusLabel.text]; | |||||
return; | |||||
} | |||||
switch (state) { | |||||
case NELBleManagerConnectStateDisconnected: | |||||
self.bleStatusLabel.text = @"断开连接"; | |||||
break; | |||||
case NELBleManagerConnectStateFailed: | |||||
case NELBleManagerConnectStateFailedValidation: | |||||
self.bleStatusLabel.text = @"连接失败"; | |||||
break; | |||||
case NELBleManagerConnectStateConnecting: | |||||
self.bleStatusLabel.text = @"正在连接..."; | |||||
break; | |||||
case NELBleManagerConnectStatePassed: | |||||
self.bleStatusLabel.text = @"连接成功"; | |||||
[self requestDeviceData]; | |||||
// read RSSI | |||||
// [self readRSSI]; | |||||
break; | |||||
case NELBleManagerConnectStateCentralScanning: | |||||
self.bleStatusLabel.text = @"正在扫描..."; | |||||
break; | |||||
default: | |||||
break; | |||||
} | |||||
[self addLog:self.bleStatusLabel.text]; | |||||
} | |||||
- (void)requestDeviceData { | |||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0), dispatch_get_main_queue(), ^{ | |||||
}); | |||||
} | |||||
// 设备状态变更 | |||||
- (void)managerDidUpdateState:(CBCentralManager *)central { | |||||
NSLog(@"%s state:%@", __func__, @(central.state)); | |||||
if (central.state == CBManagerStatePoweredOn) { | |||||
[self scanBle]; | |||||
} else if (central.state == CBManagerStatePoweredOff) { | |||||
self.bleConnectState = NELBleManagerConnectStateCentralPowerOff; | |||||
[self updateBleStatusView:NELBleManagerConnectStateCentralPowerOff]; | |||||
} | |||||
} | |||||
- (void)managerScanState:(BOOL)scanning { | |||||
NSLog(@"%s scanning:%@", __func__, @(scanning)); | |||||
if (scanning) { | |||||
[self updateBleStatusView:NELBleManagerConnectStateCentralScanning]; | |||||
} | |||||
} | |||||
// 扫描到设备 | |||||
- (void)managerDidDiscoverPeripheral:(ELAILinkPeripheral *)peripheral { | |||||
NSLog(@"managerDidDiscoverPeripheral cid:%02x vid:%02x pid:%02x mac:%@", peripheral.cid, peripheral.vid, peripheral.pid, peripheral.macAddressString); | |||||
if ([peripheral.macAddressString isEqualToString:self.per.macAddressString]) { | |||||
[self.bleManager stopScan]; | |||||
[self connect:peripheral]; | |||||
} | |||||
} | |||||
- (void)managerDidUpdateConnect:(NELBleManagerConnectState)state { | |||||
NSLog(@"%s NELBleManagerConnectState:%@", __func__, @(state)); | |||||
[self updateBleStatusView:state]; | |||||
} | |||||
//A7数据 | |||||
- (void)aiLinkBleReceiveA7Data:(NSData *)payload { | |||||
NSLog(@"%s #### payload:%@", __func__, payload.elHexString); | |||||
NSString *log = [NSString stringWithFormat:@"收: payload: %@", payload.elHexString]; | |||||
[self addLog:log]; | |||||
[self.bleParser parseA7Payload:payload]; | |||||
} | |||||
//A6数据 | |||||
- (void)aiLinkBleReceiveA6Data:(NSData *)packet { | |||||
NSLog(@"%s ##### packet:%@", __func__, packet.elHexString); | |||||
Byte *bytes = (Byte *)packet.bytes; | |||||
Byte cmd = bytes[2]; | |||||
if (cmd == ELInetGetCmdTypeGetBMVersion) { | |||||
NSString *bmVersion = self.bleManager.bmVersion; | |||||
NSLog(@"##### bmVersion: %@", bmVersion); | |||||
} | |||||
if (cmd == ELInetGetCmdTypeGetBMVersionPro) { | |||||
NSString *bmVersionPro = self.bleManager.bmVersionPro; | |||||
NSLog(@"##### bmVersionPro: %@", bmVersionPro); | |||||
} | |||||
} | |||||
#pragma mark - ELMeatProbeBoxMultipleBleParserDelegate | |||||
//MCU 上报设备状态数据(Type:02) | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser boxStatus:(ELMeatProbeBoxMultipleStatusModel *)boxStatus { NSLog(@"##### boxStatus(): %@ ", boxStatus.debugDescription); | |||||
self.boxStatus = boxStatus; | |||||
NSString *log = [NSString stringWithFormat:@"boxStatus: { mac:%@, probeMaxCount:%hhu, probeCount:%hhu, batteryStatus:%hhu batteryPercent:%hhu, unit:%ld }", parser.mac, boxStatus.probeMaxCount, boxStatus.probeCount, boxStatus.batteryStatus, boxStatus.batteryPercent, boxStatus.unit]; | |||||
[self addLog:log]; | |||||
ELMeatProbeBoxMultipleProbeStatusModel *probeStatus = boxStatus.probeStatusArray.firstObject; | |||||
NSString *log2 = [NSString stringWithFormat:@"probeStatus: { connectState:%@ macString:%hhu, internalTemperature_C:%ld ℃, ambientTemperature_C:%ld ℃ batteryStatus:%hhu batteryPercent:%hhu }", probeStatus.macString, probeStatus.connectState, probeStatus.internalTemperature_C, probeStatus.ambientTemperature_C, probeStatus.batteryStatus, probeStatus.batteryPercent]; | |||||
[self addLog:log2]; | |||||
} | |||||
//切换单位(Type:04) | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser unit:(ELDeviceTemperatureUnit)unit { | |||||
NSLog(@"##### unit(): %@", @(unit)); | |||||
NSString *log = [NSString stringWithFormat:@"unit(): %@", unit == 0 ? @"℃" : @"°F"]; | |||||
[self addLog:log]; | |||||
} | |||||
//报警状态数据(Type:06)//state: bit0:食物目标温度到达时置1 | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser startAlarmWithState:(Byte)state macData:(NSData *)macData mac:(NSString *)mac { | |||||
NSLog(@"##### box:%@ startAlarmWithState(): probe:%@ state:%@", parser.mac, mac, @(state)); | |||||
NSString *log = [NSString stringWithFormat:@"box:%@ startAlarmWithState(): probe:%@ state:%@", parser.mac, mac, @(state)]; | |||||
[self addLog:log]; | |||||
} | |||||
//取消报警(Type:08) | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser stopAlarmWithMacData:(NSData *)macData mac:(NSString *)mac { | |||||
NSLog(@"##### box:%@ stopAlarmWithMacData(): probe:%@ ", parser.mac, mac); | |||||
NSString *log = [NSString stringWithFormat:@"box:%@ stopAlarmWithMacData(): probe:%@ ", parser.mac, mac]; | |||||
[self addLog:log]; | |||||
} | |||||
//烧烤任务参数(Type:0A)//Op:0x00:设置任务参数(设置时需要一个针一个针设定任务) 0x01:获取任务参数(返回所有的针任务,如果包长度超MTU时,会分包发) 0x02:结束烧烤任务 | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser option:(UInt8)option supportProbe:(UInt8)supportProbe param:(ELMeatProbeBoxMultipleBleBBQParamModel *)param { | |||||
NSLog(@"##### box:%@ meatProbeScreenBoxBleParser(): option:%@ supportProbe:%@ ", parser.mac, @(option), @(supportProbe)); | |||||
NSLog(@"##### param:%@ state:%@ foodType:%@", param.macString, @(param.state), @(param.foodType)); | |||||
self.paramDic[param.macString] = param; | |||||
NSString *log = [NSString stringWithFormat:@"box:%@ meatProbeScreenBoxBleParser(): option:%@ supportProbe:%@ ", parser.mac, @(option), @(supportProbe)]; | |||||
NSString *log2 = [NSString stringWithFormat:@"param:%@ state:%@ foodType:%@", param.macString, @(param.state), @(param.foodType)]; | |||||
[self addLog:log]; | |||||
[self addLog:log2]; | |||||
} | |||||
//color info | |||||
- (void)meatProbeBoxMultipleBleParser:(ELMeatProbeBoxMultipleBleParser *)parser colorInfos:(NSArray<ELMeatProbeBoxMultipleColorInfoModel *> *)colorInfos { | |||||
NSLog(@"##### colorInfos(): %@", colorInfos); | |||||
if (colorInfos == nil || colorInfos.count == 0) { | |||||
return; | |||||
} | |||||
ELMeatProbeBoxMultipleColorInfoModel *colorInfo = colorInfos.firstObject; | |||||
NSString *log = [NSString stringWithFormat:@"colorInfos(): count:%@ probeIndex:%@ colorIndex:%@", @(colorInfos.count), @(colorInfo.probeIndex), @(colorInfo.colorIndex)]; | |||||
[self addLog:log]; | |||||
} | |||||
- (void)peripheralDidReadRSSI:(nonnull NSNumber *)RSSI { | |||||
NSLog(@"%s peripheralDidReadRSSI: %@", __FUNCTION__, RSSI); | |||||
// main thread | |||||
dispatch_async(dispatch_get_main_queue(), ^{ | |||||
[self addLog:[NSString stringWithFormat:@"peripheralDidReadRSSI: %@", RSSI]]; | |||||
}); | |||||
[self readRSSI]; | |||||
} | |||||
- (void)readRSSI { | |||||
// delay | |||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(4.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ | |||||
// Read RSSI | |||||
[self.bleManager readRSSI]; | |||||
}); | |||||
} | |||||
#pragma mark - addLog | |||||
- (void)addLog:(NSString *)log { | |||||
[self addLog:log newline:YES]; | |||||
} | |||||
- (void)addWithoutNewlineLog:(NSString *)log { | |||||
[self addLog:log newline:NO]; | |||||
} | |||||
- (void)addLog:(NSString *)log newline:(BOOL)newline { | |||||
NSDateFormatter *format = [[NSDateFormatter alloc] init]; | |||||
format.dateFormat = @"HH:mm:ss.SSS"; | |||||
NSString *time = [format stringFromDate:[NSDate date]]; | |||||
if (newline) { | |||||
self.logTextView.text = [self.logTextView.text stringByAppendingFormat:@"%@ %@\n", time, log]; | |||||
} else { | |||||
self.logTextView.text = [self.logTextView.text stringByAppendingFormat:@"%@ %@", time, log]; | |||||
} | |||||
[self.logTextView scrollRangeToVisible:NSMakeRange(self.logTextView.text.length, 1)]; | |||||
} | |||||
@end |
<?xml version="1.0" encoding="UTF-8"?> | |||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> | |||||
<device id="retina6_12" orientation="portrait" appearance="light"/> | |||||
<dependencies> | |||||
<deployment identifier="iOS"/> | |||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/> | |||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/> | |||||
<capability name="System colors in document resources" minToolsVersion="11.0"/> | |||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | |||||
</dependencies> | |||||
<objects> | |||||
<placeholder placeholderIdentifier="IBFilesOwner" id="-1" userLabel="File's Owner" customClass="MultipleMeatProbeBoxVC"> | |||||
<connections> | |||||
<outlet property="bleStatusLabel" destination="avL-mp-uk3" id="FYb-Yh-SLT"/> | |||||
<outlet property="logTextView" destination="E0x-Fa-KTj" id="N8a-h2-SB1"/> | |||||
<outlet property="view" destination="x2W-jW-2kg" id="rLz-wJ-z8g"/> | |||||
</connections> | |||||
</placeholder> | |||||
<placeholder placeholderIdentifier="IBFirstResponder" id="-2" customClass="UIResponder"/> | |||||
<view clearsContextBeforeDrawing="NO" contentMode="scaleToFill" id="x2W-jW-2kg"> | |||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/> | |||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | |||||
<subviews> | |||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stauts" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="avL-mp-uk3"> | |||||
<rect key="frame" x="0.0" y="59" width="393" height="21"/> | |||||
<fontDescription key="fontDescription" type="system" pointSize="17"/> | |||||
<nil key="textColor"/> | |||||
<nil key="highlightedColor"/> | |||||
</label> | |||||
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="vOk-FU-BQ9"> | |||||
<rect key="frame" x="8" y="380" width="377" height="438"/> | |||||
<subviews> | |||||
<textView clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="scaleToFill" showsHorizontalScrollIndicator="NO" indicatorStyle="white" editable="NO" selectable="NO" translatesAutoresizingMaskIntoConstraints="NO" id="E0x-Fa-KTj"> | |||||
<rect key="frame" x="0.0" y="0.0" width="377" height="438"/> | |||||
<color key="backgroundColor" systemColor="labelColor"/> | |||||
<color key="textColor" systemColor="opaqueSeparatorColor"/> | |||||
<fontDescription key="fontDescription" name="HelveticaNeue-Light" family="Helvetica Neue" pointSize="10"/> | |||||
<textInputTraits key="textInputTraits" autocapitalizationType="sentences"/> | |||||
</textView> | |||||
</subviews> | |||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/> | |||||
<constraints> | |||||
<constraint firstAttribute="bottom" secondItem="E0x-Fa-KTj" secondAttribute="bottom" id="BHm-cI-1oG"/> | |||||
<constraint firstItem="E0x-Fa-KTj" firstAttribute="leading" secondItem="vOk-FU-BQ9" secondAttribute="leading" id="KII-WE-P1m"/> | |||||
<constraint firstAttribute="trailing" secondItem="E0x-Fa-KTj" secondAttribute="trailing" id="nXv-F2-TLg"/> | |||||
<constraint firstItem="E0x-Fa-KTj" firstAttribute="top" secondItem="vOk-FU-BQ9" secondAttribute="top" id="uJZ-ST-1Ce"/> | |||||
</constraints> | |||||
<userDefinedRuntimeAttributes> | |||||
<userDefinedRuntimeAttribute type="number" keyPath="cornerRadius"> | |||||
<real key="value" value="8"/> | |||||
</userDefinedRuntimeAttribute> | |||||
</userDefinedRuntimeAttributes> | |||||
</view> | |||||
<button hidden="YES" opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="e5p-j3-6VG"> | |||||
<rect key="frame" x="354" y="342" width="31" height="30"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="分享"/> | |||||
<connections> | |||||
<action selector="shareLogAction:" destination="-1" eventType="touchUpInside" id="8YU-6o-y8q"/> | |||||
</connections> | |||||
</button> | |||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="FoH-SE-VcD"> | |||||
<rect key="frame" x="8" y="342" width="31" height="30"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="清空"/> | |||||
<connections> | |||||
<action selector="clearAction:" destination="-1" eventType="touchUpInside" id="sBW-gD-CZ4"/> | |||||
</connections> | |||||
</button> | |||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="d8W-4g-bv9"> | |||||
<rect key="frame" x="16" y="96" width="128" height="35"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="Button"/> | |||||
<buttonConfiguration key="configuration" style="filled" title="请求烧烤参数"/> | |||||
<connections> | |||||
<action selector="requestParamsAction:" destination="-1" eventType="touchUpInside" id="zbL-Pf-OOz"/> | |||||
</connections> | |||||
</button> | |||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="RUX-kg-vMY"> | |||||
<rect key="frame" x="176" y="96" width="128" height="35"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="Button"/> | |||||
<buttonConfiguration key="configuration" style="filled" title="设置烧烤参数"/> | |||||
<connections> | |||||
<action selector="setupParamsAction:" destination="-1" eventType="touchUpInside" id="acG-k5-idT"/> | |||||
</connections> | |||||
</button> | |||||
<button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="dXn-E2-KcZ"> | |||||
<rect key="frame" x="16" y="147" width="93.333333333333329" height="35"/> | |||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | |||||
<state key="normal" title="Button"/> | |||||
<buttonConfiguration key="configuration" style="filled" title="单位切换"/> | |||||
<connections> | |||||
<action selector="switchUnitAction:" destination="-1" eventType="touchUpInside" id="rCn-DM-9bK"/> | |||||
</connections> | |||||
</button> | |||||
</subviews> | |||||
<viewLayoutGuide key="safeArea" id="NHq-9v-F7t"/> | |||||
<color key="backgroundColor" systemColor="systemBackgroundColor"/> | |||||
<constraints> | |||||
<constraint firstItem="d8W-4g-bv9" firstAttribute="leading" secondItem="NHq-9v-F7t" secondAttribute="leading" constant="16" id="0mG-RC-xTr"/> | |||||
<constraint firstItem="RUX-kg-vMY" firstAttribute="leading" secondItem="d8W-4g-bv9" secondAttribute="trailing" constant="32" id="4o1-mG-nyl"/> | |||||
<constraint firstItem="avL-mp-uk3" firstAttribute="top" secondItem="NHq-9v-F7t" secondAttribute="top" id="65b-CM-qWc"/> | |||||
<constraint firstItem="dXn-E2-KcZ" firstAttribute="leading" secondItem="d8W-4g-bv9" secondAttribute="leading" id="MnL-Ml-ELh"/> | |||||
<constraint firstItem="NHq-9v-F7t" firstAttribute="bottom" secondItem="vOk-FU-BQ9" secondAttribute="bottom" id="P3H-ha-my3"/> | |||||
<constraint firstItem="vOk-FU-BQ9" firstAttribute="top" secondItem="avL-mp-uk3" secondAttribute="bottom" constant="300" id="XgC-e8-meq"/> | |||||
<constraint firstItem="dXn-E2-KcZ" firstAttribute="top" secondItem="d8W-4g-bv9" secondAttribute="bottom" constant="16" id="Y47-BO-ap7"/> | |||||
<constraint firstItem="vOk-FU-BQ9" firstAttribute="leading" secondItem="NHq-9v-F7t" secondAttribute="leading" constant="8" id="bI5-zC-F3I"/> | |||||
<constraint firstItem="RUX-kg-vMY" firstAttribute="top" secondItem="d8W-4g-bv9" secondAttribute="top" id="hGc-8d-bah"/> | |||||
<constraint firstItem="avL-mp-uk3" firstAttribute="trailing" secondItem="NHq-9v-F7t" secondAttribute="trailing" id="jgI-X6-rF6"/> | |||||
<constraint firstItem="FoH-SE-VcD" firstAttribute="leading" secondItem="NHq-9v-F7t" secondAttribute="leading" constant="8" id="ldB-hE-eps"/> | |||||
<constraint firstItem="d8W-4g-bv9" firstAttribute="top" secondItem="avL-mp-uk3" secondAttribute="bottom" constant="16" id="mb7-bS-812"/> | |||||
<constraint firstItem="vOk-FU-BQ9" firstAttribute="top" secondItem="e5p-j3-6VG" secondAttribute="bottom" constant="8" symbolic="YES" id="mlJ-Mg-6V6"/> | |||||
<constraint firstItem="vOk-FU-BQ9" firstAttribute="top" secondItem="FoH-SE-VcD" secondAttribute="bottom" constant="8" symbolic="YES" id="szh-L5-bcY"/> | |||||
<constraint firstItem="avL-mp-uk3" firstAttribute="leading" secondItem="NHq-9v-F7t" secondAttribute="leading" id="uaL-lJ-HX1"/> | |||||
<constraint firstItem="NHq-9v-F7t" firstAttribute="trailing" secondItem="vOk-FU-BQ9" secondAttribute="trailing" constant="8" id="wtV-so-dPb"/> | |||||
<constraint firstItem="NHq-9v-F7t" firstAttribute="trailing" secondItem="e5p-j3-6VG" secondAttribute="trailing" constant="8" id="z2L-Bc-1Rc"/> | |||||
</constraints> | |||||
<point key="canvasLocation" x="139" y="21"/> | |||||
</view> | |||||
</objects> | |||||
<resources> | |||||
<systemColor name="labelColor"> | |||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | |||||
</systemColor> | |||||
<systemColor name="opaqueSeparatorColor"> | |||||
<color red="0.77647058823529413" green="0.77647058823529413" blue="0.78431372549019607" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |||||
</systemColor> | |||||
<systemColor name="systemBackgroundColor"> | |||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | |||||
</systemColor> | |||||
</resources> | |||||
</document> |
// | |||||
// ELMeatProbeBoxCustomDataModel.h | |||||
// AILinkBleSDK | |||||
// | |||||
#import <Foundation/Foundation.h> | |||||
#import <AILinkBleSDK/ELMeatProbeBleTool.h> | |||||
NS_ASSUME_NONNULL_BEGIN | |||||
#pragma pack(1) | |||||
typedef struct ELMeatProbeBoxCustomDataStruct { | |||||
UInt8 ver; //数据版本 (当前版本 0x02) //数据总长度: modelSize() | |||||
UInt32 cookingId; //烧烤id (选择食物的时间戳) | |||||
UInt8 foodType; //食物类型 | |||||
UInt8 foodRawness; //食物熟度 | |||||
SInt16 targetTemperature_C; //食物目标温度:℃ | |||||
SInt16 targetTemperature_F; //食物目标温度:℉ | |||||
SInt16 ambientMinTemperature_C; //炉温目标下限:℃ | |||||
SInt16 ambientMinTemperature_F; //炉温目标下限:℉ | |||||
SInt16 ambientMaxTemperature_C; //炉温目标上限:℃ | |||||
SInt16 ambientMaxTemperature_F; //炉温目标上限:℉ | |||||
double alarmTemperaturePercent; //提醒温度对目标温度百分比 0~1.0 | |||||
UInt32 timerStart;//计时开始时间戳 | |||||
UInt32 timerEnd;//计时结束时间戳 | |||||
UInt8 currentUnit; //当前温度单位 | |||||
SInt16 alarmTemperature_C; //食物提醒温度:℃ | |||||
SInt16 alarmTemperature_F; //食物提醒温度:℉ | |||||
UInt8 remarkBytes[32]; //UTF-8 编码 | |||||
} ELMeatProbeBoxCustomDataStruct; | |||||
#pragma pack() | |||||
/// | |||||
@interface ELMeatProbeBoxCustomDataModel : NSObject | |||||
@property (nonatomic, assign) ELMeatProbeBoxCustomDataStruct customStruct; | |||||
@property (nonatomic, assign, readonly) NSInteger ver; | |||||
@property (nonatomic, assign, readonly) NSInteger cookingId; | |||||
@property (nonatomic, assign, readonly) NSInteger foodType; | |||||
@property (nonatomic, assign, readonly) NSInteger foodRawness; | |||||
@property (nonatomic, assign) double alarmTemperaturePercent; | |||||
@property (nonatomic, assign, readonly) ELDeviceTemperatureUnit currentUnit; | |||||
+ (instancetype _Nullable)modelWithData:(NSData *)data; | |||||
- (NSData *)dataValue; | |||||
- (NSString *)remark; | |||||
- (NSString *)setRemark:(NSString *)remark; | |||||
+ (Byte)version; | |||||
+ (Byte)modelSize; | |||||
@end | |||||
NS_ASSUME_NONNULL_END |
// | |||||
// ELMeatProbeCustomDataModel.m | |||||
// AILinkBleSDK | |||||
// | |||||
#import "ELMeatProbeBoxCustomDataModel.h" | |||||
#import <AILinkBleSDK/NSData+AILinkBle.h> | |||||
#import <objc/runtime.h> | |||||
@implementation ELMeatProbeBoxCustomDataModel | |||||
+ (Byte)version { | |||||
return 0x02; | |||||
} | |||||
+ (Byte)modelSize { | |||||
return 128;//sizeof(ELMeatProbeCustomDataStruct); | |||||
} | |||||
+ (instancetype)modelWithData:(NSData *)data { | |||||
if (data.length != self.modelSize) { | |||||
NSLog(@"数据长度错误 data:%@", data); | |||||
return nil; | |||||
} | |||||
ELMeatProbeBoxCustomDataModel *model = [[ELMeatProbeBoxCustomDataModel alloc] initWithData:data]; | |||||
if (model.customStruct.ver != self.version) { | |||||
NSLog(@"数据版本错误 data:%@", data); | |||||
return nil; | |||||
} | |||||
return model; | |||||
} | |||||
- (instancetype)init { | |||||
if (self = [super init]) { | |||||
memset(&_customStruct, 0, sizeof(_customStruct)); | |||||
_customStruct.ver = self.class.version; | |||||
} | |||||
return self; | |||||
} | |||||
- (instancetype)initWithData:(NSData *)data { | |||||
if (self = [self init]) { | |||||
memcpy(&_customStruct, data.bytes, sizeof(_customStruct)); | |||||
} | |||||
return self; | |||||
} | |||||
- (NSData *)dataValue { | |||||
Byte bytes[128] = {0x00}; | |||||
memcpy(bytes, &_customStruct, sizeof(_customStruct)); | |||||
return [NSData dataWithBytes:bytes length:sizeof(bytes)]; | |||||
} | |||||
- (NSString *)remark { | |||||
char *remarkBytes[64] = {0}; | |||||
memcpy(remarkBytes, _customStruct.remarkBytes, sizeof(_customStruct.remarkBytes)); | |||||
NSString *str = [NSString stringWithUTF8String:(const char *)remarkBytes]; | |||||
return str; | |||||
} | |||||
- (NSString *)setRemark:(NSString *)remark { | |||||
NSData *data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
if (data.length > 32) { | |||||
while (data.length > 29) { | |||||
remark = [remark substringToIndex:(remark.length - 1)]; | |||||
data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
} | |||||
remark = [remark stringByAppendingString:@"..."]; | |||||
data = [remark dataUsingEncoding:NSUTF8StringEncoding]; | |||||
} | |||||
Byte *bytes = (Byte *)data.bytes; | |||||
NSUInteger total = data.length > 32 ? 32 : data.length; | |||||
memset(_customStruct.remarkBytes, 0, 32); | |||||
memcpy(_customStruct.remarkBytes, bytes, total); | |||||
return [self remark]; | |||||
} | |||||
#pragma mark setter getter | |||||
- (NSInteger)ver { | |||||
return self.customStruct.ver; | |||||
} | |||||
- (NSInteger)cookingId { | |||||
return self.customStruct.cookingId; | |||||
} | |||||
- (NSInteger)foodType { | |||||
return self.customStruct.foodType; | |||||
} | |||||
- (NSInteger)foodRawness { | |||||
return self.customStruct.foodRawness; | |||||
} | |||||
- (double)alarmTemperaturePercent { | |||||
return self.customStruct.alarmTemperaturePercent; | |||||
} | |||||
- (NSInteger)alarmTemperature_C { | |||||
return self.customStruct.alarmTemperature_C; | |||||
} | |||||
- (NSInteger)alarmTemperature_F { | |||||
return self.customStruct.alarmTemperature_F; | |||||
} | |||||
- (void)setAlarmTemperaturePercent:(double)alarmTemperaturePercent { | |||||
_customStruct.alarmTemperaturePercent = alarmTemperaturePercent; | |||||
_customStruct.alarmTemperature_C = _customStruct.targetTemperature_C * alarmTemperaturePercent; | |||||
_customStruct.alarmTemperature_F = _customStruct.targetTemperature_F * alarmTemperaturePercent; | |||||
} | |||||
- (ELDeviceTemperatureUnit)currentUnit { | |||||
return self.customStruct.currentUnit; | |||||
} | |||||
#pragma mark ---- description | |||||
- (NSString *)description { | |||||
NSMutableString *desc = [NSStringFromClass([self class]) stringByAppendingString:@": {\n"].mutableCopy; | |||||
[desc appendString:[NSString stringWithFormat:@"ver: %@,\n", @(self.customStruct.ver)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"cookingId: %@,\n", @(self.customStruct.cookingId)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"foodType: %@,\n", @(self.customStruct.foodType)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"foodRawness: %@,\n", @(self.customStruct.foodRawness)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"targetTemperature_C: %@,\n", @(self.customStruct.targetTemperature_C)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"targetTemperature_F: %@,\n", @(self.customStruct.targetTemperature_F)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"ambientMinTemperature_C: %@,\n", @(self.customStruct.ambientMinTemperature_C)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"ambientMinTemperature_F: %@,\n", @(self.customStruct.ambientMinTemperature_F)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"ambientMaxTemperature_C: %@,\n", @(self.customStruct.ambientMaxTemperature_C)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"ambientMaxTemperature_F: %@,\n", @(self.customStruct.ambientMaxTemperature_F)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"alarmTemperaturePercent: %@,\n", @(self.alarmTemperaturePercent)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"timerStart: %@,\n", @(self.customStruct.timerStart)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"timerEnd: %@,\n", @(self.customStruct.timerEnd)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"alarmTemperature_C: %@,\n", @(self.customStruct.alarmTemperature_C)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"alarmTemperature_F: %@,\n", @(self.customStruct.alarmTemperature_F)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"currentUnit: %@,\n", @(self.customStruct.currentUnit)]]; | |||||
[desc appendString:[NSString stringWithFormat:@"remark: %@,\n", self.remark]]; | |||||
[desc appendString:@"}"]; | |||||
return desc; | |||||
} | |||||
- (NSString *)debugDescription { | |||||
return [self description]; | |||||
} | |||||
@end |
- (void)initBle { | - (void)initBle { | ||||
self.bleManager = [[ELAILinkBleManager alloc] init]; | self.bleManager = [[ELAILinkBleManager alloc] init]; | ||||
self.bleManager.ailinkDelegate = self; | self.bleManager.ailinkDelegate = self; | ||||
self.bleParser = [ELMeatProbeBoxBleParser new]; | |||||
self.bleParser = [[ELMeatProbeBoxBleParser alloc] init]; | |||||
self.bleParser.delegate = self; | self.bleParser.delegate = self; | ||||
self.bleParser.mac = self.per.macAddressString; | |||||
} | } | ||||
- (void)scanBle { | - (void)scanBle { | ||||
- (void)requestDeviceData { | - (void)requestDeviceData { | ||||
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0), dispatch_get_main_queue(), ^{ | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1.0), dispatch_get_main_queue(), ^{ | ||||
// //APP获取设备功能列表 | |||||
// [self.bleManager airDetectorRequestDeviceFunctions]; | |||||
// //APP获取设备状态 //0x03 CMD:获取设备状态 | |||||
// [self.bleManager airDetectorRequestDeviceStatus]; | |||||
}); | }); | ||||
} | } | ||||
Byte *bytes = (Byte *)packet.bytes; | Byte *bytes = (Byte *)packet.bytes; | ||||
Byte cmd = bytes[2]; | Byte cmd = bytes[2]; | ||||
if (cmd == ELInetGetCmdTypeGetBatteryState) { | |||||
int power = self.bleManager.battery.power; | |||||
ELBatteryChargingState state = self.bleManager.battery.state; | |||||
NSLog(@"##### state: %lu power: %d", (unsigned long)state, power); | |||||
} | |||||
if (cmd == ELInetGetCmdTypeGetBMVersion) { | if (cmd == ELInetGetCmdTypeGetBMVersion) { | ||||
NSString *bmVersion = self.bleManager.bmVersion; | NSString *bmVersion = self.bleManager.bmVersion; | ||||
NSLog(@"##### bmVersion: %@", bmVersion); | NSLog(@"##### bmVersion: %@", bmVersion); |
<?xml version="1.0" encoding="UTF-8"?> | <?xml version="1.0" encoding="UTF-8"?> | ||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> | |||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.XIB" version="3.0" toolsVersion="32700.99.1234" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES"> | |||||
<device id="retina6_12" orientation="portrait" appearance="light"/> | <device id="retina6_12" orientation="portrait" appearance="light"/> | ||||
<dependencies> | <dependencies> | ||||
<deployment identifier="iOS"/> | <deployment identifier="iOS"/> | ||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/> | |||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="22684"/> | |||||
<capability name="Safe area layout guides" minToolsVersion="9.0"/> | <capability name="Safe area layout guides" minToolsVersion="9.0"/> | ||||
<capability name="System colors in document resources" minToolsVersion="11.0"/> | <capability name="System colors in document resources" minToolsVersion="11.0"/> | ||||
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> | ||||
<rect key="frame" x="0.0" y="0.0" width="393" height="852"/> | <rect key="frame" x="0.0" y="0.0" width="393" height="852"/> | ||||
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> | ||||
<subviews> | <subviews> | ||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stauts" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rgz-Ge-utp"> | |||||
<rect key="frame" x="0.0" y="63" width="393" 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="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="K5I-eH-HGA"> | <button opaque="NO" contentMode="scaleToFill" contentHorizontalAlignment="center" contentVerticalAlignment="center" buttonType="system" lineBreakMode="middleTruncation" translatesAutoresizingMaskIntoConstraints="NO" id="K5I-eH-HGA"> | ||||
<rect key="frame" x="16" y="346" width="31" height="30"/> | <rect key="frame" x="16" y="346" width="31" height="30"/> | ||||
<inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | <inset key="imageEdgeInsets" minX="0.0" minY="0.0" maxX="2.2250738585072014e-308" maxY="0.0"/> | ||||
<action selector="shareLogAction:" destination="-1" eventType="touchUpInside" id="aLe-00-nz6"/> | <action selector="shareLogAction:" destination="-1" eventType="touchUpInside" id="aLe-00-nz6"/> | ||||
</connections> | </connections> | ||||
</button> | </button> | ||||
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Stauts" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="Rgz-Ge-utp"> | |||||
<rect key="frame" x="0.0" y="63" width="393" height="21"/> | |||||
<fontDescription key="fontDescription" type="system" pointSize="17"/> | |||||
<nil key="textColor"/> | |||||
<nil key="highlightedColor"/> | |||||
</label> | |||||
<view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="I1h-EM-UuI"> | <view clipsSubviews="YES" contentMode="scaleToFill" translatesAutoresizingMaskIntoConstraints="NO" id="I1h-EM-UuI"> | ||||
<rect key="frame" x="8" y="384" width="377" height="434"/> | <rect key="frame" x="8" y="384" width="377" height="434"/> | ||||
<subviews> | <subviews> | ||||
</objects> | </objects> | ||||
<resources> | <resources> | ||||
<systemColor name="labelColor"> | <systemColor name="labelColor"> | ||||
<color red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |||||
<color white="0.0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | |||||
</systemColor> | </systemColor> | ||||
<systemColor name="opaqueSeparatorColor"> | <systemColor name="opaqueSeparatorColor"> | ||||
<color red="0.77647058823529413" green="0.77647058823529413" blue="0.78431372549019607" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |||||
<color red="0.77647058820000003" green="0.77647058820000003" blue="0.7843137255" alpha="1" colorSpace="custom" customColorSpace="sRGB"/> | |||||
</systemColor> | </systemColor> | ||||
<systemColor name="systemBackgroundColor"> | <systemColor name="systemBackgroundColor"> | ||||
<color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> | <color white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/> |
#import "MeatProbeVC.h" | #import "MeatProbeVC.h" | ||||
#import "MeatProbeBoxVC.h" | #import "MeatProbeBoxVC.h" | ||||
#import "HygrothermographVC.h" | #import "HygrothermographVC.h" | ||||
#import "MeatProbeScreenBoxVC.h" | |||||
#import "MultipleMeatProbeBoxVC.h" | |||||
@interface ViewController ()<UITableViewDelegate,UITableViewDataSource> | @interface ViewController ()<UITableViewDelegate,UITableViewDataSource> | ||||
[ELDemoDeviceModel modelWithIndex:@"26" imageName:@"meat_probe_type_ic" title:@"MeatProbe" subtitle:@"食物探针" entryVCName:NSStringFromClass(MeatProbeVC.class) cids:@[@(ELSupportDeviceTypeMeatProbe)]], | [ELDemoDeviceModel modelWithIndex:@"26" imageName:@"meat_probe_type_ic" title:@"MeatProbe" subtitle:@"食物探针" entryVCName:NSStringFromClass(MeatProbeVC.class) cids:@[@(ELSupportDeviceTypeMeatProbe)]], | ||||
[ELDemoDeviceModel modelWithIndex:@"27" imageName:@"ailink_cid85_type_ic" title:@"MeatProbeBox" subtitle:@"食物探针盒子" entryVCName:NSStringFromClass(MeatProbeBoxVC.class) cids:@[@(ELSupportDeviceTypeMeatProbeBox)]], | [ELDemoDeviceModel modelWithIndex:@"27" imageName:@"ailink_cid85_type_ic" title:@"MeatProbeBox" subtitle:@"食物探针盒子" entryVCName:NSStringFromClass(MeatProbeBoxVC.class) cids:@[@(ELSupportDeviceTypeMeatProbeBox)]], | ||||
[ELDemoDeviceModel modelWithIndex:@"27B" imageName:@"ailink_cid85_banding_cid_0062_100_ic" title:@"MeatProbeScreenBox" subtitle:@"食物探针带屏盒子" entryVCName:NSStringFromClass(MeatProbeScreenBoxVC.class) cids:@[@(0x0062)]], | |||||
[ELDemoDeviceModel modelWithIndex:@"27C" imageName:@"aibbq_add_equipment_probe_100_ic" title:@"MultipleMeatProbeBox" subtitle:@"多食物探针盒子" entryVCName:NSStringFromClass(MultipleMeatProbeBoxVC.class) cids:@[@(0x006B)]], | |||||
[ELDemoDeviceModel modelWithIndex:@"28" imageName:@"Hygrothermograph_add_icon2_100" title:@"Hygrothermograph" subtitle:@"温湿度计" entryVCName:NSStringFromClass(HygrothermographVC.class) cids:@[@(ELSupportDeviceTypeHygrothermograph)]], | [ELDemoDeviceModel modelWithIndex:@"28" imageName:@"Hygrothermograph_add_icon2_100" title:@"Hygrothermograph" subtitle:@"温湿度计" entryVCName:NSStringFromClass(HygrothermographVC.class) cids:@[@(ELSupportDeviceTypeHygrothermograph)]], | ||||
]; | ]; | ||||
} | } |
_tableView = [[UITableView alloc]init]; | _tableView = [[UITableView alloc]init]; | ||||
_tableView.delegate = self; | _tableView.delegate = self; | ||||
_tableView.dataSource = self; | _tableView.dataSource = self; | ||||
_tableView.tableFooterView = [UIView new]; | |||||
_tableView.tableFooterView = [[UIView alloc] init]; | |||||
_tableView.separatorColor = [UIColor clearColor]; | _tableView.separatorColor = [UIColor clearColor]; | ||||
} | } | ||||
return _tableView; | return _tableView; |
| 1.8.0 | 20240313 | larry | 修改 增加 readRSSI 接口 | | | 1.8.0 | 20240313 | larry | 修改 增加 readRSSI 接口 | | ||||
| 1.9.0 | 20240603 | larry | 修改 增加 Privacy Manifest | | | 1.9.0 | 20240603 | larry | 修改 增加 Privacy Manifest | | ||||
| 1.9.0(Demo v1.9.2) | 20240628 | larry | 修改 增加 温湿度计 Demo | | | 1.9.0(Demo v1.9.2) | 20240628 | larry | 修改 增加 温湿度计 Demo | | ||||
| 1.10.0 | 20240910 | larry | 修改 增加 带屏食物探针盒 多探针盒子 | | |||||