From: liangzhenying <867174124@qq.com>
Date: Mon, 3 Jun 2024 08:59:24 +0000 (+0800)
Subject: init
X-Git-Url: http://git.snicker.com.cn/Users/apple/Desktop/static/gitweb.css?a=commitdiff_plain;h=HEAD;p=mirrors%2FIOTBluetooth-iOS.git
init
---
c094088b5f04ae85934dd102f76a91a9344e865f
diff --git "a/Doc/230\350\223\235\347\211\231\346\211\213\350\241\250\351\200\232\350\256\257\345\215\217\350\256\256.docx" "b/Doc/230\350\223\235\347\211\231\346\211\213\350\241\250\351\200\232\350\256\257\345\215\217\350\256\256.docx"
new file mode 100644
index 0000000..0ab76ca
Binary files /dev/null and "b/Doc/230\350\223\235\347\211\231\346\211\213\350\241\250\351\200\232\350\256\257\345\215\217\350\256\256.docx" differ
diff --git "a/Doc/\346\265\267\346\200\235\350\223\235\347\211\231SDK\345\274\200\345\217\221\350\256\241\345\210\222.xlsx" "b/Doc/\346\265\267\346\200\235\350\223\235\347\211\231SDK\345\274\200\345\217\221\350\256\241\345\210\222.xlsx"
new file mode 100644
index 0000000..517995f
Binary files /dev/null and "b/Doc/\346\265\267\346\200\235\350\223\235\347\211\231SDK\345\274\200\345\217\221\350\256\241\345\210\222.xlsx" differ
diff --git a/IOTBluetooth/IOTBluetooth/Example/AbilityViewController.swift b/IOTBluetooth/IOTBluetooth/Example/AbilityViewController.swift
new file mode 100644
index 0000000..f390f9d
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/AbilityViewController.swift
@@ -0,0 +1,57 @@
+//
+// AbilityViewController.swift
+// Example
+//
+// Created by yaozuopan on 2024/3/11.
+//
+
+import UIKit
+import IOTBluetooth
+
+class AbilityViewController: BaseViewController {
+
+ @IBOutlet weak var listView: UITableView!
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ title = "å·²è¿æ¥" + IBManager.currentConnected!.name
+ }
+
+ deinit {
+ IBManager.remove(self)
+ }
+}
+
+extension AbilityViewController: UITableViewDelegate, UITableViewDataSource {
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ datas.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let data = datas[indexPath.row]
+ let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
+ let label = cell.viewWithTag(10) as! UILabel
+ label.text = "\(indexPath.row) " + data.ability.description + " \(data.label)"
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ activityIndicatorView.startAnimating()
+ let data = datas[indexPath.row]
+ IBSender()
+ .ability(data.ability)
+ .parameters(data.parameters)
+ .response {[weak self] result in
+ guard let self = self else {return}
+ if result.isSuccess{
+ //è¯·æ±æå
+ }
+ else{
+ //请æ±å¤±è´¥
+ }
+ print(result)
+ activityIndicatorView.stopAnimating()
+ }
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/Example/AppDelegate.swift b/IOTBluetooth/IOTBluetooth/Example/AppDelegate.swift
new file mode 100644
index 0000000..983bdde
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/AppDelegate.swift
@@ -0,0 +1,24 @@
+//
+// AppDelegate.swift
+// Example
+//
+// Created by yaozuopan on 2024/3/11.
+//
+
+import UIKit
+import IOTBluetooth
+
+@main
+class AppDelegate: UIResponder, UIApplicationDelegate {
+
+ var window: UIWindow?
+
+ func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
+ // Override point for customization after application launch.
+ IBManager.isDebug = true
+ IBManager.initializationSDK()
+
+ return true
+ }
+}
+
diff --git a/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/AccentColor.colorset/Contents.json b/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/AccentColor.colorset/Contents.json
new file mode 100644
index 0000000..eb87897
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/AccentColor.colorset/Contents.json
@@ -0,0 +1,11 @@
+{
+ "colors" : [
+ {
+ "idiom" : "universal"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/AppIcon.appiconset/Contents.json b/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/AppIcon.appiconset/Contents.json
new file mode 100644
index 0000000..13613e3
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/AppIcon.appiconset/Contents.json
@@ -0,0 +1,13 @@
+{
+ "images" : [
+ {
+ "idiom" : "universal",
+ "platform" : "ios",
+ "size" : "1024x1024"
+ }
+ ],
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/Contents.json b/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/Contents.json
new file mode 100644
index 0000000..73c0059
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/Assets.xcassets/Contents.json
@@ -0,0 +1,6 @@
+{
+ "info" : {
+ "author" : "xcode",
+ "version" : 1
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/Example/Base.lproj/LaunchScreen.storyboard b/IOTBluetooth/IOTBluetooth/Example/Base.lproj/LaunchScreen.storyboard
new file mode 100644
index 0000000..865e932
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/Base.lproj/LaunchScreen.storyboard
@@ -0,0 +1,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/Example/Base.lproj/Main.storyboard b/IOTBluetooth/IOTBluetooth/Example/Base.lproj/Main.storyboard
new file mode 100644
index 0000000..5a59854
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/Base.lproj/Main.storyboard
@@ -0,0 +1,298 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/Example/BaseViewController.swift b/IOTBluetooth/IOTBluetooth/Example/BaseViewController.swift
new file mode 100644
index 0000000..c7ab315
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/BaseViewController.swift
@@ -0,0 +1,36 @@
+//
+// BaseViewController.swift
+// Example
+//
+// Created by yaozuopan on 2024/3/14.
+//
+
+import UIKit
+
+class BaseViewController: UIViewController {
+
+ func showAlert(_ title: String? = nil, msg: String, confirmLabel: String? = nil, onConfirm: (() -> Void)? = nil) {
+ let alert = UIAlertController(title: title, message: msg, preferredStyle: .alert)
+ alert.addAction(UIAlertAction(title: "è¿å", style: .cancel))
+
+ if let confirmLabel = confirmLabel {
+ alert.addAction(UIAlertAction(title: confirmLabel, style: .default, handler: { _ in
+ onConfirm?()
+ }))
+ }
+ present(alert, animated: true)
+ }
+
+ let activityIndicatorView = UIActivityIndicatorView(style: .large)
+ override func viewDidLoad() {
+ super.viewDidLoad()
+
+ activityIndicatorView.frame = UIScreen.main.bounds
+ activityIndicatorView.layer.zPosition = 1
+ view.addSubview(activityIndicatorView)
+ }
+
+ deinit {
+ print("deinit \(Self.self)")
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/Example/ConnectViewController.swift b/IOTBluetooth/IOTBluetooth/Example/ConnectViewController.swift
new file mode 100644
index 0000000..53ec0bb
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/ConnectViewController.swift
@@ -0,0 +1,127 @@
+//
+// ConnectViewController.swift
+// Example
+//
+// Created by yaozuopan on 2024/3/14.
+//
+
+import UIKit
+import IOTBluetooth
+
+class ConnectViewController: BaseViewController {
+
+ @IBOutlet weak var dataView: UITextView!
+ @IBOutlet weak var dataPacketView: UITextView!
+ @IBOutlet weak var newLRC: UISwitch!
+ @IBOutlet weak var oldLRC: UISwitch!
+
+ var peripheral: IBPeripheral!
+
+ var dataPacket: [UInt8] = [] {
+ didSet {
+ dataPacketView.text = dataPacket.data.joined(" ")
+ }
+ }
+
+ var isNewLRC: Bool = true {
+ didSet {
+ if isNewLRC { oldLRC.isOn = false }
+ if isNewLRC == false { newLRC.isOn = false }
+
+ if isNewLRC == oldValue { return }
+ makeData()
+ }
+ }
+
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ title = "å·²è¿æ¥ \(peripheral.name)"
+
+ navigationItem.rightBarButtonItem = UIBarButtonItem(title: "æ¥çæ¥è®°", style: .done, target: self, action: #selector(onLog(_:)))
+
+ newLRC.addTarget(self, action: #selector(newOn(_:)), for: .valueChanged)
+ oldLRC.addTarget(self, action: #selector(oldOn(_:)), for: .valueChanged)
+ }
+
+ @objc func newOn(_ sender: UISwitch) {
+ isNewLRC = true
+ }
+
+ @objc func oldOn(_ sender: UISwitch) {
+ isNewLRC = false
+ }
+
+ @objc func onLog(_ sender: Any?) {
+ let vc = storyboard!.instantiateViewController(withIdentifier: "LogViewController")
+ navigationController?.pushViewController(vc, animated: true)
+ }
+
+ @IBAction func onSend(_ sender: UIButton) {
+// guard dataPacketView.text.count > 10 else { return }
+// showAlert("å°åé以䏿°æ®", msg: dataPacketView.text, confirmLabel: "åé") { [unowned self] in
+// activityIndicatorView.startAnimating()
+// let bytes = dataPacketView.text!
+// .split(separator: " ")
+// .map { String($0) }
+// .map {
+// var result: UInt64 = 0
+// Scanner(string: $0).scanHexInt64(&result)
+// return UInt8(result)
+// }
+// IBManager.sendInfo(dataPacket.data) { [unowned self] isSuccess in
+// activityIndicatorView.stopAnimating()
+// guard isSuccess else { return }
+// showAlert(msg: "æ°æ®å·²åé")
+// }
+//
+// IBSender()
+// .ability(.battery)
+// .completion { response in
+//
+// }
+// .send()
+ }
+
+ /// ç»è£
ä¿¡æ¯
+ func makeData() {
+
+ let data: [UInt8] = []//dataView.text!.data!.bytes
+
+ /// åå
æ°
+ let packageCount = 1
+ /// æ°æ®å
æ»é¿åº¦
+ let dataTotalLength = data.count
+ /// æ°æ®å
é¿åº¦
+ let dataLength = data.count
+ /// æ°æ®å
ç´¢å¼
+ let index = 1
+
+ var bytes = [0x73, 0x01, 0x07] + packageCount.byte4 + dataTotalLength.byte4 + index.byte4 + dataLength.byte2
+
+ dataPacket = bytes + data + [0x00]
+
+// if isNewLRC {
+// dataPacket = bytes + [LRC.calculateLRC(data)]
+// } else {
+// dataPacket = bytes + [LRC.calculate(data)]
+// }
+ }
+
+ override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+ makeData()
+ }
+}
+
+extension ConnectViewController: UITextViewDelegate {
+
+ func textView(_ textView: UITextView, shouldChangeTextIn range: NSRange, replacementText text: String) -> Bool {
+ guard text == "\n" else { return true }
+ textView.resignFirstResponder()
+
+ if textView === dataView {
+ makeData()
+ }
+ return false
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/Example/Datas.swift b/IOTBluetooth/IOTBluetooth/Example/Datas.swift
new file mode 100644
index 0000000..a72c68a
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/Datas.swift
@@ -0,0 +1,93 @@
+//
+// Datas.swift
+// Example
+//
+// Created by yaozuopan on 2024/3/19.
+//
+
+import Foundation
+import IOTBluetooth
+
+let datas: [(ability: IBAbility, label: String, parameters: [IBParameter])] = [
+ (.userData,"è®¾ç½®ç¨æ·æ°æ®",[.userInfo(IBUserInfo())]),
+ (.language, "设置è¯è¨", [.language(.english)]),
+ (.about,"å
³äºæ¬æºå
容",[]),
+ (.find, "å¼å§æ¥æ¾æè¡¨", [.action(1)]),
+ (.find, "åæ¢æ¥æ¾æè¡¨", [.action(0)]),
+ (.message, "å¼å¯æ¶æ¯æ¨éåè½", [.action(1)]),
+ (.message, "å
³éæ¶æ¯æ¨éåè½", [.action(0)]),
+
+ (.takePhoto, "å¼å¯æå¿æç
§", [.action(1)]),
+ (.takePhoto, "å
³éæå¿æç
§", [.action(0)]),
+ (.restore, "æ¢å¤åºå设置", []),
+ (.reboot, "éæ°å¯å¨", []),
+ (.shutdown, "å
³æº", []),
+ (.fetchScreen, "è·åæè¡¨å±å¹åæ°", []),
+ (.screen, "设置æè¡¨å±å¹åæ°", [.screen(IBScreen())]),
+ (.fetchBattery, "è·åçµé", []),
+ (.fetchClock, "è·åé¹é设置", []),
+ (.setClock, "åéé¹é设置", [.clock(IBClock())]),
+
+ (.fetchCurrentDialId, "åéå½å表çID", []),
+ (.switchDial, "åæ¢è¡¨ç", [.dialID(12)]),
+ (.deleteDial, "å é¤è¡¨ç", [.dialID(12)]),
+ (.fetchDials, "è·åææè¡¨çUID", []),
+ (.checkDialID, "è·åæè¡¨çIDæ¯å¦å·²å®è£
", [.dialID(12)]),
+
+ (.fetchWatchState, "è·åå½åæè¡¨ç¶æ", []),
+ (.fetchVibrateSound, "è·åæè¡¨å£°é³ä¸éå¨åæ°", []),
+ (.vibrateSound, "设置æè¡¨å£°é³ä¸éå¨åæ°", [.vibrateSound(IBVibrateSound())]),
+ (.fetchAuxiliary, "è·åæè¡¨è¾
å©åè½åæ°", []),
+ (.auxiliary, "设置æè¡¨è¾
å©åè½åæ°", [.auxiliary(.bloodOxygen)]),
+ (.unit, "设置æè¡¨å
¬è±å¶åä½", [.value(1)]),
+
+ (.sendWeather, "åéå¤©æ°æ°æ®", [.weather(IBWeather())]),
+ (.disk, "è·åSDå¡å©ä½ç©ºé´", []),
+ (.unpair, "åéè§£é¤é
å¯¹æ¶æ¯", []),
+ (.sendUnpair, "åéåæ¶è§£é¤é
å¯¹æ¶æ¯", []),
+
+
+ (.startSport, "å¼å¯æå®è¿å¨æ¨¡å¼", [.motionMode(.running)]),
+ (.trainPauseResume, "è®ç»æå", [.action(0)]),
+ (.trainPauseResume, "è®ç»æ¢å¤", [.action(1)]),
+ (.endSport, "ç»æè¿å¨æ¨¡å¼", []),
+
+ (.heartRateMode, "å¼å¯èªå¨è·å宿¶å¿ç", [.action(1)]),
+ (.heartRateMode, "å
³éèªå¨è·å宿¶å¿ç", [.action(0)]),
+ (.heartRateHigh, "设置æé«å¿çæé", [.value(240)]),
+ (.heartRateHigh, "å
³éæé«å¿çæé", [.value(0)]),
+ (.fetchHeartRate, "è·åæè¡¨å¿çåæ°", []),
+ (.heartRate, "设置æè¡¨å¿çåæ°", [.heartRate(IBHeartRate())]),
+ (.currentHeartRate, "è·å宿¶å¿ç", []),
+
+ (.fetchBloodOxygen, "è·åæè¡¨è¡æ°§è®¾ç½®", []),
+ (.bloodOxygen, "设置æè¡¨è¡æ°§åæ°", [.bloodOxygen(IBBloodOxygen())]),
+ (.trainFrequency, "设置è®ç»å®æ¶æ°æ®éæ ·é¢ç", [.value(30)]),
+
+ (.fetchTargetStep, "è·åç®æ æ¥æ°è®¾ç½®", []),
+ (.targetStep, "è®¾ç½®ç®æ æ¥æ°", [.targetStep(IBTargetStep())]),
+ (.fetchOtherTarget, "è·åå
¶ä»ç®æ 设置", []),
+ (.targetOther, "设置å
¶ä»ç®æ ", [.otherTarget(IBOtherTarget())]),
+ (.trainTarget, "设置è®ç»ç®æ ", [.trainTarget(IBTrainTarget())]),
+ (.fetchSleep, "è·åç¡ç 设置", []),
+ (.sleep, "设置ç¡ç ", [.sleep(IBSleep())]),
+ (.fetchWater, "è·åæè¡¨åæ°´æé设置", []),
+ (.water, "è®¾ç½®åæ°´æé", [.water(IBWater())]),
+
+
+ (.syncHeartRate, "忥å¿çå岿°æ®", [.value(30)]),
+ (.syncBloodOxygen, "åæ¥è¡æ°§å岿°æ®", [.value(30)]),
+ (.syncStepCount, "忥å岿¥æ°æ°æ®", [.value(30)]),
+ (.syncFatBurning, "忥çèæ¶é´å岿°æ®", [.value(30)]),
+ (.syncStand, "忥ç«ç«å岿°æ®", [.value(30)]),
+ (.syncCalorie, "忥å¡è·¯éå岿°æ®", [.value(30)]),
+ (.syncDistance, "忥è·ç¦»å岿°æ®", [.value(30)]),
+ (.syncTrain, "忥åºç¡è®ç»å岿°æ®", [.value(30)]),
+ (.syncGPS, "åæ¥è·¯å¾åæ éå岿°æ®", [.value(1654012800)]),
+ (.sendSyncEnd, "åéåæ¥æ°æ®ç»ææ¶æ¯", []),
+ (.addressBook, "åéé讯å½", [.addressBook(IBAddressBook.test())]),
+
+// (.revokeFileSend, "æ¤éå½åæä»¶ä¼ è¾", [.file(.mp3)]),
+// (.fetchFiles, "è·åæå®ç±»åæææä»¶", [.file(.mp3)]),
+// (.deleteFiles, "å 餿å®ç±»åæææä»¶", [.file(.mp3)]),
+]
diff --git a/IOTBluetooth/IOTBluetooth/Example/Info.plist b/IOTBluetooth/IOTBluetooth/Example/Info.plist
new file mode 100644
index 0000000..e999718
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/Info.plist
@@ -0,0 +1,10 @@
+
+
+
+
+ UIBackgroundModes
+
+ bluetooth-central
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/Example/LogViewController.swift b/IOTBluetooth/IOTBluetooth/Example/LogViewController.swift
new file mode 100644
index 0000000..246784a
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/LogViewController.swift
@@ -0,0 +1,24 @@
+//
+// LogViewController.swift
+// Example
+//
+// Created by yaozuopan on 2024/3/14.
+//
+
+import UIKit
+import IOTBluetooth
+
+class LogViewController: BaseViewController {
+
+ @IBOutlet weak var textView: UITextView!
+
+ override func viewDidLoad() {
+ title = "èçæ¥å¿"
+ }
+
+ override func viewDidAppear(_ animated: Bool) {
+ super.viewDidAppear(animated)
+ textView.text = IBManager.logs.joined(separator: "\n")
+ }
+}
+
diff --git a/IOTBluetooth/IOTBluetooth/Example/ViewController.swift b/IOTBluetooth/IOTBluetooth/Example/ViewController.swift
new file mode 100644
index 0000000..1d6af06
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/Example/ViewController.swift
@@ -0,0 +1,98 @@
+//
+// ViewController.swift
+// Example
+//
+// Created by yaozuopan on 2024/3/11.
+//
+
+import UIKit
+import IOTBluetooth
+
+class ViewController: BaseViewController {
+
+ @IBOutlet weak var listView: UITableView!
+
+ private var datas: [IBPeripheral] = []
+ override func viewDidLoad() {
+ super.viewDidLoad()
+ title = "IOTBluetooth"
+
+ IBManager.subscribe(.connectStateDidChange, observer: self) { object, userInfo in
+ print("connect notice " + "\(object!)")
+ }
+ IBManager.subscribe(.takePhoto, observer: self) { object, userInfo in
+ print("takePhoto notice " + "\(object!)")
+ }
+ IBManager.subscribe(.didFindDevice, observer: self) { object, userInfo in
+ print("find notice " )
+ }
+ IBManager.subscribe(.trainStateDidChanged, observer: self) { object, userInfo in
+ let model = object as! IBTarinState
+ print("trainState notice " + model.description)
+ }
+ IBManager.subscribe(.trainingData, observer: self) { object, userInfo in
+ let model = object as! IBTrainingData
+ print("trainingData notice " + model.description)
+ }
+// IBManager.subscribe(.weather, observer: self) { object, userInfo in
+// print("weather notice ")
+// }
+ }
+
+ deinit {
+ IBManager.remove(self)
+ }
+
+ @IBAction func startScan(_ sender: UIButton) {
+ title = "æ£å¨æ«æèç设å¤..."
+ IBManager.scan { [unowned self] peripheral in
+ if let _ = datas.filter({ $0.uuid == peripheral.uuid }).last {
+ return
+ }
+ print(peripheral.name)
+ print(peripheral.macAddress)
+ print(peripheral.softwareVersion)
+ print(peripheral.rssi)
+
+ datas.append(peripheral)
+ listView.reloadData()
+ }
+ }
+
+ override func viewWillDisappear(_ animated: Bool) {
+ super.viewWillDisappear(animated)
+ IBManager.stopScan()
+ title = "IOTBluetooth"
+ }
+
+}
+
+extension ViewController: UITableViewDelegate, UITableViewDataSource {
+
+ func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
+ datas.count
+ }
+
+ func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
+ let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
+ let label = cell.viewWithTag(10) as! UILabel
+ label.text = datas[indexPath.row].name + "ï¼ç¹å»è¿æ¥ï¼"
+ return cell
+ }
+
+ func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+ activityIndicatorView.startAnimating()
+ let device = datas[indexPath.row]
+ IBManager.connect(device) { [unowned self] isSuccess in
+ activityIndicatorView.stopAnimating()
+ if isSuccess{
+ let vc = storyboard!.instantiateViewController(identifier: "AbilityViewController")
+ navigationController?.pushViewController(vc, animated: true)
+ }
+ else{
+ print("è¿æ¥å¤±è´¥")
+ }
+ }
+ print(indexPath)
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.pbxproj b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.pbxproj
new file mode 100644
index 0000000..5ffed27
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.pbxproj
@@ -0,0 +1,821 @@
+// !$*UTF8*$!
+{
+ archiveVersion = 1;
+ classes = {
+ };
+ objectVersion = 56;
+ objects = {
+
+/* Begin PBXBuildFile section */
+ 180B01982BFC831300524729 /* IBHistoryHeartRate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 180B01972BFC831300524729 /* IBHistoryHeartRate.swift */; };
+ 180B019E2BFC9CF400524729 /* IBHistoryBaseTraining.swift in Sources */ = {isa = PBXBuildFile; fileRef = 180B019D2BFC9CF400524729 /* IBHistoryBaseTraining.swift */; };
+ 180CE2652C0D728F00A7006E /* IBAddressBook.swift in Sources */ = {isa = PBXBuildFile; fileRef = 180CE2642C0D728F00A7006E /* IBAddressBook.swift */; };
+ 184431322BF3720E00546E4E /* IBOtherTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184431312BF3720E00546E4E /* IBOtherTarget.swift */; };
+ 1849DC8F2BEC8007002C2D2D /* IBVibrateSound.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1849DC8E2BEC8007002C2D2D /* IBVibrateSound.swift */; };
+ 1849DC912BECD131002C2D2D /* IBCode.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1849DC902BECD131002C2D2D /* IBCode.swift */; };
+ 184B94CB2BF606CC0042BEB3 /* IBTrainTarget.swift in Sources */ = {isa = PBXBuildFile; fileRef = 184B94CA2BF606CC0042BEB3 /* IBTrainTarget.swift */; };
+ 1859DFA02BFF5A2700112E8C /* IBSendTime.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1859DF9F2BFF5A2700112E8C /* IBSendTime.swift */; };
+ 18993AA22C073FED006742D2 /* IBBloodOxygen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18993AA12C073FED006742D2 /* IBBloodOxygen.swift */; };
+ 189C15892C05E0CD00676A80 /* IBTarinState.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189C15882C05E0CD00676A80 /* IBTarinState.swift */; };
+ 189C158B2C05F27C00676A80 /* IBAbout.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189C158A2C05F27C00676A80 /* IBAbout.swift */; };
+ 189C158D2C05F58A00676A80 /* IBHistoryBloodOxygen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189C158C2C05F58A00676A80 /* IBHistoryBloodOxygen.swift */; };
+ 189C158F2C05F85200676A80 /* IBHistoryStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189C158E2C05F85200676A80 /* IBHistoryStep.swift */; };
+ 189C15912C05FBA100676A80 /* IBHistoryBurning.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189C15902C05FBA100676A80 /* IBHistoryBurning.swift */; };
+ 189C15932C05FFA600676A80 /* IBHistoryStand.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189C15922C05FFA600676A80 /* IBHistoryStand.swift */; };
+ 189C15952C05FFC700676A80 /* IBHistoryCalorie.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189C15942C05FFC700676A80 /* IBHistoryCalorie.swift */; };
+ 189C15972C05FFEE00676A80 /* IBHistoryDistance.swift in Sources */ = {isa = PBXBuildFile; fileRef = 189C15962C05FFEE00676A80 /* IBHistoryDistance.swift */; };
+ 18C9589B2C082FA7006A5DE8 /* IBWeather.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C9589A2C082FA7006A5DE8 /* IBWeather.swift */; };
+ 18C9589D2C08600C006A5DE8 /* IBHistoryGps.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C9589C2C08600C006A5DE8 /* IBHistoryGps.swift */; };
+ 18C9589F2C086A9D006A5DE8 /* IBHistorySleep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18C9589E2C086A9D006A5DE8 /* IBHistorySleep.swift */; };
+ 18E7AC922BF44C6800CB9393 /* IBSleep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E7AC912BF44C6800CB9393 /* IBSleep.swift */; };
+ 18E7AC942BF4B31000CB9393 /* IBWater.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E7AC932BF4B31000CB9393 /* IBWater.swift */; };
+ 18E7AC962BF5E39900CB9393 /* IBHeartRate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18E7AC952BF5E39900CB9393 /* IBHeartRate.swift */; };
+ 18EC6E282BFF4C6D00757CA8 /* IBPhoneInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EC6E272BFF4C6D00757CA8 /* IBPhoneInfo.swift */; };
+ 18EFF59B2C080F14001B1E0E /* IBUserInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 18EFF59A2C080F14001B1E0E /* IBUserInfo.swift */; };
+ 8A0A39BF2B980BEF006A3B18 /* IOTBluetooth.h in Headers */ = {isa = PBXBuildFile; fileRef = 8A0A39BE2B980BEF006A3B18 /* IOTBluetooth.h */; settings = {ATTRIBUTES = (Public, ); }; };
+ 8A0A39C62B980C88006A3B18 /* IBluetooth.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0A39C52B980C88006A3B18 /* IBluetooth.swift */; };
+ 8A0A39C92B980CC2006A3B18 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A0A39C82B980CC2006A3B18 /* CoreBluetooth.framework */; };
+ 8A0A39CB2B980CFC006A3B18 /* Logger.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0A39CA2B980CFC006A3B18 /* Logger.swift */; };
+ 8A0A39CD2B980D53006A3B18 /* IBPeripheral.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0A39CC2B980D53006A3B18 /* IBPeripheral.swift */; };
+ 8A0A39D22B980E4C006A3B18 /* JSON.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0A39D12B980E4C006A3B18 /* JSON.swift */; };
+ 8A0A39D42B980E93006A3B18 /* Any.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0A39D32B980E93006A3B18 /* Any.swift */; };
+ 8A0A39D62B980EC9006A3B18 /* IBPeripheralUUID.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0A39D52B980EC9006A3B18 /* IBPeripheralUUID.swift */; };
+ 8A0A39D82B980F58006A3B18 /* UTF8.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0A39D72B980F58006A3B18 /* UTF8.swift */; };
+ 8A0A39DA2B981037006A3B18 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A0A39D92B981037006A3B18 /* Date.swift */; };
+ 8A1DFF522B9EB4F800B735FF /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1DFF512B9EB4F800B735FF /* AppDelegate.swift */; };
+ 8A1DFF562B9EB4F800B735FF /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A1DFF552B9EB4F800B735FF /* ViewController.swift */; };
+ 8A1DFF592B9EB4F900B735FF /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8A1DFF572B9EB4F900B735FF /* Main.storyboard */; };
+ 8A1DFF5B2B9EB4F900B735FF /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 8A1DFF5A2B9EB4F900B735FF /* Assets.xcassets */; };
+ 8A1DFF5E2B9EB4F900B735FF /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 8A1DFF5C2B9EB4F900B735FF /* LaunchScreen.storyboard */; };
+ 8A34B9252BA2A069000F66BD /* IBWatchInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A34B9242BA2A069000F66BD /* IBWatchInfo.swift */; };
+ 8A34B9272BA2AB66000F66BD /* ConnectViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A34B9262BA2AB66000F66BD /* ConnectViewController.swift */; };
+ 8A34B9292BA2AB86000F66BD /* LogViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A34B9282BA2AB86000F66BD /* LogViewController.swift */; };
+ 8A34B92B2BA2D446000F66BD /* BaseViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A34B92A2BA2D446000F66BD /* BaseViewController.swift */; };
+ 8A34B92D2BA2FA02000F66BD /* IBManufacturer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A34B92C2BA2FA02000F66BD /* IBManufacturer.swift */; };
+ 8A5822CF2BA1A67700590AB6 /* IBAbility.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A5822CE2BA1A67700590AB6 /* IBAbility.swift */; };
+ 8A5822D12BA1C80700590AB6 /* LRC.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A5822D02BA1C80700590AB6 /* LRC.swift */; };
+ 8A65F95F2BABEC4D005C1EA4 /* IBClock.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A65F95E2BABEC4D005C1EA4 /* IBClock.swift */; };
+ 8A65F9612BAC0810005C1EA4 /* IBSimulateParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A65F9602BAC0810005C1EA4 /* IBSimulateParser.swift */; };
+ 8A65F9632BAC1018005C1EA4 /* IBTargetStep.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A65F9622BAC1018005C1EA4 /* IBTargetStep.swift */; };
+ 8A65F9652BAC271B005C1EA4 /* IBScreen.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A65F9642BAC271B005C1EA4 /* IBScreen.swift */; };
+ 8A76B6092BA84C2B0016F2AB /* AbilityViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A76B6082BA84C2B0016F2AB /* AbilityViewController.swift */; };
+ 8A76B60B2BA851730016F2AB /* IBParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A76B60A2BA851730016F2AB /* IBParser.swift */; };
+ 8A79D2252BA4278E0096A98C /* IBSender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A79D2242BA4278E0096A98C /* IBSender.swift */; };
+ 8A79D2272BA433330096A98C /* IBNotify.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A79D2262BA433330096A98C /* IBNotify.swift */; };
+ 8A79D2292BA43F5A0096A98C /* IBResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A79D2282BA43F5A0096A98C /* IBResponse.swift */; };
+ 8A878FE02BA93CF1008C7F26 /* Datas.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A878FDF2BA93CF1008C7F26 /* Datas.swift */; };
+ 8A878FE22BA9444C008C7F26 /* IBParameter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A878FE12BA9444C008C7F26 /* IBParameter.swift */; };
+ 8A878FE42BA94D09008C7F26 /* IBChecker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A878FE32BA94D09008C7F26 /* IBChecker.swift */; };
+ 8A87FBB32BAA7F3900096761 /* IBLanguage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A87FBB22BAA7F3900096761 /* IBLanguage.swift */; };
+ 8A87FBB52BAA85FB00096761 /* IBTrainingData.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A87FBB42BAA85FB00096761 /* IBTrainingData.swift */; };
+ 8A9F6ABD2BA0463D00DA520F /* CRC16.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A9F6ABC2BA0463D00DA520F /* CRC16.swift */; };
+ 8A9F6ABE2BA0475100DA520F /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A0A39C82B980CC2006A3B18 /* CoreBluetooth.framework */; };
+ 8A9F6AC12BA04BE100DA520F /* IBManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 8A9F6AC02BA04BE100DA520F /* IBManager.swift */; };
+ 8A9F6AC22BA05CB500DA520F /* IOTBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 8A0A39BB2B980BEF006A3B18 /* IOTBluetooth.framework */; };
+ 8A9F6AC32BA05CB500DA520F /* IOTBluetooth.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 8A0A39BB2B980BEF006A3B18 /* IOTBluetooth.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
+/* End PBXBuildFile section */
+
+/* Begin PBXContainerItemProxy section */
+ 8A9F6AC42BA05CB500DA520F /* PBXContainerItemProxy */ = {
+ isa = PBXContainerItemProxy;
+ containerPortal = 8A0A39B22B980BEF006A3B18 /* Project object */;
+ proxyType = 1;
+ remoteGlobalIDString = 8A0A39BA2B980BEF006A3B18;
+ remoteInfo = IOTBluetooth;
+ };
+/* End PBXContainerItemProxy section */
+
+/* Begin PBXCopyFilesBuildPhase section */
+ 8A9F6AC62BA05CB500DA520F /* Embed Frameworks */ = {
+ isa = PBXCopyFilesBuildPhase;
+ buildActionMask = 2147483647;
+ dstPath = "";
+ dstSubfolderSpec = 10;
+ files = (
+ 8A9F6AC32BA05CB500DA520F /* IOTBluetooth.framework in Embed Frameworks */,
+ );
+ name = "Embed Frameworks";
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXCopyFilesBuildPhase section */
+
+/* Begin PBXFileReference section */
+ 180B01972BFC831300524729 /* IBHistoryHeartRate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryHeartRate.swift; sourceTree = ""; };
+ 180B019D2BFC9CF400524729 /* IBHistoryBaseTraining.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryBaseTraining.swift; sourceTree = ""; };
+ 180CE2642C0D728F00A7006E /* IBAddressBook.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBAddressBook.swift; sourceTree = ""; };
+ 184431312BF3720E00546E4E /* IBOtherTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBOtherTarget.swift; sourceTree = ""; };
+ 1849DC8E2BEC8007002C2D2D /* IBVibrateSound.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBVibrateSound.swift; sourceTree = ""; };
+ 1849DC902BECD131002C2D2D /* IBCode.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBCode.swift; sourceTree = ""; };
+ 184B94CA2BF606CC0042BEB3 /* IBTrainTarget.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBTrainTarget.swift; sourceTree = ""; };
+ 1859DF9F2BFF5A2700112E8C /* IBSendTime.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBSendTime.swift; sourceTree = ""; };
+ 18993AA12C073FED006742D2 /* IBBloodOxygen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBBloodOxygen.swift; sourceTree = ""; };
+ 189C15882C05E0CD00676A80 /* IBTarinState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBTarinState.swift; sourceTree = ""; };
+ 189C158A2C05F27C00676A80 /* IBAbout.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBAbout.swift; sourceTree = ""; };
+ 189C158C2C05F58A00676A80 /* IBHistoryBloodOxygen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryBloodOxygen.swift; sourceTree = ""; };
+ 189C158E2C05F85200676A80 /* IBHistoryStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryStep.swift; sourceTree = ""; };
+ 189C15902C05FBA100676A80 /* IBHistoryBurning.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryBurning.swift; sourceTree = ""; };
+ 189C15922C05FFA600676A80 /* IBHistoryStand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryStand.swift; sourceTree = ""; };
+ 189C15942C05FFC700676A80 /* IBHistoryCalorie.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryCalorie.swift; sourceTree = ""; };
+ 189C15962C05FFEE00676A80 /* IBHistoryDistance.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryDistance.swift; sourceTree = ""; };
+ 18C9589A2C082FA7006A5DE8 /* IBWeather.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBWeather.swift; sourceTree = ""; };
+ 18C9589C2C08600C006A5DE8 /* IBHistoryGps.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistoryGps.swift; sourceTree = ""; };
+ 18C9589E2C086A9D006A5DE8 /* IBHistorySleep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHistorySleep.swift; sourceTree = ""; };
+ 18E7AC912BF44C6800CB9393 /* IBSleep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBSleep.swift; sourceTree = ""; };
+ 18E7AC932BF4B31000CB9393 /* IBWater.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBWater.swift; sourceTree = ""; };
+ 18E7AC952BF5E39900CB9393 /* IBHeartRate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBHeartRate.swift; sourceTree = ""; };
+ 18EC6E272BFF4C6D00757CA8 /* IBPhoneInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBPhoneInfo.swift; sourceTree = ""; };
+ 18EFF59A2C080F14001B1E0E /* IBUserInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBUserInfo.swift; sourceTree = ""; };
+ 8A0A39BB2B980BEF006A3B18 /* IOTBluetooth.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = IOTBluetooth.framework; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8A0A39BE2B980BEF006A3B18 /* IOTBluetooth.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = IOTBluetooth.h; sourceTree = ""; };
+ 8A0A39C52B980C88006A3B18 /* IBluetooth.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IBluetooth.swift; sourceTree = ""; };
+ 8A0A39C82B980CC2006A3B18 /* CoreBluetooth.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreBluetooth.framework; path = System/Library/Frameworks/CoreBluetooth.framework; sourceTree = SDKROOT; };
+ 8A0A39CA2B980CFC006A3B18 /* Logger.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Logger.swift; sourceTree = ""; };
+ 8A0A39CC2B980D53006A3B18 /* IBPeripheral.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBPeripheral.swift; sourceTree = ""; };
+ 8A0A39D12B980E4C006A3B18 /* JSON.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = JSON.swift; sourceTree = ""; };
+ 8A0A39D32B980E93006A3B18 /* Any.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Any.swift; sourceTree = ""; };
+ 8A0A39D52B980EC9006A3B18 /* IBPeripheralUUID.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IBPeripheralUUID.swift; sourceTree = ""; };
+ 8A0A39D72B980F58006A3B18 /* UTF8.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = UTF8.swift; sourceTree = ""; };
+ 8A0A39D92B981037006A3B18 /* Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = ""; };
+ 8A1DFF4F2B9EB4F800B735FF /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; };
+ 8A1DFF512B9EB4F800B735FF /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
+ 8A1DFF552B9EB4F800B735FF /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
+ 8A1DFF582B9EB4F900B735FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
+ 8A1DFF5A2B9EB4F900B735FF /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
+ 8A1DFF5D2B9EB4F900B735FF /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
+ 8A1DFF5F2B9EB4F900B735FF /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
+ 8A34B9242BA2A069000F66BD /* IBWatchInfo.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBWatchInfo.swift; sourceTree = ""; };
+ 8A34B9262BA2AB66000F66BD /* ConnectViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ConnectViewController.swift; sourceTree = ""; };
+ 8A34B9282BA2AB86000F66BD /* LogViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LogViewController.swift; sourceTree = ""; };
+ 8A34B92A2BA2D446000F66BD /* BaseViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BaseViewController.swift; sourceTree = ""; };
+ 8A34B92C2BA2FA02000F66BD /* IBManufacturer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBManufacturer.swift; sourceTree = ""; };
+ 8A5822CE2BA1A67700590AB6 /* IBAbility.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBAbility.swift; sourceTree = ""; };
+ 8A5822D02BA1C80700590AB6 /* LRC.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LRC.swift; sourceTree = ""; };
+ 8A65F95E2BABEC4D005C1EA4 /* IBClock.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBClock.swift; sourceTree = ""; };
+ 8A65F9602BAC0810005C1EA4 /* IBSimulateParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IBSimulateParser.swift; sourceTree = ""; };
+ 8A65F9622BAC1018005C1EA4 /* IBTargetStep.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBTargetStep.swift; sourceTree = ""; };
+ 8A65F9642BAC271B005C1EA4 /* IBScreen.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBScreen.swift; sourceTree = ""; };
+ 8A76B6082BA84C2B0016F2AB /* AbilityViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AbilityViewController.swift; sourceTree = ""; };
+ 8A76B60A2BA851730016F2AB /* IBParser.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBParser.swift; sourceTree = ""; };
+ 8A79D2242BA4278E0096A98C /* IBSender.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBSender.swift; sourceTree = ""; };
+ 8A79D2262BA433330096A98C /* IBNotify.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = IBNotify.swift; sourceTree = ""; };
+ 8A79D2282BA43F5A0096A98C /* IBResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBResponse.swift; sourceTree = ""; };
+ 8A878FDF2BA93CF1008C7F26 /* Datas.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Datas.swift; sourceTree = ""; };
+ 8A878FE12BA9444C008C7F26 /* IBParameter.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBParameter.swift; sourceTree = ""; };
+ 8A878FE32BA94D09008C7F26 /* IBChecker.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBChecker.swift; sourceTree = ""; };
+ 8A87FBB22BAA7F3900096761 /* IBLanguage.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBLanguage.swift; sourceTree = ""; };
+ 8A87FBB42BAA85FB00096761 /* IBTrainingData.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBTrainingData.swift; sourceTree = ""; };
+ 8A9F6ABC2BA0463D00DA520F /* CRC16.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CRC16.swift; sourceTree = ""; };
+ 8A9F6AC02BA04BE100DA520F /* IBManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = IBManager.swift; sourceTree = ""; };
+/* End PBXFileReference section */
+
+/* Begin PBXFrameworksBuildPhase section */
+ 8A0A39B82B980BEF006A3B18 /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8A0A39C92B980CC2006A3B18 /* CoreBluetooth.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8A1DFF4C2B9EB4F800B735FF /* Frameworks */ = {
+ isa = PBXFrameworksBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8A9F6AC22BA05CB500DA520F /* IOTBluetooth.framework in Frameworks */,
+ 8A9F6ABE2BA0475100DA520F /* CoreBluetooth.framework in Frameworks */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXFrameworksBuildPhase section */
+
+/* Begin PBXGroup section */
+ 8A0A39B12B980BEF006A3B18 = {
+ isa = PBXGroup;
+ children = (
+ 8A0A39BD2B980BEF006A3B18 /* IOTBluetooth */,
+ 8A1DFF502B9EB4F800B735FF /* Example */,
+ 8A0A39BC2B980BEF006A3B18 /* Products */,
+ 8A0A39C72B980CC2006A3B18 /* Frameworks */,
+ );
+ sourceTree = "";
+ };
+ 8A0A39BC2B980BEF006A3B18 /* Products */ = {
+ isa = PBXGroup;
+ children = (
+ 8A0A39BB2B980BEF006A3B18 /* IOTBluetooth.framework */,
+ 8A1DFF4F2B9EB4F800B735FF /* Example.app */,
+ );
+ name = Products;
+ sourceTree = "";
+ };
+ 8A0A39BD2B980BEF006A3B18 /* IOTBluetooth */ = {
+ isa = PBXGroup;
+ children = (
+ 8A9F6ABF2BA04B5100DA520F /* Models */,
+ 8A0A39D02B980DFD006A3B18 /* Tools */,
+ 8A0A39C52B980C88006A3B18 /* IBluetooth.swift */,
+ 8A5822CE2BA1A67700590AB6 /* IBAbility.swift */,
+ 8A878FE32BA94D09008C7F26 /* IBChecker.swift */,
+ 8A76B60A2BA851730016F2AB /* IBParser.swift */,
+ 8A65F9602BAC0810005C1EA4 /* IBSimulateParser.swift */,
+ 8A878FE12BA9444C008C7F26 /* IBParameter.swift */,
+ 8A79D2242BA4278E0096A98C /* IBSender.swift */,
+ 8A79D2262BA433330096A98C /* IBNotify.swift */,
+ 8A9F6AC02BA04BE100DA520F /* IBManager.swift */,
+ 8A0A39BE2B980BEF006A3B18 /* IOTBluetooth.h */,
+ );
+ path = IOTBluetooth;
+ sourceTree = "";
+ };
+ 8A0A39C72B980CC2006A3B18 /* Frameworks */ = {
+ isa = PBXGroup;
+ children = (
+ 8A0A39C82B980CC2006A3B18 /* CoreBluetooth.framework */,
+ );
+ name = Frameworks;
+ sourceTree = "";
+ };
+ 8A0A39D02B980DFD006A3B18 /* Tools */ = {
+ isa = PBXGroup;
+ children = (
+ 8A0A39D52B980EC9006A3B18 /* IBPeripheralUUID.swift */,
+ 8A0A39D32B980E93006A3B18 /* Any.swift */,
+ 8A0A39D92B981037006A3B18 /* Date.swift */,
+ 8A0A39D12B980E4C006A3B18 /* JSON.swift */,
+ 8A9F6ABC2BA0463D00DA520F /* CRC16.swift */,
+ 8A5822D02BA1C80700590AB6 /* LRC.swift */,
+ 8A0A39D72B980F58006A3B18 /* UTF8.swift */,
+ 8A0A39CA2B980CFC006A3B18 /* Logger.swift */,
+ );
+ path = Tools;
+ sourceTree = "";
+ };
+ 8A1DFF502B9EB4F800B735FF /* Example */ = {
+ isa = PBXGroup;
+ children = (
+ 8A1DFF512B9EB4F800B735FF /* AppDelegate.swift */,
+ 8A1DFF552B9EB4F800B735FF /* ViewController.swift */,
+ 8A34B9262BA2AB66000F66BD /* ConnectViewController.swift */,
+ 8A76B6082BA84C2B0016F2AB /* AbilityViewController.swift */,
+ 8A878FDF2BA93CF1008C7F26 /* Datas.swift */,
+ 8A34B92A2BA2D446000F66BD /* BaseViewController.swift */,
+ 8A34B9282BA2AB86000F66BD /* LogViewController.swift */,
+ 8A1DFF572B9EB4F900B735FF /* Main.storyboard */,
+ 8A1DFF5A2B9EB4F900B735FF /* Assets.xcassets */,
+ 8A1DFF5C2B9EB4F900B735FF /* LaunchScreen.storyboard */,
+ 8A1DFF5F2B9EB4F900B735FF /* Info.plist */,
+ );
+ path = Example;
+ sourceTree = "";
+ };
+ 8A9F6ABF2BA04B5100DA520F /* Models */ = {
+ isa = PBXGroup;
+ children = (
+ 8A0A39CC2B980D53006A3B18 /* IBPeripheral.swift */,
+ 8A87FBB22BAA7F3900096761 /* IBLanguage.swift */,
+ 8A79D2282BA43F5A0096A98C /* IBResponse.swift */,
+ 8A65F95E2BABEC4D005C1EA4 /* IBClock.swift */,
+ 18E7AC912BF44C6800CB9393 /* IBSleep.swift */,
+ 8A65F9642BAC271B005C1EA4 /* IBScreen.swift */,
+ 18E7AC932BF4B31000CB9393 /* IBWater.swift */,
+ 8A65F9622BAC1018005C1EA4 /* IBTargetStep.swift */,
+ 8A87FBB42BAA85FB00096761 /* IBTrainingData.swift */,
+ 8A34B92C2BA2FA02000F66BD /* IBManufacturer.swift */,
+ 8A34B9242BA2A069000F66BD /* IBWatchInfo.swift */,
+ 184431312BF3720E00546E4E /* IBOtherTarget.swift */,
+ 184B94CA2BF606CC0042BEB3 /* IBTrainTarget.swift */,
+ 18E7AC952BF5E39900CB9393 /* IBHeartRate.swift */,
+ 18993AA12C073FED006742D2 /* IBBloodOxygen.swift */,
+ 180B01972BFC831300524729 /* IBHistoryHeartRate.swift */,
+ 189C158C2C05F58A00676A80 /* IBHistoryBloodOxygen.swift */,
+ 189C158E2C05F85200676A80 /* IBHistoryStep.swift */,
+ 189C15902C05FBA100676A80 /* IBHistoryBurning.swift */,
+ 189C15922C05FFA600676A80 /* IBHistoryStand.swift */,
+ 189C15942C05FFC700676A80 /* IBHistoryCalorie.swift */,
+ 189C15962C05FFEE00676A80 /* IBHistoryDistance.swift */,
+ 180B019D2BFC9CF400524729 /* IBHistoryBaseTraining.swift */,
+ 18C9589E2C086A9D006A5DE8 /* IBHistorySleep.swift */,
+ 18C9589C2C08600C006A5DE8 /* IBHistoryGps.swift */,
+ 1849DC8E2BEC8007002C2D2D /* IBVibrateSound.swift */,
+ 18EC6E272BFF4C6D00757CA8 /* IBPhoneInfo.swift */,
+ 1859DF9F2BFF5A2700112E8C /* IBSendTime.swift */,
+ 189C15882C05E0CD00676A80 /* IBTarinState.swift */,
+ 189C158A2C05F27C00676A80 /* IBAbout.swift */,
+ 18EFF59A2C080F14001B1E0E /* IBUserInfo.swift */,
+ 18C9589A2C082FA7006A5DE8 /* IBWeather.swift */,
+ 180CE2642C0D728F00A7006E /* IBAddressBook.swift */,
+ 1849DC902BECD131002C2D2D /* IBCode.swift */,
+ );
+ path = Models;
+ sourceTree = "";
+ };
+/* End PBXGroup section */
+
+/* Begin PBXHeadersBuildPhase section */
+ 8A0A39B62B980BEF006A3B18 /* Headers */ = {
+ isa = PBXHeadersBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8A0A39BF2B980BEF006A3B18 /* IOTBluetooth.h in Headers */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXHeadersBuildPhase section */
+
+/* Begin PBXNativeTarget section */
+ 8A0A39BA2B980BEF006A3B18 /* IOTBluetooth */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8A0A39C22B980BEF006A3B18 /* Build configuration list for PBXNativeTarget "IOTBluetooth" */;
+ buildPhases = (
+ 8A0A39B62B980BEF006A3B18 /* Headers */,
+ 8A0A39B72B980BEF006A3B18 /* Sources */,
+ 8A0A39B82B980BEF006A3B18 /* Frameworks */,
+ 8A0A39B92B980BEF006A3B18 /* Resources */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ );
+ name = IOTBluetooth;
+ productName = IOTBluetooth;
+ productReference = 8A0A39BB2B980BEF006A3B18 /* IOTBluetooth.framework */;
+ productType = "com.apple.product-type.framework";
+ };
+ 8A1DFF4E2B9EB4F800B735FF /* Example */ = {
+ isa = PBXNativeTarget;
+ buildConfigurationList = 8A1DFF622B9EB4F900B735FF /* Build configuration list for PBXNativeTarget "Example" */;
+ buildPhases = (
+ 8A1DFF4B2B9EB4F800B735FF /* Sources */,
+ 8A1DFF4C2B9EB4F800B735FF /* Frameworks */,
+ 8A1DFF4D2B9EB4F800B735FF /* Resources */,
+ 8A9F6AC62BA05CB500DA520F /* Embed Frameworks */,
+ );
+ buildRules = (
+ );
+ dependencies = (
+ 8A9F6AC52BA05CB500DA520F /* PBXTargetDependency */,
+ );
+ name = Example;
+ productName = Example;
+ productReference = 8A1DFF4F2B9EB4F800B735FF /* Example.app */;
+ productType = "com.apple.product-type.application";
+ };
+/* End PBXNativeTarget section */
+
+/* Begin PBXProject section */
+ 8A0A39B22B980BEF006A3B18 /* Project object */ = {
+ isa = PBXProject;
+ attributes = {
+ BuildIndependentTargetsInParallel = 1;
+ LastSwiftUpdateCheck = 1500;
+ LastUpgradeCheck = 1500;
+ TargetAttributes = {
+ 8A0A39BA2B980BEF006A3B18 = {
+ CreatedOnToolsVersion = 15.0;
+ LastSwiftMigration = 1500;
+ };
+ 8A1DFF4E2B9EB4F800B735FF = {
+ CreatedOnToolsVersion = 15.0;
+ };
+ };
+ };
+ buildConfigurationList = 8A0A39B52B980BEF006A3B18 /* Build configuration list for PBXProject "IOTBluetooth" */;
+ compatibilityVersion = "Xcode 14.0";
+ developmentRegion = en;
+ hasScannedForEncodings = 0;
+ knownRegions = (
+ en,
+ Base,
+ );
+ mainGroup = 8A0A39B12B980BEF006A3B18;
+ productRefGroup = 8A0A39BC2B980BEF006A3B18 /* Products */;
+ projectDirPath = "";
+ projectRoot = "";
+ targets = (
+ 8A0A39BA2B980BEF006A3B18 /* IOTBluetooth */,
+ 8A1DFF4E2B9EB4F800B735FF /* Example */,
+ );
+ };
+/* End PBXProject section */
+
+/* Begin PBXResourcesBuildPhase section */
+ 8A0A39B92B980BEF006A3B18 /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8A1DFF4D2B9EB4F800B735FF /* Resources */ = {
+ isa = PBXResourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8A1DFF5E2B9EB4F900B735FF /* LaunchScreen.storyboard in Resources */,
+ 8A1DFF5B2B9EB4F900B735FF /* Assets.xcassets in Resources */,
+ 8A1DFF592B9EB4F900B735FF /* Main.storyboard in Resources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXResourcesBuildPhase section */
+
+/* Begin PBXSourcesBuildPhase section */
+ 8A0A39B72B980BEF006A3B18 /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8A79D2292BA43F5A0096A98C /* IBResponse.swift in Sources */,
+ 189C15932C05FFA600676A80 /* IBHistoryStand.swift in Sources */,
+ 1849DC8F2BEC8007002C2D2D /* IBVibrateSound.swift in Sources */,
+ 180CE2652C0D728F00A7006E /* IBAddressBook.swift in Sources */,
+ 8A878FE22BA9444C008C7F26 /* IBParameter.swift in Sources */,
+ 184431322BF3720E00546E4E /* IBOtherTarget.swift in Sources */,
+ 189C158B2C05F27C00676A80 /* IBAbout.swift in Sources */,
+ 189C15972C05FFEE00676A80 /* IBHistoryDistance.swift in Sources */,
+ 180B019E2BFC9CF400524729 /* IBHistoryBaseTraining.swift in Sources */,
+ 8A87FBB52BAA85FB00096761 /* IBTrainingData.swift in Sources */,
+ 8A878FE42BA94D09008C7F26 /* IBChecker.swift in Sources */,
+ 189C15892C05E0CD00676A80 /* IBTarinState.swift in Sources */,
+ 8A76B60B2BA851730016F2AB /* IBParser.swift in Sources */,
+ 18EFF59B2C080F14001B1E0E /* IBUserInfo.swift in Sources */,
+ 8A65F9612BAC0810005C1EA4 /* IBSimulateParser.swift in Sources */,
+ 180B01982BFC831300524729 /* IBHistoryHeartRate.swift in Sources */,
+ 189C158D2C05F58A00676A80 /* IBHistoryBloodOxygen.swift in Sources */,
+ 8A79D2272BA433330096A98C /* IBNotify.swift in Sources */,
+ 8A0A39D42B980E93006A3B18 /* Any.swift in Sources */,
+ 1849DC912BECD131002C2D2D /* IBCode.swift in Sources */,
+ 8A34B92D2BA2FA02000F66BD /* IBManufacturer.swift in Sources */,
+ 184B94CB2BF606CC0042BEB3 /* IBTrainTarget.swift in Sources */,
+ 8A79D2252BA4278E0096A98C /* IBSender.swift in Sources */,
+ 18C9589D2C08600C006A5DE8 /* IBHistoryGps.swift in Sources */,
+ 189C15912C05FBA100676A80 /* IBHistoryBurning.swift in Sources */,
+ 8A9F6ABD2BA0463D00DA520F /* CRC16.swift in Sources */,
+ 18E7AC942BF4B31000CB9393 /* IBWater.swift in Sources */,
+ 8A5822CF2BA1A67700590AB6 /* IBAbility.swift in Sources */,
+ 8A65F9652BAC271B005C1EA4 /* IBScreen.swift in Sources */,
+ 1859DFA02BFF5A2700112E8C /* IBSendTime.swift in Sources */,
+ 8A65F9632BAC1018005C1EA4 /* IBTargetStep.swift in Sources */,
+ 8A34B9252BA2A069000F66BD /* IBWatchInfo.swift in Sources */,
+ 8A0A39D62B980EC9006A3B18 /* IBPeripheralUUID.swift in Sources */,
+ 189C15952C05FFC700676A80 /* IBHistoryCalorie.swift in Sources */,
+ 8A9F6AC12BA04BE100DA520F /* IBManager.swift in Sources */,
+ 18EC6E282BFF4C6D00757CA8 /* IBPhoneInfo.swift in Sources */,
+ 18C9589F2C086A9D006A5DE8 /* IBHistorySleep.swift in Sources */,
+ 8A65F95F2BABEC4D005C1EA4 /* IBClock.swift in Sources */,
+ 8A0A39D22B980E4C006A3B18 /* JSON.swift in Sources */,
+ 18E7AC962BF5E39900CB9393 /* IBHeartRate.swift in Sources */,
+ 18C9589B2C082FA7006A5DE8 /* IBWeather.swift in Sources */,
+ 8A0A39D82B980F58006A3B18 /* UTF8.swift in Sources */,
+ 18E7AC922BF44C6800CB9393 /* IBSleep.swift in Sources */,
+ 8A0A39C62B980C88006A3B18 /* IBluetooth.swift in Sources */,
+ 8A0A39CB2B980CFC006A3B18 /* Logger.swift in Sources */,
+ 189C158F2C05F85200676A80 /* IBHistoryStep.swift in Sources */,
+ 8A5822D12BA1C80700590AB6 /* LRC.swift in Sources */,
+ 8A0A39DA2B981037006A3B18 /* Date.swift in Sources */,
+ 18993AA22C073FED006742D2 /* IBBloodOxygen.swift in Sources */,
+ 8A0A39CD2B980D53006A3B18 /* IBPeripheral.swift in Sources */,
+ 8A87FBB32BAA7F3900096761 /* IBLanguage.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+ 8A1DFF4B2B9EB4F800B735FF /* Sources */ = {
+ isa = PBXSourcesBuildPhase;
+ buildActionMask = 2147483647;
+ files = (
+ 8A878FE02BA93CF1008C7F26 /* Datas.swift in Sources */,
+ 8A34B92B2BA2D446000F66BD /* BaseViewController.swift in Sources */,
+ 8A76B6092BA84C2B0016F2AB /* AbilityViewController.swift in Sources */,
+ 8A34B9272BA2AB66000F66BD /* ConnectViewController.swift in Sources */,
+ 8A1DFF562B9EB4F800B735FF /* ViewController.swift in Sources */,
+ 8A1DFF522B9EB4F800B735FF /* AppDelegate.swift in Sources */,
+ 8A34B9292BA2AB86000F66BD /* LogViewController.swift in Sources */,
+ );
+ runOnlyForDeploymentPostprocessing = 0;
+ };
+/* End PBXSourcesBuildPhase section */
+
+/* Begin PBXTargetDependency section */
+ 8A9F6AC52BA05CB500DA520F /* PBXTargetDependency */ = {
+ isa = PBXTargetDependency;
+ target = 8A0A39BA2B980BEF006A3B18 /* IOTBluetooth */;
+ targetProxy = 8A9F6AC42BA05CB500DA520F /* PBXContainerItemProxy */;
+ };
+/* End PBXTargetDependency section */
+
+/* Begin PBXVariantGroup section */
+ 8A1DFF572B9EB4F900B735FF /* Main.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 8A1DFF582B9EB4F900B735FF /* Base */,
+ );
+ name = Main.storyboard;
+ sourceTree = "";
+ };
+ 8A1DFF5C2B9EB4F900B735FF /* LaunchScreen.storyboard */ = {
+ isa = PBXVariantGroup;
+ children = (
+ 8A1DFF5D2B9EB4F900B735FF /* Base */,
+ );
+ name = LaunchScreen.storyboard;
+ sourceTree = "";
+ };
+/* End PBXVariantGroup section */
+
+/* Begin XCBuildConfiguration section */
+ 8A0A39C02B980BEF006A3B18 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = dwarf;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_TESTABILITY = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_DYNAMIC_NO_PIC = NO;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_OPTIMIZATION_LEVEL = 0;
+ GCC_PREPROCESSOR_DEFINITIONS = (
+ "DEBUG=1",
+ "$(inherited)",
+ );
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.5;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
+ MTL_FAST_MATH = YES;
+ ONLY_ACTIVE_ARCH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_ACTIVE_COMPILATION_CONDITIONS = "DEBUG $(inherited)";
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Debug;
+ };
+ 8A0A39C12B980BEF006A3B18 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ALWAYS_SEARCH_USER_PATHS = NO;
+ ASSETCATALOG_COMPILER_GENERATE_SWIFT_ASSET_SYMBOL_EXTENSIONS = YES;
+ CLANG_ANALYZER_NONNULL = YES;
+ CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
+ CLANG_CXX_LANGUAGE_STANDARD = "gnu++20";
+ CLANG_ENABLE_MODULES = YES;
+ CLANG_ENABLE_OBJC_ARC = YES;
+ CLANG_ENABLE_OBJC_WEAK = YES;
+ CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
+ CLANG_WARN_BOOL_CONVERSION = YES;
+ CLANG_WARN_COMMA = YES;
+ CLANG_WARN_CONSTANT_CONVERSION = YES;
+ CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
+ CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
+ CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
+ CLANG_WARN_EMPTY_BODY = YES;
+ CLANG_WARN_ENUM_CONVERSION = YES;
+ CLANG_WARN_INFINITE_RECURSION = YES;
+ CLANG_WARN_INT_CONVERSION = YES;
+ CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
+ CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
+ CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
+ CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
+ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
+ CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
+ CLANG_WARN_STRICT_PROTOTYPES = YES;
+ CLANG_WARN_SUSPICIOUS_MOVE = YES;
+ CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
+ CLANG_WARN_UNREACHABLE_CODE = YES;
+ CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
+ COPY_PHASE_STRIP = NO;
+ CURRENT_PROJECT_VERSION = 1;
+ DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
+ ENABLE_NS_ASSERTIONS = NO;
+ ENABLE_STRICT_OBJC_MSGSEND = YES;
+ ENABLE_USER_SCRIPT_SANDBOXING = YES;
+ GCC_C_LANGUAGE_STANDARD = gnu17;
+ GCC_NO_COMMON_BLOCKS = YES;
+ GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
+ GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
+ GCC_WARN_UNDECLARED_SELECTOR = YES;
+ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
+ GCC_WARN_UNUSED_FUNCTION = YES;
+ GCC_WARN_UNUSED_VARIABLE = YES;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.5;
+ LOCALIZATION_PREFERS_STRING_CATALOGS = YES;
+ MTL_ENABLE_DEBUG_INFO = NO;
+ MTL_FAST_MATH = YES;
+ SDKROOT = iphoneos;
+ SWIFT_COMPILATION_MODE = wholemodule;
+ VALIDATE_PRODUCT = YES;
+ VERSIONING_SYSTEM = "apple-generic";
+ VERSION_INFO_PREFIX = "";
+ };
+ name = Release;
+ };
+ 8A0A39C32B980BEF006A3B18 /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = M33X987285;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ PRODUCT_BUNDLE_IDENTIFIER = com.thisiot.IOTBluetooth;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_OPTIMIZATION_LEVEL = "-Onone";
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 1;
+ };
+ name = Debug;
+ };
+ 8A0A39C42B980BEF006A3B18 /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ CLANG_ENABLE_MODULES = YES;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1;
+ DEFINES_MODULE = YES;
+ DEVELOPMENT_TEAM = M33X987285;
+ DYLIB_COMPATIBILITY_VERSION = 1;
+ DYLIB_CURRENT_VERSION = 1;
+ DYLIB_INSTALL_NAME_BASE = "@rpath";
+ ENABLE_MODULE_VERIFIER = YES;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_KEY_NSHumanReadableCopyright = "";
+ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ "@loader_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0;
+ MODULE_VERIFIER_SUPPORTED_LANGUAGES = "objective-c objective-c++";
+ MODULE_VERIFIER_SUPPORTED_LANGUAGE_STANDARDS = "gnu17 gnu++20";
+ PRODUCT_BUNDLE_IDENTIFIER = com.thisiot.IOTBluetooth;
+ PRODUCT_NAME = "$(TARGET_NAME:c99extidentifier)";
+ SKIP_INSTALL = YES;
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SUPPORTS_MAC_DESIGNED_FOR_IPHONE_IPAD = YES;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 1;
+ };
+ name = Release;
+ };
+ 8A1DFF602B9EB4F900B735FF /* Debug */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1001;
+ DEVELOPMENT_TEAM = M33X987285;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = Example/Info.plist;
+ INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "æ«ææºè½æè¡¨éè¦å¼å¯èçåè½";
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+ INFOPLIST_KEY_UIMainStoryboardFile = Main;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+ INFOPLIST_KEY_UIUserInterfaceStyle = Light;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.5;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.thisiot.IOTBluetooth.Example;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 1;
+ };
+ name = Debug;
+ };
+ 8A1DFF612B9EB4F900B735FF /* Release */ = {
+ isa = XCBuildConfiguration;
+ buildSettings = {
+ ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
+ ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
+ CODE_SIGN_STYLE = Automatic;
+ CURRENT_PROJECT_VERSION = 1001;
+ DEVELOPMENT_TEAM = M33X987285;
+ GENERATE_INFOPLIST_FILE = YES;
+ INFOPLIST_FILE = Example/Info.plist;
+ INFOPLIST_KEY_NSBluetoothAlwaysUsageDescription = "æ«ææºè½æè¡¨éè¦å¼å¯èçåè½";
+ INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents = YES;
+ INFOPLIST_KEY_UILaunchStoryboardName = LaunchScreen;
+ INFOPLIST_KEY_UIMainStoryboardFile = Main;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations = UIInterfaceOrientationPortrait;
+ INFOPLIST_KEY_UISupportedInterfaceOrientations_iPad = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight UIInterfaceOrientationPortrait UIInterfaceOrientationPortraitUpsideDown";
+ INFOPLIST_KEY_UIUserInterfaceStyle = Light;
+ IPHONEOS_DEPLOYMENT_TARGET = 13.5;
+ LD_RUNPATH_SEARCH_PATHS = (
+ "$(inherited)",
+ "@executable_path/Frameworks",
+ );
+ MARKETING_VERSION = 1.0.0;
+ PRODUCT_BUNDLE_IDENTIFIER = com.thisiot.IOTBluetooth.Example;
+ PRODUCT_NAME = "$(TARGET_NAME)";
+ SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
+ SUPPORTS_MACCATALYST = NO;
+ SWIFT_EMIT_LOC_STRINGS = YES;
+ SWIFT_VERSION = 5.0;
+ TARGETED_DEVICE_FAMILY = 1;
+ };
+ name = Release;
+ };
+/* End XCBuildConfiguration section */
+
+/* Begin XCConfigurationList section */
+ 8A0A39B52B980BEF006A3B18 /* Build configuration list for PBXProject "IOTBluetooth" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8A0A39C02B980BEF006A3B18 /* Debug */,
+ 8A0A39C12B980BEF006A3B18 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 8A0A39C22B980BEF006A3B18 /* Build configuration list for PBXNativeTarget "IOTBluetooth" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8A0A39C32B980BEF006A3B18 /* Debug */,
+ 8A0A39C42B980BEF006A3B18 /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+ 8A1DFF622B9EB4F900B735FF /* Build configuration list for PBXNativeTarget "Example" */ = {
+ isa = XCConfigurationList;
+ buildConfigurations = (
+ 8A1DFF602B9EB4F900B735FF /* Debug */,
+ 8A1DFF612B9EB4F900B735FF /* Release */,
+ );
+ defaultConfigurationIsVisible = 0;
+ defaultConfigurationName = Release;
+ };
+/* End XCConfigurationList section */
+ };
+ rootObject = 8A0A39B22B980BEF006A3B18 /* Project object */;
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/contents.xcworkspacedata
new file mode 100644
index 0000000..919434a
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/contents.xcworkspacedata
@@ -0,0 +1,7 @@
+
+
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
new file mode 100644
index 0000000..18d9810
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist
@@ -0,0 +1,8 @@
+
+
+
+
+ IDEDidComputeMac32BitWarning
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/IDEFindNavigatorScopes.plist b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/IDEFindNavigatorScopes.plist
new file mode 100644
index 0000000..5dd5da8
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/IDEFindNavigatorScopes.plist
@@ -0,0 +1,5 @@
+
+
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate
new file mode 100644
index 0000000..943a344
Binary files /dev/null and b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/project.xcworkspace/xcuserdata/apple.xcuserdatad/UserInterfaceState.xcuserstate differ
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcshareddata/xcschemes/IOTBluetooth.xcscheme b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcshareddata/xcschemes/IOTBluetooth.xcscheme
new file mode 100644
index 0000000..7630f1c
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcshareddata/xcschemes/IOTBluetooth.xcscheme
@@ -0,0 +1,66 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/apple.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/apple.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
new file mode 100644
index 0000000..c296514
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/apple.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist
@@ -0,0 +1,6 @@
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..d0682b2
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/apple.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,27 @@
+
+
+
+
+ SchemeUserState
+
+ Example.xcscheme_^#shared#^_
+
+ orderHint
+ 1
+
+ IOTBluetooth.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+
+ SuppressBuildableAutocreation
+
+ 8A0A39BA2B980BEF006A3B18
+
+ primary
+
+
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/williamtrillgates.xcuserdatad/xcschemes/xcschememanagement.plist b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/williamtrillgates.xcuserdatad/xcschemes/xcschememanagement.plist
new file mode 100644
index 0000000..8d574d1
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth.xcodeproj/xcuserdata/williamtrillgates.xcuserdatad/xcschemes/xcschememanagement.plist
@@ -0,0 +1,19 @@
+
+
+
+
+ SchemeUserState
+
+ Example.xcscheme_^#shared#^_
+
+ orderHint
+ 1
+
+ IOTBluetooth.xcscheme_^#shared#^_
+
+ orderHint
+ 0
+
+
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBAbility.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBAbility.swift
new file mode 100644
index 0000000..655ac55
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBAbility.swift
@@ -0,0 +1,505 @@
+//
+// IBAbility.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/13.
+//
+
+import Foundation
+
+/// åè½æä»¤
+public class IBAbility {
+
+ /// å½ä»¤ç±»å
+ let type: `Type`
+
+ /// å½ä»¤ID
+ private(set) var id: UInt8 = 0x0
+
+ /// æå®è§£æå¨
+ private(set) var parser: IBParser.Type!
+
+ /// æå®åæ°æ£æ¥å¨
+ private(set) var checker: IBChecker.Type!
+
+ /// æå¡ç¹å¾
+ private(set) var characteristicUUID: String!
+
+ private init(_ type: `Type`) {
+ self.type = type
+ }
+
+ private func id(_ value: UInt8) -> Self {
+ self.id = value
+ return self
+ }
+
+ private func parser(_ parser: T.Type) -> Self {
+ self.parser = parser
+ return self
+ }
+
+ private func checker(_ checker: T.Type) -> Self {
+ self.checker = checker
+ return self
+ }
+
+ private func characteristic(_ uuid: String) -> Self {
+ characteristicUUID = uuid
+ return self
+ }
+
+ /// çæä»¤(ä¸å¤§äº20个åè)
+ private static var short: IBAbility { IBAbility(.short).characteristic(writeCharacteristicUUID) }
+ /// é¿æä»¤(大äº20个åè)
+ private static var long: IBAbility { IBAbility(.long).characteristic(writeBigCharacteristicUUID) }
+ /// æä»¶æä»¤(ç¨æ¥åéæä»¶ï¼æ¯å¦è¡¨çãMP3ãOTAç)
+ private static var file: IBAbility { IBAbility(.file).characteristic(writeFileCharacteristicUUID) }
+
+ public var description: String { "[\(String(format: "0x%02X, 0x%02X", type.rawValue, id))] \(characteristicUUID!)" }
+
+ func isAnswer(_ data: Data) -> Bool {
+ let answerTypeValue = data.bytes[1]
+ let answerID = data.bytes[2]
+
+ return type.rawValue == answerTypeValue && id == answerID
+ }
+}
+
+extension IBAbility {
+ enum `Type`: UInt8 {
+ /// çæä»¤
+ case short = 0x01
+ /// é¿æä»¤
+ case long = 0x02
+ /// æä»¶æä»¤(ç¨æ¥åéæä»¶ï¼æ¯å¦è¡¨çãMP3ãOTAç)
+ case file = 0x04
+ }
+}
+
+public extension IBAbility {
+ /// è®¾ç½®ç¨æ·æ°æ®
+ /// - Parameter userInfo: see ``IBUserInfo``
+ static let userData = IBAbility.long.id(0x01).parser(IBGeneralParser.self).checker(IBUserInfoChecker.self)
+
+ /// å
³äºæ¬æºå
容
+ static let about = IBAbility.short.id(0x03).parser(IBAblutParser.self)
+
+ /// åæ¢è¡¨ç
+ /// - Parameter dialID:Int
+ /// 表çid
+ static let switchDial = IBAbility.short.id(0x02).parser(IBSwitchDialParser.self).checker(IBSwitchDialChecker.self)
+
+ /// APPå é¤è¡¨ç
+ /// - Parameter dialID:Int \
+ /// 表çid
+ static let deleteDial = IBAbility.short.id(0x1B).parser(IBGeneralParser.self).checker(IBSwitchDialChecker.self)
+
+ /// åéå½å表çID
+ /// - Returns: Int \
+ /// Read from ``IBResponse``.value
+ static let fetchCurrentDialId = IBAbility.short.id(0x17).parser(IBFetchCurrentDialParser.self)
+
+ /// æ¥æ¾æè¡¨
+ /// - Parameter action:
+ /// 0 = åæ¢æ¥æ¾ \
+ /// 1 = å¼å§æ¥æ¾
+ static let find = IBAbility.short.id(0x04).parser(IBFindParser.self).checker(IBActionChecker.self)
+
+ /// å¼å
³æ¶æ¯æ¨éåè½
+ /// - Parameter action:
+ /// 0 = å
³éæ¶æ¯ \
+ /// 1 = å¼å¯æ¶æ¯
+ static let message = IBAbility.short.id(0x08).parser(IBGeneralParser.self).checker(IBActionChecker.self)
+
+ /// å¼å¯æå®è¿å¨æ¨¡å¼
+ /// - Parameter motionMode: see ``IBMotionMode``
+ static let startSport = IBAbility.short.id(0x0A).parser(IBGeneralParser.self).checker(IBSportChecker.self)
+
+ /// ç»æè¿å¨æ¨¡å¼
+ static let endSport = IBAbility.short.id(0x0B).parser(IBGeneralParser.self)
+
+ /// 设置è®ç»å®æ¶æ°æ®éæ ·é¢ç
+ /// - Parameter value:Int \
+ /// åä½(ç§)
+ static let trainFrequency = IBAbility.short.id(0x14).parser(IBGeneralParser.self).checker(IBTrainFrequencyChecker.self)
+
+ /// è®ç»æå/æ¢å¤
+ /// - Parameter action:
+ /// 0 = æå \
+ /// 1 = æ¢å¤
+ static let trainPauseResume = IBAbility.short.id(0x16).parser(IBGeneralParser.self).checker(IBActionChecker.self)
+
+ /// 设置è¯è¨
+ /// - Parameter language: see ``IBLanguage``
+ static let language = IBAbility.short.id(0x0E).parser(IBGeneralParser.self).checker(IBLanguageChecker.self)
+
+ /// è·åæè¡¨å¿çåæ°
+ /// - Returns: ``IBHeartRate`` \
+ /// Read from ``IBResponse``.value
+ static let fetchHeartRate = IBAbility.short.id(0x1E).parser(IBHeartRateParser.self)
+
+ /// 设置æè¡¨å¿çåæ°
+ /// - Parameter heartRate: see ``IBHeartRate``
+ static let heartRate = IBAbility.long.id(0x12).parser(IBGeneralParser.self).checker(IBHeartRateChecker.self)
+
+ /// è·åæè¡¨è¡æ°§è®¾ç½®
+ /// - Returns: ``IBBloodOxygen`` \
+ /// Read from ``IBResponse``.value
+ static let fetchBloodOxygen = IBAbility.short.id(0x1F).parser(IBBloodOxygenParser.self)
+
+ /// 设置æè¡¨è¡æ°§åæ°
+ /// - Parameter heartRate: see ``IBBloodOxygen``
+ static let bloodOxygen = IBAbility.long.id(0x13).parser(IBGeneralParser.self).checker(IBBloodOxygenChecker.self)
+
+ /// è·å宿¶å¿ç(宿¶è®ç»æ°æ®)
+ /// - Returns: ``IBTrainingData`` \
+ /// Read from ``IBResponse``.value
+ static let currentHeartRate = IBAbility.short.id(0x0F).parser(IBTrainingDataParser.self)
+
+ /// å¼å¯/å
³éèªå¨è·å宿¶å¿ç
+ /// - Parameter action:
+ /// 0 = å
³éèªå¨è·å \
+ /// 1 = å¼å¯èªå¨è·å
+ static let heartRateMode = IBAbility.short.id(0x11).parser(IBGeneralParser.self).checker(IBActionChecker.self)
+
+ /// 设置æé«å¿çæé
+ /// - Parameter value:Int \
+ /// æé«ä¸è¶
è¿ 250 ,妿éè¦å
³éæé«å¿çæéï¼å¯å°æé«å¿ç设为255ï¼å¼å¯å设æ£å¸¸å¼å³å¯ã
+ static let heartRateHigh = IBAbility.short.id(0x15).parser(IBGeneralParser.self).checker(IBHeartRateHighChecker.self)
+
+ /// æå¿æç
§
+ /// - Parameter action:
+ /// 0 = éåºæå¿æç
§ \
+ /// 1 = è¿å
¥æå¿æç
§
+ static let takePhoto = IBAbility.short.id(0x23).parser(IBTakePhotoParser.self).checker(IBActionChecker.self)
+
+ /// æ¢å¤åºå设置
+ static let restore = IBAbility.short.id(0x25).parser(IBGeneralParser.self)
+
+ /// éæ°å¯å¨
+ static let reboot = IBAbility.short.id(0x26).parser(IBGeneralParser.self)
+
+ /// å
³æº
+ static let shutdown = IBAbility.short.id(0x27).parser(IBGeneralParser.self)
+
+ /// è·åæè¡¨çµæ± çµéã
+ /// - Returns: Int \
+ /// Read from ``IBResponse``.value
+ static let fetchBattery = IBAbility.short.id(0x07).parser(IBBatteryParser.self)
+
+ /// è·åé¹é设置
+ /// - Returns: ``[IBClockInfo]`` \
+ /// Read from ``IBResponse``.items
+ static let fetchClock = IBAbility.short.id(0x01).parser(IBClockParser.self)
+
+ /// åéé¹é设置
+ /// - Parameter clock: see ``IBClock``
+ static let setClock = IBAbility.long.id(0x21).parser(IBSetClockParser.self).checker(IBClockChecker.self)
+
+ /// è·åææè¡¨çUID
+ /// - Returns: [Int] \
+ /// Read from ``IBResponse``.items
+ static let fetchDials = IBAbility.short.id(0x2A).parser(IBFetchDialsParser.self)
+
+ /// APPè·åæè¡¨çIDæ¯å¦å·²å®è£
+ /// - Parameter value:Int
+ /// - Returns: Int
+ /// 0 = æªå®è£
\
+ /// 1 = å·²å®è£
\
+ /// Read from ``IBResponse``.value
+ static let checkDialID = IBAbility.long.id(0x0D).parser(IBCheckDialParser.self).checker(IBSwitchDialChecker.self)
+
+ /// è·åå½åæè¡¨ç¶æ
+ /// - Returns: Int \
+ /// 0 = 空é²ç¶æ \
+ /// 9 = USBåå¨ç¶æ \
+ /// 10 = è¿å¨è®ç»ç¶æ \
+ /// Read from ``IBResponse``.value
+ static let fetchWatchState = IBAbility.short.id(0x19).parser(IBWatchStateParser.self)
+
+ /// è·åæè¡¨å±å¹åæ°
+ /// - Returns: ``IBScreen`` \
+ /// Read from ``IBResponse``.value
+ static let fetchScreen = IBAbility.short.id(0x1A).parser(IBScreenParser.self)
+
+ /// 设置æè¡¨å±å¹åæ°
+ /// - Parameter screen: see ``screen``
+ static let screen = IBAbility.long.id(0x0E).parser(IBGeneralParser.self).checker(IBScreenChecker.self)
+
+ /// è·åæè¡¨å£°é³ä¸éå¨åæ°
+ /// - Returns: ``IBVibrateSound`` \
+ /// Read from ``IBResponse``.value
+ static let fetchVibrateSound = IBAbility.short.id(0x1C).parser(IBVibrateSoundParser.self)
+
+ /// APP设置æè¡¨å£°é³ä¸éå¨åæ°
+ /// - Parameter vibrateSound: see ``IBVibrateSound``
+ static let vibrateSound = IBAbility.long.id(0x0F).parser(IBGeneralParser.self).checker(IBVibrateSoundChecker.self)
+
+
+ /// 设置æè¡¨è¾
å©åè½åæ°
+ /// - Parameter auxiliary: see ``IBAuxiliary``
+ static let auxiliary = IBAbility.long.id(0x11).parser(IBGeneralParser.self).checker(IBAuxiliaryChecker.self)
+
+ /// è·åæè¡¨è¾
å©åè½åæ°
+ /// - Returns: IBAuxiliary \
+ /// Read from ``IBResponse``.value
+ static let fetchAuxiliary = IBAbility.short.id(0x1D).parser(IBFetchAuxiliaryParser.self)
+
+ /// è·åç®æ æ¥æ°è®¾ç½®
+ /// - Returns: ``IBTargetStep`` \
+ /// Read from ``IBResponse``.value
+ static let fetchTargetStep = IBAbility.short.id(0x2B).parser(IBTargetStepParser.self)
+
+ /// è®¾ç½®ç®æ æ¥æ°
+ /// - Parameter targetStep: see ``IBTrainTarget``
+ static let targetStep = IBAbility.long.id(0x16).parser(IBGeneralParser.self).checker(IBTargetStepChecker.self)
+
+ /// è·åå
¶ä»ç®æ 设置
+ /// - Returns: ``IBOtherTarget`` \
+ /// Read from ``IBResponse``.value
+ static let fetchOtherTarget = IBAbility.short.id(0x2C).parser(IBOtherTargetParser.self)
+
+ /// 设置å
¶ä»ç®æ
+ /// - Parameter targetOther: see ``IBOtherTarget``
+ static let targetOther = IBAbility.long.id(0x17).parser(IBGeneralParser.self).checker(IBOtherTargetChecker.self)
+
+ /// è·åç¡ç 设置
+ /// - Returns: ``IBSleep`` \
+ /// Read from ``IBResponse``.value
+ static let fetchSleep = IBAbility.short.id(0x29).parser(IBSleepParser.self)
+
+ /// 设置ç¡ç
+ /// - Parameter sleep: see ``IBSleep``
+ static let sleep = IBAbility.long.id(0x15).parser(IBGeneralParser.self).checker(IBSleepChecker.self)
+
+ /// è·åæè¡¨åæ°´æé设置
+ /// - Returns: Int \
+ /// 0 = å
³é \
+ /// 1 = å¼å¯ \
+ /// Read from ``IBResponse``.value
+ static let fetchWater = IBAbility.short.id(0x24).parser(IBWaterParser.self)
+
+ /// è®¾ç½®åæ°´æé
+ /// - Parameter water: see ``IBWater``
+ static let water = IBAbility.long.id(0x14).parser(IBGeneralParser.self).checker(IBWaterChecker.self)
+
+ /// 设置æè¡¨å
¬è±å¶åä½
+ /// - Parameter value:Int \
+ /// 0 = å
¬å¶ \
+ /// 1 = è±å¶
+ static let unit = IBAbility.short.id(0x28).parser(IBGeneralParser.self).checker(IBValueChecker.self)
+
+ /// 设置è®ç»ç®æ
+ /// - Parameter trainTargetï¼see ``IBTrainTarget``
+ static let trainTarget = IBAbility.long.id(0x04).parser(IBGeneralParser.self).checker(IBTrainTargetChecker.self)
+
+ // MARK: - åæ¥æ°æ®
+ /// 忥å¿çå岿°æ®
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistoryHeartRateItem] \
+ /// Read from ``IBResponse``.items
+ static let syncHeartRate = IBAbility.short.id(0x40).parser(IBSyncHeartRateParser.self).checker(IBValueChecker.self)
+
+ /// åæ¥è¡æ°§å岿°æ®
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistoryBloodOxygenItem] \
+ /// Read from ``IBResponse``.items
+ static let syncBloodOxygen = IBAbility.short.id(0x41).parser(IBSyncBloodOxygenParser.self).checker(IBValueChecker.self)
+
+ /// 忥å岿¥æ°
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistoryStepItem] \
+ /// Read from ``IBResponse``.items
+ static let syncStepCount = IBAbility.short.id(0x43).parser(IBSyncStepParser.self).checker(IBValueChecker.self)
+
+ /// 忥çèæ¶é´å岿°æ®
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistoryBurningItem] \
+ /// Read from ``IBResponse``.items
+ static let syncFatBurning = IBAbility.short.id(0x44).parser(IBSyncBurningParser.self).checker(IBValueChecker.self)
+
+ /// 忥ç«ç«å岿°æ®
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistoryStandItem] \
+ /// Read from ``IBResponse``.items
+ static let syncStand = IBAbility.short.id(0x45).parser(IBSyncStandParser.self).checker(IBValueChecker.self)
+
+ /// 忥å¡è·¯éå岿°æ®
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistoryCalorieItem] \
+ /// Read from ``IBResponse``.items
+ static let syncCalorie = IBAbility.short.id(0x46).parser(IBSyncCalorieParser.self).checker(IBValueChecker.self)
+
+ /// 忥è·ç¦»å岿°æ®
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistoryDistanceItem] \
+ /// Read from ``IBResponse``.items
+ static let syncDistance = IBAbility.short.id(0x47).parser(IBSyncDistanceParser.self).checker(IBValueChecker.self)
+
+ /// 忥åºç¡è®ç»å岿°æ®
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistoryBaseTrainingItem] \
+ /// Read from ``IBResponse``.items
+ static let syncTrain = IBAbility.short.id(0x49).parser(IBSyncTrainParser.self).checker(IBValueChecker.self)
+
+ /// 忥ç¡ç å岿°æ®
+ /// - Parameter value:
+ /// 0 = ä»å¤© \
+ /// 1 = å1天 \
+ /// 2 = å2天 \
+ /// 3 = å3天 \
+ /// 便¤ç±»æ¨ï¼åå¼èå´0~29ã
+ /// - Returns: [IBHistorySleepItem] \
+ /// Read from ``IBResponse``.items
+ static let syncSleep = IBAbility.short.id(0x4B).parser(IBSyncSleepParser.self).checker(IBValueChecker.self)
+
+ /// åæ¥è·¯å¾åæ éå岿°æ®
+ /// - Parameter value:å¼å§è®ç»æ¶é´æ³
+ /// - Returns: [IBHistoryGpsItem] \
+ /// Read from ``IBResponse``.items
+ static let syncGPS = IBAbility.long.id(0x4F).parser(IBSyncGpsParser.self).checker(IBSyncGpsChecker.self)
+
+ /// åéåæ¥æ°æ®ç»ææ¶æ¯
+ static let sendSyncEnd = IBAbility.short.id(0x2E).parser(IBGeneralParser.self)
+
+ /// è·åSDå¡å©ä½ç©ºé´
+ /// - Returns: Int \
+ /// Read from ``IBResponse``.value
+ static let disk = IBAbility.short.id(0x05).parser(IBDiskParser.self)
+
+ /// åéææºä¿¡æ¯
+ /// - Returns: Int \
+ /// 0 = æä»¤æ ¡éªå¤±è´¥ \
+ /// 1 = æè¡¨æªä¸ä»»ä½ææºç»å® \
+ /// 2 = æè¡¨å·²ä¸è¯¥ææºç»å® \
+ /// 3 = æè¡¨å·²ä¸å
¶ä»ææºç»å® \
+ /// Read from ``IBResponse``.value
+ static let sendPhone = IBAbility.long.id(0x10).parser(IBSendPhoneParser.self).checker(IBSendPhoneChecker.self)
+
+ /// åéå½åæ¶é´
+ /// - Parameter sendTime: see ``IBSendTime``
+ static let sendTime = IBAbility.long.id(0x02).parser(IBGeneralParser.self).checker(IBSendTimeChecker.self)
+
+ /// åéè§£é¤é
å¯¹æ¶æ¯
+ static let unpair = IBAbility.short.id(0x10).parser(IBGeneralParser.self)
+
+ /// åéåæ¶è§£é¤é
å¯¹æ¶æ¯
+ static let sendUnpair = IBAbility.short.id(0x2D).parser(IBGeneralParser.self)
+
+ /// åéå¤©æ°æ°æ®
+ /// - Parameter weather: see ``IBWeather``
+ static let sendWeather = IBAbility.long.id(0x20).parser(IBGeneralParser.self).checker(IBWeatherChecker.self)
+
+ /// APPåéé讯å½
+ /// - Parameter addressBook: see ``IBAddressBook``
+ /// 0~20
+ static let addressBook = IBAbility.long.id(0x0B).parser(IBGeneralParser.self).checker(IBAddressBookChecker.self)
+
+// /// æ¤éå½åæä»¶ä¼ è¾
+// static let revokeFileSend = IBAbility.short.id(0x20).parser(IBGeneralParser.self).checker(IBFileChecker.self)
+// /// è·åæå®ç±»åæææä»¶(å½ååªæ¯æ MP3 å 表ç)
+// static let fetchFiles = IBAbility.short.id(0x21).parser(IBGeneralParser.self).checker(IBFileChecker.self)
+// /// å 餿å®ç±»åæææä»¶(å½ååªæ¯æ MP3 å 表ç)
+// static let deleteFiles = IBAbility.short.id(0x22).parser(IBGeneralParser.self).checker(IBFileChecker.self)
+//
+//
+}
+
+extension IBAbility {
+
+
+//
+// // MARK: - Fetch è·åæ°æ®
+
+// /// æ¤éå½åæä»¶ä¼ è¾
+// static let revokeFileTransfer = IBAbility.short.id(0x20)
+
+// /// å é¤æå®æä»¶ï¼æ°æ®å
为æä»¶ç´¢å¼å·ï¼
+// static let deleteFile = IBAbility.long.id(0x22)
+
+
+//
+//
+// /// åéOTAæä»¶ä¿¡æ¯
+// static let ota = IBAbility.file.id(0x20)
+// /// åéMP3æä»¶ä¿¡æ¯
+// static let mp3 = IBAbility.file.id(0x21)
+// /// åé表çæä»¶ä¿¡æ¯
+// static let dial = IBAbility.file.id(0x22)
+// /// APPåéæä»¶æ ¡éªç
+// static let fileCheckCode = IBAbility.file.id(0x23)
+// ///  åéå个表çæä»¶ä¿¡æ¯
+// static let dialInfo = IBAbility.file.id(0x24)
+// /// åéEPOæä»¶ä¿¡æ¯ï¼04,25ï¼
+// static let epo = IBAbility.file.id(0x28)
+//
+//
+// // MARK: - ç§æ
+
+//
+// /// è·åå½åæ°æ®ï¼jSONæ ¼å¼ï¼ãä¸ä½¿ç¨ã
+// static let var681B9E92 = IBAbility.short.id(0x06)
+// /// å¼å
³å¤åªä½åè½ï¼ææ¾ææºé³ä¹ãéè¯çï¼ãä¸ä½¿ç¨ã
+// static let var681254AC = IBAbility.short.id(0x09)
+// /// è¿å
¥å·¥åæµè¯æ¨¡å¼ãä¸ä½¿ç¨ã
+// static let varD3D21DC8 = IBAbility.short.id(0x30)
+// /// 忥ååå岿°æ®ãä¸ä½¿ç¨ã
+// static let varA2A25CD8 = IBAbility.short.id(0x42)
+//
+// /// ä¿®æ¹æè¡¨èçåç§°ãæªä½¿ç¨ã
+// static let var8FA46D73 = IBAbility.long.id(0x03)
+// /// 忥åºç¡è®ç»å®æ¶å¿çè®°å½ãä¸ä½¿ç¨ã
+// static let var6CFBF636 = IBAbility.long.id(0x4B)
+// /// 忥å½å¤©ä»»ææ¶é´ä¹åçåºç¡è®ç»è®°å½ãä¸ä½¿ç¨ã
+// static let var4D0264A9 = IBAbility.long.id(0x4D)
+// /// APPåéé¶å¿çåºé´å¼ç»æè¡¨ï¼æä¸ç¨ï¼
+// static let var7EE39B21 = IBAbility.long.id(0x0C)
+//
+// /// å鿍¡åå级信æ¯ï¼04,26ï¼ãä¸ä½¿ç¨ã
+// static let var1FFA68BC = IBAbility.file.id(0x26)
+// ///  å鿍¡åå个æä»¶å级信æ¯ï¼04,27ï¼ãä¸ä½¿ç¨ã
+// static let var9AD723C3 = IBAbility.file.id(0x27)
+// /// åéEPOæä»¶ä¿¡æ¯ï¼04,25ï¼ï¼æ§çï¼ä¸ç¨ï¼
+// static let var4F791698 = IBAbility.file.id(0x25)
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBChecker.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBChecker.swift
new file mode 100644
index 0000000..43f0f55
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBChecker.swift
@@ -0,0 +1,291 @@
+//
+// IBChecker.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/19.
+//
+
+import Foundation
+
+/// åæ°æ£æ¥å¨åè®®
+protocol IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8]
+}
+
+extension Array where Element == IBParameter {
+ subscript(_ key: IBKey) -> Element? {
+ self.filter({ $0.key == key }).first
+ }
+}
+
+struct IBSwitchDialChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .dialID(dailID) = parameters[.dialID] else { fatalError("缺å°åæ°: dialID") }
+ Logger.log(dailID)
+ return dailID.byte2
+ }
+}
+
+struct IBActionChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .action(action) = parameters[.action] else { fatalError("缺å°åæ°: action") }
+ Logger.log(action)
+ return [action.byte]
+ }
+}
+
+struct IBSportChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .motionMode(mode) = parameters[.motionMode] else { fatalError("缺å°åæ°: motionMode") }
+ Logger.log(mode)
+ return [mode.rawValue.byte]
+ }
+}
+
+struct IBLanguageChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .language(value) = parameters[.language] else { fatalError("缺å°åæ°: language") }
+ Logger.log(value)
+ return [value.rawValue.byte]
+ }
+}
+struct IBAuxiliaryChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .auxiliary(value) = parameters[.auxiliary] else { fatalError("缺å°åæ°: auxiliary") }
+ Logger.log(value)
+ return [value.rawValue.byte]
+ }
+}
+struct IBValueChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .value(value) = parameters[.value] else { fatalError("缺å°åæ°: value") }
+ Logger.log(value)
+ return [value.byte]
+ }
+}
+
+struct IBHeartRateHighChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .value(value) = parameters[.value] else { fatalError("缺å°åæ°: value") }
+ Logger.log(value)
+ return [(value == 0 ? 255 : value).byte]
+ }
+}
+
+struct IBTrainFrequencyChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .value(value) = parameters[.value] else { fatalError("缺å°åæ°: value") }
+ Logger.log(value)
+ return value.byte2
+ }
+}
+
+struct IBSyncGpsChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .value(value) = parameters[.value] else { fatalError("缺å°åæ°: value") }
+ Logger.log(value)
+ return value.byte4
+ }
+}
+
+struct IBFileChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .file(value) = parameters[.file] else { fatalError("缺å°åæ°: file") }
+ Logger.log(value)
+ return [value.rawValue.byte]
+ }
+}
+
+struct IBTargetStepChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .targetStep(value) = parameters[.targetStep] else { fatalError("缺å°åæ°: targetStep") }
+ Logger.log(value.description)
+ return value.value.byte4 + [value.ring.byte] + [value.vibrate.byte] + [value.notice.byte]
+ }
+}
+
+struct IBSleepChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .sleep(value) = parameters[.sleep] else { fatalError("缺å°åæ°: sleep") }
+ Logger.log(value.description)
+ if value.sleepTimeSet == 1,let sleep = value.sleepTime,let getUp = value.getUpTime {
+ return [value.sleepTimeSet.byte] + [sleep.hour.byte] + [sleep.minute.byte] + [getUp.hour.byte] + [getUp.minute.byte] + [value.alertBeforeMin20.byte]
+ }
+ return [value.sleepTimeSet.byte]
+ }
+}
+struct IBWaterChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .water(value) = parameters[.water] else { fatalError("缺å°åæ°: water") }
+ Logger.log(value.description)
+
+ var data = [value.alertState.byte]
+ if value.alertState == 1 {
+ data = data + [value.alertType.byte] + value.drinkingValue.byte2 + [value.start.hour.byte] + [value.start.minute.byte]
+ }
+ if value.alertType == 1 {
+ data = data + [value.end.hour.byte] + [value.end.minute.byte] + [value.frequency.rawValue.byte]
+ }
+ return data
+ }
+}
+
+struct IBHeartRateChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .heartRate(value) = parameters[.heartRate] else { fatalError("缺å°åæ°: heartRate") }
+ Logger.log(value.description)
+ var data = [value.rate.rawValue.byte] + [value.state.byte]
+ if value.state == 1 {
+ data = data + [value.higherOrLower.byte] + [value.value.byte]
+ }
+ return data
+ }
+}
+struct IBBloodOxygenChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .bloodOxygen(value) = parameters[.bloodOxygen] else { fatalError("缺å°åæ°: heartRate") }
+ Logger.log(value.description)
+ var data = [value.rate.rawValue.byte] + [value.state.byte]
+ if value.state == 1 {
+ data = data + [value.value.byte]
+ }
+ return data
+ }
+}
+struct IBScreenChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .screen(value) = parameters[.screen] else { fatalError("缺å°åæ°: screen") }
+ Logger.log(value.description)
+ let data = [value.brightness.byte] + [value.duration.rawValue.byte] + [value.wrist.byte]
+ return data
+ }
+}
+
+struct IBOtherTargetChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .otherTarget(value) = parameters[.otherTarget] else { fatalError("缺å°åæ°: otherTarget") }
+ Logger.log(value.description)
+ var data = value.calorie.byte2 + [value.mileage.byte] + [value.stand.byte] + [value.burning.byte] + [value.ringsState.byte] + [value.vibrateState.byte]
+ data = data + [value.noticeState.byte]
+ return data
+ }
+}
+
+struct IBVibrateSoundChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .vibrateSound(value) = parameters[.vibrateSound] else { fatalError("缺å°åæ°: vibrateSound") }
+ Logger.log(value.description)
+ let data = [value.systemValue.byte] + [value.ringsValue.byte] + [value.mediaValue.byte] + [value.ringsState.byte] + [value.vibrateState.byte]
+ return data
+ }
+}
+struct IBUserInfoChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .userInfo(value) = parameters[.userInfo] else { fatalError("缺å°åæ°: userInfo") }
+ Logger.log(value.description)
+ var data = [value.age.byte] + [value.gender.byte] + [value.height.byte] + value.weight.byte2 + value.step.byte4 + value.burning.byte2
+ data = data + [value.stand.byte] + [value.hourSystem.byte]
+ return data
+ }
+}
+
+
+struct IBClockChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .clock(value) = parameters[.clock] else { fatalError("缺å°åæ°: clock") }
+ guard let data = value.encode else { fatalError("jsonè§£æå¼å¸¸: clock") }
+ Logger.log(value.jsonString ?? "")
+
+ return data.bytes
+ }
+}
+struct IBTrainTargetChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .trainTarget(value) = parameters[.trainTarget] else { fatalError("缺å°åæ°: trainTarget") }
+ guard let data = value.encode else { fatalError("jsonè§£æå¼å¸¸: trainTarget") }
+ Logger.log(value.jsonString ?? "")
+
+ return data.bytes
+ }
+}
+struct IBSendPhoneChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .sendPhone(value) = parameters[.sendPhone] else { fatalError("缺å°åæ°: sendPhone") }
+ guard let data = value.encode else { fatalError("jsonè§£æå¼å¸¸: sendPhone") }
+ Logger.log(value.jsonString ?? "")
+
+ return data.bytes
+ }
+}
+struct IBSendTimeChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .sendTime(value) = parameters[.sendTime] else { fatalError("缺å°åæ°: sendTime") }
+ guard let data = value.encode else { fatalError("jsonè§£æå¼å¸¸: sendTime") }
+ Logger.log(value.jsonString ?? "")
+ return data.bytes
+ }
+}
+struct IBWeatherChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .weather(value) = parameters[.weather] else { fatalError("缺å°åæ°: weather") }
+ guard let data = value.encode else { fatalError("jsonè§£æå¼å¸¸: weather") }
+ Logger.log(value.jsonString ?? "")
+ return data.bytes
+ }
+}
+struct IBAddressBookChecker: IBChecker {
+ static func check(_ parameters: [IBParameter]) -> [UInt8] {
+ guard case let .addressBook(list) = parameters[.addressBook] else { fatalError("缺å°åæ°: addressBook") }
+ if list.count > 20 { fatalError("åæ°: addressBook,æå¤ä¸è½è¶
è¿20个è系人") }
+ var data = [list.count.byte]
+ var des = "[ "
+ for item in list {
+ des += item.description
+ //æ§å«
+ data = data + [item.gender.byte]
+ //å§å
+ if let name = item.name,let value = name.data(using: .utf8),!value.isEmpty {
+ data += [value.count.byte]
+ data += value.bytes
+ }
+ else{
+ data += [0.byte]
+ }
+ //çµè¯å·ç 个æ°
+ data += [item.phoneNumbers.count.byte]
+ if item.phoneNumbers.count > 2 { fatalError("åæ°: addressBook,çµè¯å·ç 书æ°ä¸è½è¶
è¿ä¸¤ä¸ª") }
+
+ for phone in item.phoneNumbers {
+ //çµè¯å·ç
+ if let value = phone.number.data(using: .utf8),!value.isEmpty {
+ data += [value.count.byte]
+ data += value.bytes
+ }
+ else{
+ data += [0.byte]
+ }
+ //å½å±å°
+ if let value = phone.location?.data(using: .utf8),!value.isEmpty {
+ data += [value.count.byte]
+ data += value.bytes
+ }
+ else{
+ data += [0.byte]
+ }
+ //è¿è¥å
+ if let value = phone.operator?.data(using: .utf8),!value.isEmpty {
+ data += [value.count.byte]
+ data += value.bytes
+ }
+ else{
+ data += [0.byte]
+ }
+ }
+ }
+ des += " ]"
+ Logger.log(des)
+
+ return data
+ }
+}
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBKeeper.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBKeeper.swift
new file mode 100644
index 0000000..53b8a37
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBKeeper.swift
@@ -0,0 +1,104 @@
+//
+// IBKeeper.swift
+// UnifyBluetooth
+//
+// Created by yaozuopan on 2024/2/5.
+//
+
+import Foundation
+import CoreBluetooth
+
+class UBDevice: Codable {
+ let uuid: String
+ let name: String
+ let vendors: Int
+
+ var battery: Int
+ var rssi: Int
+
+ init(_ uuid: String, vendors: Int, name: String, battery: Int, rssi: Int) {
+ self.uuid = uuid
+ self.name = name
+ self.vendors = vendors
+ self.battery = battery
+ self.rssi = rssi
+ }
+}
+
+/// æ°æ®ä¿å
+struct IBKeeper {
+ static let saver = UserDefaults.standard
+
+ private static let serviceKey = "IBKeeper.Services"
+ private static let connectedKey = "IBKeeper.Connected"
+
+ /// è®°å½ææ°çè¿æ¥è®¾å¤
+ static func lastConnected(_ peripheral: IBPeripheral?) {
+ guard let peripheral = peripheral else { return }
+ addServices(peripheral.peripheral.services)
+ addConnected(peripheral)
+ }
+
+ /// ä¿åèçæå¡ç¹å¾
+ private static func addServices(_ services: [CBService]?) {
+ guard let services = services?.map({ $0.uuid.uuidString }) else { return }
+
+ var recordServices = saver.stringArray(forKey: serviceKey) ?? []
+ recordServices.append(contentsOf: services)
+ recordServices = Array(Set(recordServices))
+ saver.setValue(recordServices, forKey: serviceKey)
+ }
+
+ /// è®°å½å·²è¿æ¥è¿ç设å¤
+ private static func addConnected(_ peripheral: IBPeripheral) {
+ var recordConnected: [UBDevice] = []
+ if let jsonData = saver.data(forKey: connectedKey) {
+ recordConnected = JSON.decode([UBDevice].self, from: jsonData) ?? []
+ }
+
+ if let device = recordConnected.filter({ $0.uuid == peripheral.uuid.uuidString }).first {
+ device.battery = peripheral.battery
+ device.rssi = peripheral.rssi
+ } else {
+ recordConnected.append(UBDevice(peripheral.uuid.uuidString,
+ vendors: peripheral.vendors.rawValue,
+ name: peripheral.peripheral.name ?? "",
+ battery: peripheral.battery,
+ rssi: peripheral.rssi))
+ }
+
+ saver.setValue(recordConnected.jsonData, forKey: connectedKey)
+ }
+
+ /// ä»å·²è¿æ¥è®°å½ä¸ç§»é¤å·²è§£ç»è®¾å¤
+ static func removeConnected(_ uuid: UUID?) {
+ guard let uuid = uuid else { return }
+
+ var recordConnected: [UBDevice] = []
+ if let jsonData = saver.data(forKey: connectedKey) {
+ recordConnected = JSON.decode([UBDevice].self, from: jsonData) ?? []
+ }
+
+ recordConnected.removeAll { $0.uuid == uuid.uuidString }
+ saver.setValue(recordConnected.jsonData, forKey: connectedKey)
+ }
+
+ /// å·²è¿æ¥è¿è®¾å¤çæå¡ç¹å¾å表
+ static var services: [CBUUID] {
+ (saver.stringArray(forKey: serviceKey) ?? []).map { CBUUID(string: $0) }
+ }
+
+ /// å·²è¿æ¥è¿ç设å¤å表
+ static var connected: [IBPeripheral] {
+ guard let jsonData = saver.data(forKey: connectedKey) else { return [] }
+ let recordConnected = JSON.decode([UBDevice].self, from: jsonData) ?? []
+ return recordConnected.map {
+ IBPeripheral(nil, uuid: $0.uuid, name: $0.name, vendors: $0.vendors, rssi: $0.rssi, battery: $0.battery) }
+ }
+
+ /// å·²è¿æ¥è¿ç设å¤UUIDå表
+ static var connectedUUIDs: [UUID] {
+ guard let jsonData = saver.data(forKey: connectedKey) else { return [] }
+ return (JSON.decode([UBDevice].self, from: jsonData) ?? []).compactMap { UUID(uuidString: $0.uuid) }
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBManager.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBManager.swift
new file mode 100644
index 0000000..765644a
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBManager.swift
@@ -0,0 +1,75 @@
+//
+// IBManager.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/12.
+//
+
+import Foundation
+
+public typealias IBDiscoverHandler = (_ peripheral: IBPeripheral) -> Void
+public typealias IBCompleteHandler = (_ isSuccess: Bool) -> Void
+
+/// SDK 管çç±»
+public class IBManager {
+
+ /// åå§åå·¥ä½
+ public static func initializationSDK() {
+// IBBluetooth.shared.scan(.default)
+
+// DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
+// IBBluetooth.shared.reconnected()
+// }
+ }
+
+ public static var logs: [String] { Logger.logs }
+}
+
+public extension IBManager {
+ /// SDK çæ¬å·
+ static let version: String = "1.0.7"
+ /// é»è®¤ä¸º false
+ static var isDebug: Bool = false {
+ didSet { Logger.isDebug = isDebug }
+ }
+}
+
+// èçç¸å
³ API
+public extension IBManager {
+
+ internal static var discoverHandler: IBDiscoverHandler?
+
+ /// æ«æè®¾å¤
+ /// - Parameters:
+ /// - option: æ«æåæ°
+ /// - discoverHandler: ç»æåè°
+ static func scan(_ option: IBScanOption = .default, discoverHandler: @escaping IBDiscoverHandler) {
+ Self.discoverHandler = discoverHandler
+ IBBluetooth.shared.scan(option)
+ }
+
+ /// åæ¢æ«æèç设å¤
+ static func stopScan() {
+ Self.discoverHandler = nil
+ IBBluetooth.shared.stopScan()
+ }
+
+ internal static var completeHandler: IBCompleteHandler?
+
+ /// è¿æ¥è®¾å¤
+ /// - Parameters:
+ /// - peripheral: æ«æåç°ç设å¤
+ /// - completeHandler: ç»æåè°
+ static func connect(_ peripheral: IBPeripheral, completeHandler: @escaping IBCompleteHandler) {
+ Self.completeHandler = completeHandler
+ IBBluetooth.shared.connect(peripheral)
+ }
+
+ /// æå¼ä¸èç设å¤çè¿æ¥
+ /// - Parameter peripheral: èç设å¤å¯¹å
+ static func cancel(_ peripheral: IBPeripheral) {
+ IBBluetooth.shared.cancel(peripheral)
+ }
+ /// å½åå·²è¿æ¥è®¾å¤
+ static var currentConnected: IBPeripheral! { IBBluetooth.shared.currentConnected}
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBNotify.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBNotify.swift
new file mode 100644
index 0000000..a7c5a57
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBNotify.swift
@@ -0,0 +1,268 @@
+//
+// IBNotify.swift
+//
+//
+// Created by Harvey on 2020/1/5.
+// Copyright © 2020 å§ä½æ½/Harvey. All rights reserved.
+//
+
+import Foundation
+
+fileprivate let center = NotificationCenter.default
+
+fileprivate class Weakly: NSObject {
+ weak var owner: NSObjectProtocol?
+ var delegateObservers: [NSObjectProtocol]
+ init(_ owner: NSObjectProtocol, delegateObservers: [NSObjectProtocol] = []) {
+ self.owner = owner
+ self.delegateObservers = delegateObservers
+ }
+}
+
+extension IBNotify {
+
+ fileprivate struct Keeper {
+ static var observers: [Weakly] = []
+ static func remove(_ observer: NSObjectProtocol) {
+ observers
+ .filter { $0.owner === observer || isNil($0.owner) }
+ .forEach {
+ $0.delegateObservers.forEach { center.removeObserver($0) }
+ }
+ observers.removeAll { isNil($0.owner) || $0.owner === observer }
+ }
+
+ static func append(_ delegateObserver: NSObjectProtocol, owner: NSObjectProtocol) {
+ guard let weakly = observers.filter({ $0.owner === owner }).first else {
+ observers.append(Weakly(owner, delegateObservers: [delegateObserver]))
+ return
+ }
+ weakly.delegateObservers.append(delegateObserver)
+ }
+ }
+
+ public struct Name {
+ fileprivate let rawValue: String
+ init(_ rawValue: String) {
+ self.rawValue = rawValue
+ }
+ }
+}
+
+public class IBNotify {
+
+ init() {}
+
+ private(set) var name: Notification.Name!
+ @discardableResult
+ func name(_ value: IBNotify.Name) -> Self {
+ name = Notification.Name(rawValue: value.rawValue)
+ return self
+ }
+
+ private(set) var observer: NSObjectProtocol!
+ @discardableResult
+ func observer(_ value: NSObjectProtocol) -> Self {
+ observer = value
+ return self
+ }
+
+ private(set) var queue: OperationQueue = .main
+ @discardableResult
+ func queue(_ value: OperationQueue) -> Self {
+ queue = value
+ return self
+ }
+
+ private(set) var object: Any?
+ @discardableResult
+ func object(_ value: Any) -> Self {
+ object = value
+ return self
+ }
+
+ func subscribe(_ value: @escaping (Notification) -> Void) {
+ if isNil(observer) || isNil(name) {
+ fatalError("observer or name must be not nil")
+ }
+
+ let delegateObserver = center
+ .addObserver(forName: name,
+ object: object,
+ queue: queue,
+ using: value)
+ Keeper.append(delegateObserver, owner: observer)
+ }
+
+ static func remove(_ observer: NSObjectProtocol) {
+ center.removeObserver(observer)
+ Keeper.remove(observer)
+ }
+}
+
+extension IBNotify {
+ static func post(_ name: IBNotify.Name,
+ object: Any? = nil,
+ userInfo: [AnyHashable : Any] = [:]) {
+ center.post(name: Notification.Name(rawValue: name.rawValue),
+ object: object, userInfo: userInfo)
+ }
+}
+
+public extension IBManager {
+
+ /// 订é
éç¥
+ static func subscribe(_ name: IBNotify.Name,
+ observer: NSObjectProtocol!,
+ receive: @escaping (_ object: Any?, _ userInfo: [String: Any]) -> Void) {
+ IBNotify()
+ .name(name)
+ .observer(observer)
+ .subscribe { notification in
+ receive(notification.object, notification.userInfo as? [String: Any] ?? [:])
+ }
+ }
+
+ /// ç§»é¤è®¢é
éç¥çè§å¯è
+ static func remove(_ observer: NSObjectProtocol) {
+ IBNotify.remove(observer)
+ }
+}
+
+public extension IBNotify.Name {
+ /// æ¯å¦çµéãä¿¡å·å¼ºåº¦
+// static let deviceInfoUpdate = IBNotify.Name("IOTBluetooth.DeviceInfoUpdate")
+
+ /// è¿æ¥è®¾å¤åçåå¨ï¼ä¸ç§æ
嵿å¼è¿æ¥ï¼ä¸ç§æ¯åæ¢è®¾å¤
+// static let connectedDeviceDidChange = IBNotify.Name("IOTBluetooth.DeviceConnected")
+
+ /// é´æç¶ææ¹åï¼éè¿object è·åç¶æï¼0åå¤é´æã1çå¾
æè¡¨åæè¿æ¥ã 2çå¾
ææºç¡®è®¤é
对请æ±ã3é´ææåã4é´æå¤±è´¥ã
+// static let authStateDidChange = IBNotify.Name("IOTBluetooth.AuthStateDidChange")
+
+ /// åç°è®¾å¤
+// static let deviceHasFound = IBNotify.Name("IOTBluetooth.DeviceHasFound")
+
+
+ /// è¿æ¥ç¶æåçæ¹åãéè¿object è·åç¶æï¼0æå¼è¿æ¥ã1è¿ä¸è®¾å¤ã
+ static let connectStateDidChange = IBNotify.Name("IOTBluetooth.ConnectStateDidChange")
+
+ /// è¿ç¨æç
§å¨ä½ãéè¿objectè·åç¶æã2è¿è¡æå¿æç
§ï¼3éåº
+ static let takePhoto = IBNotify.Name("IOTBluetooth.TakePhoto")
+
+ /// æè¡¨è¯·æ±å¤©æ°æ°æ®
+ static let weather = IBNotify.Name("IOTBluetooth.weather")
+
+ /// æ¾å°è®¾å¤
+ static let didFindDevice = IBNotify.Name("IOTBluetooth.FindDevice")
+
+ /// è®ç»ç¶æåå,éè¿objectè·åç¶æIBTarinState对象
+ static let trainStateDidChanged = IBNotify.Name("IOTBluetooth.TrainStateChanged")
+
+ /// è·åæè¡¨æ¨éçè®ç»å®æ¶æ°æ®,éè¿objectè·åç¶æIBTrainingData对象
+ static let trainingData = IBNotify.Name("IOTBluetooth.TrainingData")
+}
+
+extension IBNotify {
+
+ /// å¤çæè¡¨æ¨éè¿æ¥çéç¥
+ static func handle(_ data: Data) -> Bool {
+ //æç
§
+ if IBAbility.takePhoto.isAnswer(data) {
+ let result = IBGeneralParser.dataPacket(data)
+ let code = result[0].int
+ if code == 2 || code == 3 {
+ post(.takePhoto, object:code)
+ }
+ return true
+ }
+ //æ¾å°è®¾å¤
+ if IBAbility.find.isAnswer(data) {
+ var bytes = data.bytes
+ bytes.removeLast()
+ let code = bytes.last!.int
+ if code == 2 {
+ post(.didFindDevice)
+ }
+ return true
+ }
+ //è®ç»ç¶æåå
+ if data.bytes[1] == 0x05 && data.bytes[2] == 0x50 {
+ let result = IBGeneralParser.dataPacket(data)
+ let model = IBTarinState(result.data)
+ post(.trainStateDidChanged, object: model)
+ return true
+ }
+ //è®ç»å®æ¶æ°æ®
+ if IBAbility.currentHeartRate.isAnswer(data) {
+ let dataPacket = IBGeneralParser.dataPacket(data)
+ if let model = IBTrainingData(dataPacket.data) {
+ post(.trainingData, object: model)
+ }
+ return true
+ }
+ //请æ±å¤©æ°
+ if data.bytes[1] == 0x05 && data.bytes[2] == 0x03 {
+ post(.weather)
+ return true
+ }
+
+ //é
对
+ if data.bytes[1] == 0x05 && data.bytes[2] == 0x11 {
+ let result = IBGeneralParser.dataPacket(data)
+ let code = result[0].int
+ let desc = ["æç»é
对","确认é
对","确认解ç»å
¶ä»ææº","å
¶ä»"]
+ Logger.log("æ¶å°ç¡®è®¤é
å¯¹æ¶æ¯ï¼",desc[code])
+ return true
+ }
+ if data.bytes[1] == 0x05 && data.bytes[2] == 0x1 {
+ let result = IBGeneralParser.dataPacket(data)
+ let code = result[0].int
+ let desc = ["æç»è§£ç»","确认解ç»"]
+ Logger.log("æ¶å°ç¡®è®¤è§£ç»æ¶æ¯ ",desc[code])
+ return true
+ }
+ if data.bytes[1] == 0x05 && data.bytes[2] == 0x10 {
+ var result = IBGeneralParser.dataPacket(data)
+ let code = result[0].int
+ if code == 1{
+ result.removeFirst()
+ UserDefaults.standard.setValue(result, forKey: "IOTBletooth.mac")
+ UserDefaults.standard.synchronize()
+
+ Logger.log("æ¶å°é
对æåæ¶æ¯",result)
+ //åéæ¶é´
+ IBNotify.sendTime()
+ }
+ else{
+ Logger.log("æ¶å°é
å¯¹å¤±è´¥æ¶æ¯")
+ IBManager.completeHandler?(false)
+ IBManager.completeHandler = nil
+ }
+
+ return true
+ }
+ return false
+ }
+
+ static func sendTime(){
+ let date = Date()
+ let model = IBSendTime()
+ model.time = Int(date.timeIntervalSince1970)
+ model.week = date.weekDay.rawValue - 1
+ model.year = date.year - 2000
+ model.month = date.month
+ model.day = date.day
+ model.hour = date.hour
+ model.minute = date.minute
+ model.second = date.second
+
+ IBSender()
+ .ability(IBAbility.sendTime)
+ .parameters([.sendTime(model)])
+ .response { result in
+ Logger.log(result)
+ IBManager.completeHandler?(true)
+ IBManager.completeHandler = nil
+ }
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBParameter.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBParameter.swift
new file mode 100644
index 0000000..23dfa2e
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBParameter.swift
@@ -0,0 +1,180 @@
+//
+// IBParameter.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/19.
+//
+
+import Foundation
+
+enum IBKey: String {
+ case dialID = "dialID"
+ case action = "action"
+ case motionMode = "motionMode"
+ case language = "language"
+ case value = "value"
+ case file = "file"
+ case targetStep = "targetStep"
+ case sleep = "sleep"
+ case water = "water"
+ case clock = "clock"
+ case heartRate = "heartRate"
+ case bloodOxygen = "bloodOxygen"
+ case screen = "screen"
+ case vibrateSound = "vibrateSound"
+ case otherTarget = "otherTarget"
+ case trainTarget = "trainTarget"
+ case sendPhone = "sendPhone"
+ case sendTime = "sendTime"
+ case auxiliary = "auxiliary"
+ case userInfo = "userInfo"
+ case weather = "weather"
+ case addressBook = "addressBook"
+}
+
+/// åæ°
+public enum IBParameter {
+ /// 表çID
+ case dialID(Int)
+ /// 1=(å¼å§ãå¯ç¨ãå¼å¯)ï¼0=(忢ãç¦ç¨ãå
³é)
+ case action(Int)
+ /// è¿å¨æ¨¡å¼
+ case motionMode(IBMotionMode)
+ /// è¯è¨
+ case language(IBLanguage)
+ /// éç¨å¼è®¾ç½®
+ case value(Int)
+ /// æä»¶
+ case file(IBFile)
+ /// è®ç»ç®æ
+ case targetStep(IBTargetStep)
+ /// ç¡ç
+ case sleep(IBSleep)
+ /// åæ°´
+ case water(IBWater)
+ /// 设置é¹é
+ case clock(IBClock)
+ /// 设置å¿ç
+ case heartRate(IBHeartRate)
+ /// è¡æ°§
+ case bloodOxygen(IBBloodOxygen)
+ /// 设置å±å¹
+ case screen(IBScreen)
+ /// 设置声é³åéå¨
+ case vibrateSound(IBVibrateSound)
+ /// è®¾ç½®ç®æ 设置
+ case otherTarget(IBOtherTarget)
+ /// 设置è®ç»ç®æ
+ case trainTarget(IBTrainTarget)
+ /// åéææºä¿¡æ¯
+ case sendPhone(IBPhoneInfo)
+ /// åéå½åæ¶é´
+ case sendTime(IBSendTime)
+ /// 设置è¾
å©åè½
+ case auxiliary(IBAuxiliary)
+ /// è®¾ç½®ç¨æ·æ°æ®
+ case userInfo(IBUserInfo)
+ /// åéå¤©æ°æ°æ®
+ case weather(IBWeather)
+ /// åéé讯å½
+ case addressBook([IBAddressBook])
+
+ var key: IBKey {
+ switch self {
+ case .dialID(_): return .dialID
+ case .action(_): return .action
+ case .motionMode(_): return .motionMode
+ case .language(_): return .language
+ case .value(_): return .value
+ case .file(_): return .file
+ case .targetStep(_): return .targetStep
+ case .sleep(_): return .sleep
+ case .water(_): return .water
+ case .clock(_): return .clock
+ case .heartRate(_): return .heartRate
+ case .bloodOxygen(_): return .bloodOxygen
+ case .screen(_): return .screen
+ case .vibrateSound(_): return .vibrateSound
+ case .auxiliary(_): return .auxiliary
+ case .otherTarget(_): return .otherTarget
+ case .trainTarget(_): return .trainTarget
+ case .sendPhone(_): return .sendPhone
+ case .sendTime(_): return .sendTime
+ case .userInfo(_): return .userInfo
+ case .weather(_): return .weather
+ case .addressBook(_): return .addressBook
+ }
+ }
+}
+
+public enum IBMotionMode: Int {
+ /// å¥èµ°
+ case walking = 0
+ /// è·æ¥
+ case running
+ /// éªè¡
+ case ride
+}
+
+public enum IBFile: Int {
+ /// OTA æä»¶
+ case ota = 1
+ /// MP3 æä»¶
+ case mp3
+ /// 表çä¿¡æ¯
+ case dial
+ /// 天æ°
+ case weather
+ /// é¹é
+ case clock
+}
+//0ï¼è¿å¨
+//1ï¼å¿ç
+//2ï¼è¡æ°§çæµ
+//3ï¼è®ç»
+//4ï¼è®ç»è®°å½
+//5ï¼æåé
+//6ï¼å¤©æ°
+//7ï¼é³ä¹
+//8ï¼çµè¯
+//9ï¼å½é³
+//10ï¼ç§è¡¨
+//11ï¼è®¡æ¶å¨
+//12ï¼é¹é
+//13ï¼èç
+//14ï¼ç¡ç
+//15ï¼è®¾ç½®
+public enum IBAuxiliary: Int {
+ /// è¿å¨
+ case sport = 0
+ /// å¿ç
+ case heart
+ /// è¡æ°§çæµ
+ case bloodOxygen
+ /// è®ç»
+ case train
+ /// è®ç»è®°å½
+ case tarinRecord
+ /// æåé
+ case compass
+ /// 天æ°
+ case weather
+ /// é³ä¹
+ case music
+ /// çµè¯
+ case mobile
+ /// å½é³
+ case record
+ /// ç§è¡¨
+ case secondTimer
+ /// 计æ¶å¨
+ case timer
+ /// é¹é
+ case clock
+ /// èç
+ case bluetooth
+ /// ç¡ç
+ case sleep
+ /// 设置
+ case setting
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBParser.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBParser.swift
new file mode 100644
index 0000000..97e3ea5
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBParser.swift
@@ -0,0 +1,329 @@
+//
+// IBParser.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/18.
+//
+
+import Foundation
+
+/// èçæ°æ®è§£æåè®®
+protocol IBParser {
+ /// è§£ææ°æ®
+ static func parse(_ data: Data) -> IBResponse
+}
+
+extension IBParser {
+ static func dataPacket(_ data: Data) -> [UInt8] {
+ let dataLength = data[7...10].int
+ return data.suffix(from: 17).prefix(dataLength).map({ $0 })
+ }
+}
+
+struct IBBatteryParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ var bytes = data.bytes
+ bytes.removeLast()
+ return .response.code(.success).value(bytes.last!.int)
+ }
+}
+
+struct IBSwitchDialParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ var bytes = data.bytes
+ bytes.removeLast()
+ let code = bytes.last!.int
+ let desc = ["æä»¤æ ¡éªå¤±è´¥", "忢æå", "æ 该表çèµæº", "åæ¢å¤±è´¥"]
+ return .response.code(code == 1 ? .success:.failure).message(desc[code]).value(code)
+ }
+}
+struct IBFetchCurrentDialParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let bytes = dataPacket(data)
+ let value = bytes.int
+ return .response.code(.success).value(value)
+ }
+}
+struct IBFetchAuxiliaryParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let bytes = dataPacket(data)
+ guard let value = IBAuxiliary(rawValue: bytes.int) else {return .response.code(.parseError) }
+ return .response.code(.success).value(value)
+ }
+}
+
+struct IBCheckDialParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ var bytes = data.bytes
+ bytes.removeLast()
+ let code = bytes.last!.int
+ let desc = ["æä»¤æ ¡éªå¤±è´¥", "å·²å®è£
", "æªå®è£
"]
+ return .response.code(code != 0 ? .success:.failure).message(desc[code]).value(code)
+ }
+}
+
+/// éç¨è§£æ(1 Byte)
+struct IBGeneralParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+// guard data.isEmpty == false else { return IBSingleByteSimulateParser.parse() }
+
+ let code = dataPacket(data).int
+ return .response.code(code == 1 ? .success:.failure)
+ }
+}
+struct IBTakePhotoParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let code = dataPacket(data).int
+ let desc = ["æä»¤æ ¡éªå¤±è´¥", "æä½æå", "è¿è¡æå¿æç
§","éåº"]
+ return .response.code(code != 0 ? .success:.failure).message(desc[code]).value(code)
+ }
+}
+struct IBWaterParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+// guard data.isEmpty == false else { return IBSingleByteSimulateParser.parse() }
+
+ let code = dataPacket(data).int
+ let desc = code == 0 ? "å
³é":"å¼å¯"
+ return .response.code(.success).value(code).message(desc)
+ }
+}
+struct IBFindParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let code = dataPacket(data).int
+ let desc = ["æä»¤æ ¡éªå¤±è´¥", "æä½æå", "æè¡¨å·²æ¾å°ï¼åæ¢æ¥æ¾"]
+ return .response.code(code != 0 ? .success:.failure).message(desc[code]).value(code)
+ }
+}
+struct IBSendPhoneParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let code = dataPacket(data).int
+ let desc = ["æä»¤æ ¡éªå¤±è´¥","æè¡¨æªä¸ä»»ä½ææºç»å®", "æè¡¨å·²ä¸è¯¥ææºç»å®", "æè¡¨å·²ä¸å
¶ä»ææºç»å®"]
+ return .response.code(code != 0 ? .success:.failure).message(desc[code]).value(code)
+ }
+}
+
+
+struct IBWatchStateParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ var bytes = data.bytes
+ bytes.removeLast()
+ let code = bytes.last!.int
+ let desc = [0:"空é²ç¶æ", 9:"USBåå¨ç¶æ", 10:"è¿å¨è®ç»ç¶æ"]
+ return .response.code(.success).value(code).message(desc[code] ?? "")
+ }
+}
+
+
+struct IBDiskParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let code = dataPacket[0].int
+ if code == 1 {
+ var value: Int = 0
+ value = dataPacket.suffix(from: 1).map({ $0 }).int
+ return .response.code(.success).value(value)
+ }
+ else {
+ return .response.code(.failure)
+ }
+ }
+}
+
+struct IBTrainingDataParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ if dataPacket.count == 0 {
+ return .response.code(.success)
+ }
+ guard let model = IBTrainingData(dataPacket.data) else { return .response.code(.parseError) }
+ return .response.code(.success).value(model)
+ }
+}
+struct IBHeartRateParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHeartRate(dataPacket.data)
+ Logger.log(model.description)
+ return .response.code(.success).value(model)
+ }
+}
+struct IBBloodOxygenParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBBloodOxygen(dataPacket.data)
+ Logger.log(model.description)
+ return .response.code(.success).value(model)
+ }
+}
+
+struct IBSyncTrainParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ guard let model = JSON.decode(IBHistoryBaseTraining.self, from: dataPacket.data) else { return .response.code(.parseError) }
+ return .response.code(.success).items(model.list)
+
+// let dataPacket = baseData.jsonString()!
+// guard let model = JSON.decode(IBHistoryBaseTraining.self, from: dataPacket.data!) else { return .response.code(.parseError) }
+// Logger.log(model.jsonString ?? "")
+// return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncHeartRateParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistoryHeartRate(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncBloodOxygenParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistoryBloodOxygen(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncStepParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistoryStep(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncBurningParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistoryBurning(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncStandParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistoryStand(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncCalorieParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistoryCalorie(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncDistanceParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistoryDistance(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncSleepParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistorySleep(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+struct IBSyncGpsParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBHistoryGps(dataPacket.data)
+// Logger.log(model.list)
+ return .response.code(.success).items(model.list)
+ }
+}
+
+
+struct IBAblutParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ guard let model = JSON.decode(IBAbout.self, from: dataPacket.data) else { return .response.code(.parseError) }
+ Logger.log(model.jsonString ?? "")
+ return .response.code(.success).value(model)
+ }
+}
+struct IBClockParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ guard let model = JSON.decode(IBClock.self, from: dataPacket.data) else { return .response.code(.parseError) }
+ Logger.log(model.jsonString ?? "")
+ return .response.code(.success).items(model.alarms)
+ }
+}
+struct IBSetClockParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+// guard data.isEmpty == false else { return IBClockSimulateParser.parse() }
+ let code = dataPacket(data).int
+ return .response.code(code == 1 ? .success:.failure)
+ }
+}
+
+struct IBFetchDialsParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let num = dataPacket[0].int
+ var list:[Int] = []
+ for i in 0.. IBResponse {
+ let dataPacket = dataPacket(data)
+ guard let model = IBTargetStep(dataPacket.data) else { return .response.code(.parseError) }
+
+ Logger.log(model.description)
+ return .response.code(.success).value(model)
+ }
+}
+struct IBSleepParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBSleep(dataPacket.data)
+ Logger.log(model.description)
+ return .response.code(.success).value(model)
+ }
+}
+struct IBScreenParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBScreen(dataPacket.data)
+ Logger.log(model.description)
+ return .response.code(.success).value(model)
+ }
+}
+struct IBVibrateSoundParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBVibrateSound(dataPacket.data)
+ Logger.log(model.description)
+ return .response.code(.success).value(model)
+ }
+}
+struct IBOtherParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBVibrateSound(dataPacket.data)
+ Logger.log(model.description)
+ return .response.code(.success).value(model)
+ }
+}
+struct IBOtherTargetParser: IBParser {
+ static func parse(_ data: Data) -> IBResponse {
+ let dataPacket = dataPacket(data)
+ let model = IBOtherTarget(dataPacket.data)
+ Logger.log(model.description)
+ return .response.code(.success).value(model)
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBSender.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBSender.swift
new file mode 100644
index 0000000..d9527d8
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBSender.swift
@@ -0,0 +1,111 @@
+//
+// IBSender.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/15.
+//
+
+import Foundation
+
+public typealias IBCompletionHandler = (_ result: IBResponse) -> Void
+
+//public typealias IBCmdSuccess = (_ result: IBResponse) -> Void
+//public typealias IBCmdError = (_ error: IBError) -> Void
+
+/// èçæ¶æ¯åéç±»
+public class IBSender {
+ public init() {
+ Self.all.append(self)
+ }
+
+ var ability: IBAbility!
+ var parameters: [IBParameter] = []
+ var completion: IBCompletionHandler!
+
+// var cmdSuccess: IBCmdSuccess?
+// var cmdFailure: IBCmdError?
+
+ var data: [UInt8] = []
+
+ var dataPacket: [UInt8] {
+ if isValue(ability.checker) {
+ data = ability.checker.check(parameters)
+ }
+
+// let data: [UInt8] = data?.bytes ?? []
+ /// åå
æ°
+ let packageCount = 1
+ /// æ°æ®å
æ»é¿åº¦
+ let dataTotalLength = data.count
+ /// æ°æ®å
é¿åº¦
+ let dataLength = data.count
+ /// æ°æ®å
ç´¢å¼
+ let index = 1
+
+ var bytes: [UInt8] = [0x73, ability.type.rawValue, ability.id]
+ bytes = bytes + packageCount.byte4 + dataTotalLength.byte4 + index.byte4 + dataLength.byte2
+
+ if data.count > 0 {
+ bytes = bytes + data
+ bytes = bytes + [LRC.calculateLRC(data)]
+ } else {
+ bytes = bytes + [0x00]
+ }
+
+ return bytes
+ }
+
+ func isAnswer(_ data: Data) -> Bool {
+ return ability.isAnswer(data)
+ }
+
+ func parse(_ data: Data) -> IBResponse {
+ return ability.parser.parse(data)
+ }
+
+ deinit {
+// Logger.log("deinit IBSender")
+ }
+}
+
+public extension IBSender {
+
+ /// åè½æ¥å£
+ @discardableResult
+ func ability(_ value: IBAbility) -> Self {
+ ability = value
+ return self
+ }
+
+ /// åæ°
+ @discardableResult
+ func parameters(_ value: [IBParameter]) -> Self {
+ parameters = value
+ return self
+ }
+
+ /// æ§è¡ä¸ååºå¤ç
+ @discardableResult
+ func response(_ handler: @escaping IBCompletionHandler) -> Self {
+ completion = handler
+ IBBluetooth.shared.send(self)
+ return self
+ }
+// /// æ§è¡ä¸ååºå¤ç
+// @discardableResult
+// func response(success: @escaping IBCmdSuccess,failure:@escaping IBCmdError) -> Self {
+// cmdSuccess = success
+// cmdFailure = failure
+// IBBluetooth.shared.send(self)
+// return self
+// }
+}
+
+extension IBSender {
+ static var all: [IBSender] = []
+
+ /// ä»ç¼åå®ä¾éåä¸ç§»é¤è¯¥å®ä¾
+ func remove() {
+ Self.all.removeAll { $0 === self }
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBSimulateParser.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBSimulateParser.swift
new file mode 100644
index 0000000..4f97eb2
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBSimulateParser.swift
@@ -0,0 +1,24 @@
+//
+// IBSimulateParser.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/18.
+//
+
+import Foundation
+
+/// éç¨æ¨¡æååº
+//struct IBSingleByteSimulateParser {
+// static func parse() -> IBResponse {
+// return .response
+// }
+//}
+
+///// é¹é模æååº
+//struct IBClockSimulateParser {
+// static func parse() -> IBResponse {
+// let str = #"{"code":1,"alarms":[{"id":0,"repeat":[0],"hour":10,"minute":0,"enable":1},{"id":1,"repeat":[1,2,3,4,5],"hour":7,"minute":45,"enable":1}]}"#
+// guard let clock = JSON.decode(IBClock.self, from: str.data!) else { return .response.message("æ°æ®è§£æå¤±è´¥") }
+// return .response.success(true).items(clock.alarms)
+// }
+//}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBluetooth.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBluetooth.swift
new file mode 100644
index 0000000..2ba56a0
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IBluetooth.swift
@@ -0,0 +1,389 @@
+//
+// IBluetooth.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/2/4.
+//
+
+import Foundation
+import CoreBluetooth
+
+/// Max is 482
+let dataPacketMaxBytes = 450
+
+public class IBScanOption {
+ var values: [String : Any] = [:]
+ var serviceUUIDs: [String]? = nil
+
+ /// å
许é夿«æ
+ @discardableResult
+ public func allowDuplicates(_ value: Bool) -> Self {
+ values[CBCentralManagerScanOptionAllowDuplicatesKey] = value
+ return self
+ }
+
+ /// æ«ææå®æå¡
+ @discardableResult
+ public func solicited(_ serviceUUIDs: [String]) -> Self {
+ self.serviceUUIDs = serviceUUIDs
+ values[CBCentralManagerScanOptionSolicitedServiceUUIDsKey] = serviceUUIDs.map({ CBUUID(string: $0) })
+ return self
+ }
+
+ public static let `default` = IBScanOption()
+ public static var custom: IBScanOption { IBScanOption() }
+}
+
+/// 主æå¡
+let serviceUUID: String = "18E0"
+/// Notify ç¹å¾å¼
+let notifyCharacteristicUUID: String = "2AE5"
+/// Read ç¹å¾å¼
+let readCharacteristicUUID: String = "2AE2"
+/// Write ç¹å¾å¼(åéåèæ°â¤20)
+let writeCharacteristicUUID: String = "2AE3"
+/// Write ç¹å¾å¼(åéåèæ°>20)
+let writeBigCharacteristicUUID: String = "2AE4"
+/// Write ç¹å¾å¼(åéæä»¶OATãMP3ç)
+let writeFileCharacteristicUUID: String = "2AE0"
+
+class IBBluetooth: NSObject {
+ static let shared = IBBluetooth()
+
+ private override init() {
+ super.init()
+ centralManager = CBCentralManager(delegate: self, queue: nil)
+ }
+
+ /// 2AE5
+ private var notifyCharacteristic: CBCharacteristic!
+ /// 2AE2
+ private var readCharacteristic: CBCharacteristic!
+ /// 2AE3
+ private var writeCharacteristic: CBCharacteristic!
+ /// 2AE4
+ private var writeBigCharacteristic: CBCharacteristic!
+ /// 2AE0
+ private var writeFileCharacteristic: CBCharacteristic!
+
+ /// ä¸å¤®ç®¡çç±»ï¼ç®¡çèççæ«æè¿æ¥
+ var centralManager: CBCentralManager!
+
+ /// æ«æå°çèç设å¤éå
+ var devices: [IBPeripheral] = []
+
+ private var option: IBScanOption = .default
+ func scan(_ option: IBScanOption = .default) {
+ self.option = option
+ startScan()
+ }
+
+ /// éè¿æ¥è®¾å¤
+ func reconnected() {
+ guard let connectedPeripheral = centralManager.retrieveConnectedPeripherals(withServices: [CBUUID(string: serviceUUID)]).first else { return }
+ currentConnected = IBPeripheral()
+ currentConnected.peripheral = connectedPeripheral
+ centralManager.connect(connectedPeripheral)
+ }
+
+ /// å½åè¿æ¥è®¾å¤
+ var currentConnected: IBPeripheral!
+ /// æåæ¶æ¯åéå®ä¾
+ private weak var lastSender: IBSender?
+
+ /// å¼å§æ«æ
+ private func startScan() {
+ if centralManager.state == .poweredOn {
+ Logger.log("å¼å§æ«æèç设å¤...")
+ }
+ centralManager.scanForPeripherals(withServices: nil, options: option.values)
+ }
+
+ /// åæ¢æ«æ
+ func stopScan(){
+ Logger.log("åæ¢æ«æèç设å¤...")
+ centralManager.stopScan()
+ }
+
+ /// è¿æ¥èç设å¤
+ ///
+ /// - Parameter peripheral: èç设å¤å¯¹å
+ func connect(_ peripheral: IBPeripheral) {
+ currentConnected = peripheral
+ centralManager.connect(peripheral.peripheral)
+ }
+
+ /// æå¼ä¸èç设å¤çè¿æ¥
+ ///
+ /// - Parameter peripheral: èç设å¤å¯¹å
+ func cancel(_ peripheral: IBPeripheral) {
+ centralManager.cancelPeripheralConnection(peripheral.peripheral)
+ }
+
+ /// åéæ°æ®
+ /// - Parameters:
+ /// - sender: æ¶æ¯ç±»
+ func send(_ sender: IBSender) {
+ if let _ = lastSender {
+ sender.remove()
+ Logger.log("æå½ä»¤æ£å¨æ§è¡ä¸...")
+ return
+ }
+ lastSender = sender
+ startTimer()
+
+ let dataPacket = sender.dataPacket
+ Logger.log("\(sender.ability.characteristicUUID!) Write:", dataPacket.data.joined(" "), "Bytes(\(dataPacket.count))")
+
+ var writeCharacteristic: CBCharacteristic = writeCharacteristic
+ if sender.ability.characteristicUUID == writeBigCharacteristicUUID {
+ writeCharacteristic = writeBigCharacteristic
+ }
+ if sender.ability.characteristicUUID == writeFileCharacteristicUUID {
+ writeCharacteristic = writeFileCharacteristic
+ }
+
+ currentConnected.peripheral.writeValue(dataPacket.data, for: writeCharacteristic, type: .withResponse)
+ }
+
+ func sendDeviceInfo(){
+// IBNotify.post(.authStateDidChange, userInfo: ["state": 0])
+
+ let mac = UserDefaults.standard.object(forKey: "IOTBletooth.mac") as? [Int] ?? []
+ let model = IBPhoneInfo()
+ model.mac = mac
+ IBSender()
+ .ability(IBAbility.sendPhone)
+ .parameters([.sendPhone(model)])
+ .response { result in
+ Logger.log(result)
+ guard let value = result.value as? Int else {return}
+ if value == 2 {
+ //éç¥è¿æ¥æå
+ IBManager.completeHandler?(true)
+ IBManager.completeHandler = nil
+ }
+ else if value == 1{
+ //çå¾
æè¡¨åæè¿æ¥
+ Logger.log("çå¾
æè¡¨åæè¿æ¥")
+ }
+ else if value == 3{
+ //æè¡¨å·²ä¸å
¶ä»ææºç»å®
+ IBManager.completeHandler?(false)
+ IBManager.completeHandler = nil
+ }
+ }
+ }
+}
+
+extension IBBluetooth: CBCentralManagerDelegate {
+
+ /// ææºèçç¶ææ´æ°
+ /// - Parameter central: ä¸å¤®ç®¡çç±»
+ func centralManagerDidUpdateState(_ central: CBCentralManager) {
+ switch central.state {
+ case .unknown:
+ Logger.log("unknown")
+ case .resetting:
+ Logger.log("resetting")
+ case .unsupported:
+ Logger.log("unsupported")
+ case .unauthorized:
+ Logger.log("unauthorized")
+ case .poweredOff:
+ Logger.log("poweredOff")
+ case .poweredOn:
+ startScan()
+ Logger.log("poweredOn")
+ @unknown default:
+ break
+ }
+ }
+
+ /// åç°è®¾å¤
+ func centralManager(_ central: CBCentralManager, didDiscover peripheral: CBPeripheral, advertisementData: [String : Any], rssi RSSI: NSNumber) {
+
+ guard let manufacturerData = advertisementData["kCBAdvDataManufacturerData"] as? Data else { return }
+ guard let manufacturer = IBManufacturer(manufacturerData) else { return }
+
+ let device = IBPeripheral()
+ device.code = manufacturer.code
+ device.isBind = manufacturer.isBind
+ device.rssi = RSSI.intValue
+ device.peripheral = peripheral
+ device.productID = manufacturer.productID
+ device.customerID = manufacturer.productID
+ device.advertisementData = advertisementData
+ device.macAddress = manufacturer.macAddress
+ device.softwareVersion = manufacturer.softwareVersion
+ IBManager.discoverHandler?(device)
+ Logger.log("åç°è®¾å¤", device.name, device.macAddress)
+ }
+
+ /// è¿æ¥ä¸è®¾å¤
+ func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral) {
+ peripheral.delegate = self
+ peripheral.discoverServices([CBUUID(string: serviceUUID)])
+// IBNotify.post(.connectedDeviceDidChange)
+ Logger.log("å·²è¿æ¥", currentConnected.name)
+ IBNotify.post(.connectStateDidChange, object: 1)
+ }
+
+ /// è¿æ¥å¤±è´¥
+ func centralManager(_ central: CBCentralManager, didFailToConnect peripheral: CBPeripheral, error: Error?) {
+ Logger.log("è¿æ¥å¤±è´¥",error?.localizedDescription ?? "" )
+ currentConnected = nil
+ IBManager.completeHandler?(false)
+ IBManager.completeHandler = nil
+ }
+
+ /// æå¼è¿æ¥
+ func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?) {
+ Logger.log("æå¼è¿æ¥")
+
+ deinitTimer()
+ lastSender?.completion?(.response.code(.failure))
+ lastSender?.remove()
+
+ IBManager.completeHandler?(false)
+ IBManager.completeHandler = nil
+ IBNotify.post(.connectStateDidChange,object: 0)
+ }
+}
+
+extension IBBluetooth: CBPeripheralDelegate {
+
+ /// 读åå°ä¿¡å·
+ func peripheral(_ peripheral: CBPeripheral, didReadRSSI RSSI: NSNumber, error: Error?) {
+
+ }
+
+ /// åç°æå¡
+ func peripheral(_ peripheral: CBPeripheral, didDiscoverServices error: Error?) {
+ peripheral
+ .services?
+ .forEach {
+ peripheral.discoverCharacteristics(nil, for: $0)
+ }
+ }
+
+ /// åç°æå¡æ¾é£ä¸ªçç¹å¾,ç¶åéåææç¹å¾è®¢é
+ func peripheral(_ peripheral: CBPeripheral, didDiscoverCharacteristicsFor service: CBService, error: Error?) {
+ service
+ .characteristics?
+ .forEach {
+ if $0.uuid.uuidString == notifyCharacteristicUUID {
+ notifyCharacteristic = $0
+ peripheral.setNotifyValue(true, for: $0)
+ return
+ }
+
+ if $0.uuid.uuidString == readCharacteristicUUID {
+ readCharacteristic = $0
+ peripheral.setNotifyValue(true, for: $0)
+ return
+ }
+
+ if $0.uuid.uuidString == writeCharacteristicUUID {
+ writeCharacteristic = $0
+ return
+ }
+
+ if $0.uuid.uuidString == writeBigCharacteristicUUID {
+ writeBigCharacteristic = $0
+ return
+ }
+
+ if $0.uuid.uuidString == writeFileCharacteristicUUID {
+ writeFileCharacteristic = $0
+ return
+ }
+ }
+ }
+
+ /// æ¥èªèç设å¤çéç¥
+ func peripheral(_ peripheral: CBPeripheral, didUpdateNotificationStateFor characteristic: CBCharacteristic, error: Error?) {
+ // 读åç¹å¾çå¼
+ peripheral.readValue(for: characteristic)
+ }
+
+ /// èç设å¤åè¿æ¥çæ°æ®
+ func peripheral(_ peripheral: CBPeripheral, didUpdateValueFor characteristic: CBCharacteristic, error: Error?) {
+ if let error = error {
+ Logger.log(error)
+ }
+
+ guard let data = characteristic.value else { return }
+ if(data.count == 2 && data.int == 0){
+ Logger.log("æ¶å°0000æä»¤å¼å¸¸")
+ return
+ }
+
+ let mark = characteristic.isNotifying ? "Notify Read" : "Read"
+ let uuid = characteristic.uuid.uuidString
+ Logger.log(mark, uuid, "->", data.joined(" "), "Bytes(\(data.count))")
+
+ if lastSender?.isAnswer(data) == true {
+ deinitTimer()
+
+ let result = lastSender!.parse(data)
+ lastSender?.completion?(result)
+ lastSender?.remove()
+ return
+ }
+
+ if characteristic.uuid.uuidString == readCharacteristicUUID {
+ let info = IBWatchInfo(data)
+ currentConnected.battery = info.battery
+ currentConnected.macAddress = info.macAddress
+ currentConnected.productID = info.productID
+ currentConnected.customerID = info.customerID
+ sendDeviceInfo()
+ return
+ }
+
+// if characteristic.uuid.uuidString == notifyCharacteristicUUID {
+// Logger.log("Notify == ")
+// return
+// }
+ if IBNotify.handle(data) {
+// Logger.log("éç¥æ¶æ¯")
+ return
+ }
+
+ Logger.log("Other handle")
+ }
+
+ /// åå
¥å®æï¼åéæä»¤å®æï¼
+ func peripheral(_ peripheral: CBPeripheral, didWriteValueFor characteristic: CBCharacteristic, error: Error?) {
+ if let error = error {
+ Logger.log(error)
+ return
+ }
+
+ Logger.log(characteristic.uuid.uuidString, "write success")
+ }
+}
+
+extension IBBluetooth {
+
+ static var timer: Timer?
+ func startTimer() {
+ deinitTimer()
+
+ Self.timer = Timer.scheduledTimer(withTimeInterval: 10.0, repeats: false, block: { [unowned self] _ in
+ deinitTimer()
+ lastSender?.completion?(.response.code(.timeout))
+ lastSender?.remove()
+ })
+ Logger.log("åå»ºå®æ¶å¨")
+ }
+
+ func deinitTimer() {
+ guard let _ = Self.timer else { return }
+ Self.timer?.invalidate()
+ Self.timer = nil
+
+ Logger.log("鿝宿¶å¨")
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/IOTBluetooth.h b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IOTBluetooth.h
new file mode 100644
index 0000000..98258c9
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/IOTBluetooth.h
@@ -0,0 +1,18 @@
+//
+// IOTBluetooth.h
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/6.
+//
+
+#import
+
+//! Project version number for IOTBluetooth.
+FOUNDATION_EXPORT double IOTBluetoothVersionNumber;
+
+//! Project version string for IOTBluetooth.
+FOUNDATION_EXPORT const unsigned char IOTBluetoothVersionString[];
+
+// In this header, you should import all the public headers of your framework using statements like #import
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBAbout.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBAbout.swift
new file mode 100644
index 0000000..2e70140
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBAbout.swift
@@ -0,0 +1,24 @@
+//
+// IBAbout.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/28.
+//
+
+import Foundation
+/// å
³äºæ¬æºæ¨¡å
+public class IBAbout:Codable {
+ /// æ è®°ç ï¼ææ°æ®æ´æ°æ¶ä¸º1ï¼æ æ°æ®æ´æ°æ¶ä¸º0ï¼æä¸ç¨
+ public var code: Int = 0
+ /// åºä»¶ä¸»çæ¬å·
+ public var major: Int = 1
+ /// åºä»¶ä¸çæ¬å·
+ public var mid: Int = 0
+ /// åºä»¶æ¬¡çæ¬å·
+ public var minor: Int = 0
+ /// MACå°å
+ public var macAddress: String = ""
+
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBAddressBook.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBAddressBook.swift
new file mode 100644
index 0000000..fef7b43
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBAddressBook.swift
@@ -0,0 +1,71 @@
+//
+// IBAddressBook.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/6/3.
+//
+
+import Foundation
+/// éè®¯å½æ¨¡å
+public class IBAddressBook {
+ /// æ§å« 0ï¼æªæå®ï¼1ï¼ç·æ§ ï¼2ï¼å¥³æ§
+ public var gender: Int = 0
+
+ /// å§å,ä¸ä¼ æè¡¨ä¸æ¾ç¤ºååä¸ºâæªç¥â
+ public var name: String?
+
+ /// çµè¯å·ç ï¼ä¸ä¸ªè系人åä¸å¯ææå°1个æå¤2个çµè¯å·ç
+ public var phoneNumbers: [IBPhoneNumber] = []
+
+
+ public init() { }
+
+ public static func test() -> [IBAddressBook]{
+ var list = [IBAddressBook]();
+ for i in 0...10{
+ let model = IBAddressBook()
+ model.gender = i%2
+ model.name = "å¼ \(i)"
+
+ for j in 0...1{
+ let phone = IBPhoneNumber()
+ phone.number = "1300000000\(j)"
+ phone.location = "æ·±å³å¸å®å®åº\(j)"
+ phone.operator = "ä¸å½ç§»å¨"
+ model.phoneNumbers.append(phone)
+ }
+ list.append(model)
+ }
+
+ return list
+ }
+
+ public var description: String {
+ var phoneStr = "[ "
+ for phone in phoneNumbers {
+ phoneStr += phone.description
+ }
+ phoneStr += " ]"
+ return "IBAddressBook(gender: \(gender), name:\(name ?? ""), phoneNumbers:\(phoneStr))"
+ }
+}
+
+/// çµè¯å·ç 模å
+public class IBPhoneNumber {
+ /// çµè¯å·ç ï¼é¿åº¦1~255
+ public var number: String = ""
+
+ /// å½å±å°ï¼é¿åº¦0~255ï¼ä¸ä¼ æè¡¨ä¸æ¾ç¤ºå½å±å°ä¸ºâæªç¥
+ public var location: String?
+
+ /// è¿è¥åï¼é¿åº¦0~255ï¼ä¸ä¼ æè¡¨ä¸æ¾ç¤ºè¿è¥åä¸ºâæªç¥
+ public var `operator`: String?
+
+ public init() { }
+
+ public var description: String {
+ return "IBPhoneNumber(number: \(number), location:\(location ?? ""), `operator`:\(`operator` ?? ""))"
+ }
+}
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBBloodOxygen.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBBloodOxygen.swift
new file mode 100644
index 0000000..99f6639
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBBloodOxygen.swift
@@ -0,0 +1,42 @@
+//
+// IBBloodOxygen.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/29.
+//
+
+import Foundation
+/// è¡æ°§è®¾ç½®æ¨¡å
+public class IBBloodOxygen {
+ /// çæµé¢ç
+ public var rate: IBBloodOxygenFrequency = .min30
+ /// è¡æ°§æé 0ï¼å
³é 1ï¼å¼å¯ã 为0æ¶åé¢åºé´é弿 é设置ã
+ public var state: Int = 1
+ /// æééå¼ 90~99
+ public var value: Int = 95
+
+ public init() { }
+
+ init(_ data: Data) {
+ rate = IBBloodOxygenFrequency(rawValue:data[0].int) ?? .none
+ state = data[1].int
+ if state == 1 {
+ value = data[2].int
+ }
+ }
+
+ var description: String {
+ return "IBBloodOxygen(rate: \(rate), state:\(state), value:\(value))"
+ }
+}
+/// è¡æ°§çæµé¢ç
+public enum IBBloodOxygenFrequency: Int {
+ /// å
³é
+ case none = 0
+ /// 30åé
+ case min30
+ /// 1å°æ¶
+ case hour1
+ /// 2å°æ¶
+ case hour2
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBClock.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBClock.swift
new file mode 100644
index 0000000..7b12f33
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBClock.swift
@@ -0,0 +1,46 @@
+//
+// IBClock.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/21.
+//
+
+import Foundation
+
+/// é¹é模å
+public class IBClock: Codable {
+ /// é¹éå表
+ public var alarms: [IBClockInfo] = []
+
+ public init() { }
+}
+
+/// é¹éä¿¡æ¯æ¨¡å
+public class IBClockInfo: Codable {
+ /// é¹éid èå´ä¸º0~4. ï¼å³é¹éæå®æå¤è®¾ç½®ä¸º5个ï¼
+ public var id: Int = 0
+ /// å°æ¶
+ public var hour: Int = 0
+ /// åé
+ public var minute: Int = 0
+ /// 0å
³éé¹éï¼1å¼å¯é¹é
+ public var enable: Int = 0
+ /// é¹ééå¤å表
+ ///
+ /// - 0 ä¸éå¤ï¼å䏿¬¡
+ /// - 1 å¨ä¸
+ /// - 2 å¨äº
+ /// - ......
+ /// - 7 卿¥
+ public var `repeat`: [Int] = [0]
+
+// enum CodingKeys: String, CodingKey {
+// case id = "id"
+// case hour = "hour"
+// case minute = "minute"
+// case enable = "enable"
+// case `repeat` = "repeat"
+// }
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBCode.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBCode.swift
new file mode 100644
index 0000000..3711401
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBCode.swift
@@ -0,0 +1,45 @@
+//
+// IBError.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/9.
+//
+
+import Foundation
+
+/// ç¶æç
+public enum IBCode: Int,CustomStringConvertible {
+ public var description: String{
+ return "IBError(rawValue:\(rawValue), message:\(message))"
+ }
+ /// æä½æå
+ case success = 1000
+ /// æä½å¤±è´¥
+ case failure = 1001
+ /// åæ°é误
+ case invalidParam = 1002
+ /// è§£æé误
+ case parseError = 1003
+ /// 请æ±è¶
æ¶
+ case timeout = 1004
+ /// æªç¥é误
+ case unknow = 1005
+
+ var message:String{
+ switch self {
+ case .failure:
+ return "æä½å¤±è´¥"
+ case .success:
+ return "æä½æå"
+ case .invalidParam:
+ return "åæ°é误"
+ case .parseError:
+ return "è§£æé误"
+ case .timeout:
+ return "请æ±è¶
æ¶"
+ default:
+ return "æªç¥é误"
+ }
+ }
+
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHeartRate.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHeartRate.swift
new file mode 100644
index 0000000..554758d
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHeartRate.swift
@@ -0,0 +1,45 @@
+//
+// IBHeartRate.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/16.
+//
+
+import Foundation
+/// å¿ç设置模å
+public class IBHeartRate {
+ /// çæµé¢ç
+ public var rate: IBHeartRateFrequency = .none
+ /// å¿çæé 0ï¼å
³é 1ï¼å¼å¯ã 为0æ¶åé¢åºé´é弿 é设置ã
+ public var state: Int = 1
+ /// å¿çåºé´éå¼ é«äºæä½äº 0ï¼ä½äº 1ï¼é«äº
+ public var higherOrLower: Int = 0
+ /// å¿çåºé´éå¼ 30~200
+ public var value: Int = 100
+
+ public init() { }
+
+ init(_ data: Data) {
+ rate = IBHeartRateFrequency(rawValue:data[0].int) ?? .none
+ state = data[1].int
+ if state == 1 {
+ higherOrLower = data[2].int
+ value = data[3].int
+ }
+ }
+
+ var description: String {
+ return "IBHeartRate(rate: \(rate), state:\(state), higherOrLower:\(higherOrLower), value:\(value))"
+ }
+}
+/// æéé¢ç
+public enum IBHeartRateFrequency: Int {
+ /// å
³é
+ case none = 0
+ /// 1åé
+ case min1
+ /// 5åé
+ case min5
+ /// 10åé
+ case min10
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBaseTraining.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBaseTraining.swift
new file mode 100644
index 0000000..b93cb22
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBaseTraining.swift
@@ -0,0 +1,113 @@
+//
+// IBHistoryBaseTraining.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/21.
+//
+
+import Foundation
+
+/// åºç¡è®ç»å岿°æ®æ¨¡å
+class IBHistoryBaseTraining:Codable {
+ /// è®ç»åå²è®°å½
+ var list:[IBHistoryBaseTrainingItem] = []
+
+ enum CodingKeys: String, CodingKey {
+ case list = "recs"
+ }
+}
+
+/// åºç¡è®ç»å岿°æ®æ¨¡å
+public class IBHistoryBaseTrainingItem:Codable {
+ /// 0:æè¡¨å¼å¯çè®ç»1:APPå¼å¯çè®ç»
+ public var source: Int = 0
+
+ /// ï¼ä»
W4ï¼0ï¼å¥èº«ç±»1ï¼èè¹ç±»2ï¼ä¼é²è¿å¨3ï¼çç±»4ï¼æ°´ä¸é¡¹ç®5ï¼å°ä¸é¡¹ç®6ï¼æéè¿å¨7ï¼å
¶ä»
+ public var otherType: Int?
+
+ /// è®ç»ç±»åï¼0ï¼å¥èµ°1ï¼è·æ¥2ï¼éªè¡ä»¥ä¸éç¨W2/W3ï¼W4è¯¥åæ®µè¡¨ç¤ºåè®ç»å¤§ç±»ä¸çå°ç±»ï¼å¯¹åºè®ç»åç§°åè èªç±è®ç»176.xlsx è¡¨æ ¼ã
+ public var trainingType: Int = 0
+
+ /// è®ç»å¼å§æ¶é´æ³ï¼åä½ç§
+ public var star: Int = 0
+
+ /// è®ç»ç»ææ¶é´æ³ï¼åä½ç§
+ public var stop: Int = 0
+
+ /// è®ç»ç®æ ç±»åï¼0ï¼è·¯ç¨ 1ï¼å¡è·¯é 2ï¼æ¶é´ 3ï¼æ¥æ°
+ public var targetType: Int = 0
+
+ /// è®ç»ç®æ è·¯ç¨ï¼åä½ç±³ï¼ å¡è·¯éï¼åä½kcal ï¼æ¶é´ï¼åä½åé ï¼æ¥æ°ï¼å使¥
+ public var target: Int = 0
+
+ /// ç®æ å®æåº¦ï¼åä½%
+ public var progress: Int = 0
+
+ /// è®ç»æ»æ¶é´ï¼åä½ç§
+ public var duration: Int = 0
+
+ /// å¡è·¯éï¼ä¸ºè¯¥æ°å¼ä¹ä»¥0.1ï¼åä½kcal
+ public var calorie: Int?
+
+ /// è·ç¦»ï¼åä½ç±³
+ public var distance: Int?
+
+ /// å¹³åè¿å¨å¿ç
+ public var heartRate: Int = 0
+
+ /// è¿å¨æ¥æ°
+ public var step: Int?
+
+ /// è®ç»å¼ºåº¦ï¼ä»
W4), 0 = è¾ä½å¼ºåº¦ï¼1 = ä¸ç强度ï¼2 = é«ç强度ï¼3 = è¶
é«å¼ºåº¦
+ public var trainingLevel:Int?
+
+ /// åæ°ï¼ä»
éè·æ¥è®ç»ï¼
+ public var circle: Int?
+
+ /// æé«æµ·æé«åº¦ï¼ä»
éç»å±±è®ç»ï¼
+ public var elevation: Int?
+
+
+ enum CodingKeys: String, CodingKey {
+ case source = "src"
+ case otherType = "bt"
+ case trainingType = "ty"
+ case star = "st"
+ case stop = "sp"
+ case targetType = "tgt"
+ case target = "tg"
+ case progress = "pg"
+ case duration = "du"
+ case calorie = "ca"
+ case distance = "dl"
+ case heartRate = "hr"
+ case step = "stp"
+ case trainingLevel = "tl"
+ case circle = "cir"
+ case elevation = "alt"
+ }
+}
+
+///// è®ç»ç®æ ç±»å
+//public enum IBTrainingTargetType: Int,Codable {
+// /// è·¯ç¨
+// case distance = 0
+// /// å¡è·¯é
+// case calorie
+// /// æ¶é´
+// case time
+// /// æ¥æ°
+// case step
+//}
+
+///// è®ç»å¼ºåº¦
+//public enum IBTrainingLevel: Int,Codable {
+// /// è¾ä½å¼ºåº¦
+// case low = 0
+// /// ä¸ç强度
+// case medium
+// /// é«ç强度
+// case high
+// /// è¶
é«å¼ºåº¦
+// case superHigh
+//}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBloodOxygen.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBloodOxygen.swift
new file mode 100644
index 0000000..e922be8
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBloodOxygen.swift
@@ -0,0 +1,36 @@
+//
+// IBHistoryBloodOxygen.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/28.
+//
+
+import Foundation
+/// è¡æ°§å岿¨¡å
+class IBHistoryBloodOxygen {
+ /// è®°å½
+ var list:[IBHistoryBloodOxygenItem] = []
+
+ init(_ data: Data) {
+ var historyList:[IBHistoryBloodOxygenItem] = []
+ for i in stride(from: 0, to: data.count, by: 5){
+ if data.count > i + 4 {
+ let model = IBHistoryBloodOxygenItem()
+ model.time = data[i...i+3].int
+ model.value = data[i+4].int
+ historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+
+/// è¡æ°§åå²è®°å½
+public class IBHistoryBloodOxygenItem {
+ /// æ¶é´æ³
+ public var time: Int = 0
+ /// è¡æ°§ï¼åä½%
+ public var value: Int = 0
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBurning.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBurning.swift
new file mode 100644
index 0000000..33f1466
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryBurning.swift
@@ -0,0 +1,36 @@
+//
+// IBHistoryBurning.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/28.
+//
+
+import Foundation
+/// çèå岿¨¡å
+ class IBHistoryBurning {
+ /// è®°å½
+ var list:[IBHistoryBurningItem] = []
+
+ init(_ data: Data) {
+ var historyList:[IBHistoryBurningItem] = []
+ for i in stride(from: 0, to: data.count, by: 6){
+ if data.count > i + 5 {
+ let model = IBHistoryBurningItem()
+ model.time = data[i...i+3].int
+ model.value = data[i+4...i+5].int
+ historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+
+/// çèåå²è®°å½
+public class IBHistoryBurningItem {
+ /// æ¶é´æ³
+ public var time: Int = 0
+ /// åä½åé
+ public var value: Int = 0
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryCalorie.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryCalorie.swift
new file mode 100644
index 0000000..b6e2e87
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryCalorie.swift
@@ -0,0 +1,36 @@
+//
+// IBHistoryCalorie.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/28.
+//
+
+import Foundation
+/// å¡è·¯éå岿¨¡å
+ class IBHistoryCalorie {
+ /// è®°å½
+ var list:[IBHistoryCalorieItem] = []
+
+ init(_ data: Data) {
+ var historyList:[IBHistoryCalorieItem] = []
+ for i in stride(from: 0, to: data.count, by: 8){
+ if data.count > i + 7 {
+ let model = IBHistoryCalorieItem()
+ model.time = data[0...3].int
+ model.value = data[i+4...i+7].int
+ historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+
+/// å¡è·¯éåå²è®°å½
+public class IBHistoryCalorieItem {
+ /// æ¶é´æ³
+ public var time: Int = 0
+ /// åä½kcal
+ public var value: Int = 0
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryDistance.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryDistance.swift
new file mode 100644
index 0000000..0c876bd
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryDistance.swift
@@ -0,0 +1,36 @@
+//
+// IBHistoryDistance.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/28.
+//
+
+import Foundation
+/// å¡è·¯éå岿¨¡å
+ class IBHistoryDistance {
+ /// åå²è®°å½
+ var list:[IBHistoryDistanceItem] = []
+
+ init(_ data: Data) {
+ var historyList:[IBHistoryDistanceItem] = []
+ for i in stride(from: 0, to: data.count, by: 8){
+ if data.count > i + 7 {
+ let model = IBHistoryDistanceItem()
+ model.time = data[i...i+3].int
+ model.value = data[i+4...i+7].int
+ historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+
+/// è·ç¦»åå²è®°å½
+public class IBHistoryDistanceItem {
+ /// æ¶é´æ³
+ public var time: Int = 0
+ /// åä½km
+ public var value: Int = 0
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryGps.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryGps.swift
new file mode 100644
index 0000000..78eb6fc
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryGps.swift
@@ -0,0 +1,40 @@
+//
+// IBHistoryGps.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/30.
+//
+
+import Foundation
+
+/// åæ¥è·¯å¾åæ å岿°æ®æ¨¡å
+public class IBHistoryGps {
+ /// è®°å½
+ var list:[IBHistoryGpsItem] = []
+
+ init(_ data: Data) {
+ var historyList:[IBHistoryGpsItem] = []
+ for i in stride(from: 0, to: data.count, by: 12){
+ if data.count > i + 11 {
+ let model = IBHistoryGpsItem()
+ model.time = data[i...i+3].int
+ model.lon = data[i+4...i+7].int
+ model.lat = data[i+8...i+11].int
+ historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+/// åæ¥è·¯å¾åæ å岿°æ®æ¨¡å
+public class IBHistoryGpsItem {
+ /// unixæ¶é´æ³
+ public var time: Int = 0
+ /// 纬度ï¼è¯¥å¼é¤ä»¥10000000å¾å°å®é
纬度å¼
+ public var lat: Int = 0
+ /// ç»åº¦ï¼è¯¥å¼é¤ä»¥10000000å¾å°å®é
ç»åº¦å¼
+ public var lon: Int = 0
+
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryHeartRate.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryHeartRate.swift
new file mode 100644
index 0000000..ad3248f
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryHeartRate.swift
@@ -0,0 +1,36 @@
+//
+// IBHistoryHeartRate.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/21.
+//
+
+import Foundation
+/// å¿çå岿¨¡å
+ class IBHistoryHeartRate {
+ /// è®°å½
+ var list:[IBHistoryHeartRateItem] = []
+
+ init(_ data: Data) {
+ var historyList:[IBHistoryHeartRateItem] = []
+ for i in stride(from: 0, to: data.count, by: 5){
+ if data.count > i + 4 {
+ let model = IBHistoryHeartRateItem()
+ model.time = data[i...i+3].int
+ model.value = data[i+4].int
+ historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+
+/// å¿çåå²è®°å½
+public class IBHistoryHeartRateItem {
+ /// æ¶é´æ³
+ public var time: Int = 0
+ /// å¿ç
+ public var value: Int = 0
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistorySleep.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistorySleep.swift
new file mode 100644
index 0000000..ebf1904
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistorySleep.swift
@@ -0,0 +1,86 @@
+//
+// IBHistorySleep.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/30.
+//
+
+import Foundation
+/// ç¡ç å岿¨¡å
+ class IBHistorySleep {
+ /// è®°å½
+ var list:[IBHistorySleepItem] = []
+
+ init(_ data: Data) {
+ if(data.count <= 0){
+ return
+ }
+
+ var historyList:[IBHistorySleepItem] = []
+ let number = data[0].int
+
+
+ for i in stride(from: 0, to: data.count, by: 8){
+ if data.count > i + 7 {
+ let model = IBHistorySleepItem()
+// model.time = data[i...i+3].int
+// model.value = data[i+4...i+7].int
+// historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+
+/// ç¡ç åå²è®°å½
+public class IBHistorySleepItem {
+ /// ç¡ç IDï¼0~255ï¼è¡¨ç¤ºç¬¬å 次ç¡ç
+ public var sleepId: UInt8 = 0
+ /// ç¡ç ç±»åï¼0ï¼å°ç¡ï¼æ æ»æ¶é¿ä¹åçææé¡¹ç®ï¼1ï¼ç¡ç
+ public var type: Int = 0
+ /// å
¥ç¡æ¶é´æ³ï¼Unixæ¶é´æ³
+ public var startTime: Int = 0
+ /// åºç¡æ¶é´æ³ï¼Unixæ¶é´æ³
+ public var endTime: Int = 0
+ /// æ»æ¶é¿
+ public var totalSleep: IBSleepTime = IBSleepTime(hour: 0, minute: 0)
+ /// æ·±ç¡æ¶é¿
+ public var deepSleep: IBSleepTime = IBSleepTime(hour: 0, minute: 0)
+ /// æµ
ç¡æ¶é¿
+ public var lightSleep: IBSleepTime = IBSleepTime(hour: 0, minute: 0)
+ /// å¿«éå¨ç¼æ¶é¿
+ public var remSleep: IBSleepTime = IBSleepTime(hour: 0, minute: 0)
+ /// æ¸
éæ¶é¿
+ public var awake: IBSleepTime = IBSleepTime(hour: 0, minute: 0)
+ /// ç¡ç ç¶æ
+ public var states:[IBSleepState] = []
+
+
+ public init() { }
+}
+
+/// æ¶é´
+public struct IBSleepTime {
+ /// æ¶
+ public var hour: UInt8
+ /// å 0~59
+ public var minute: UInt8
+
+ public init(hour: UInt8, minute: UInt8) {
+ self.hour = hour
+ self.minute = minute
+ }
+
+ var description: String {
+ return "IBSleepTime(hour: \(hour), minute:\(minute)"
+ }
+}
+
+
+/// ç¡ç ç¶æ
+public class IBSleepState {
+ /// Unixæ¶é´æ³
+ public var time: Int32 = 0
+ /// ç¶æï¼0ï¼è¿å
¥ç¡ç 1ï¼æµ
å±ç¡ç 2ï¼æ·±å±ç¡ç 3ï¼æ¸
é 4ï¼ç»æç¡ç 7ï¼æªåºç¡æåä¸ç¬ç¡ç æ°æ®ï¼èµæä¸æ¥ç»ææ å¿ï¼ 9ï¼åºç¡æåä¸ç¬ç¡ç æ°æ®ï¼èµæä¸æ¥ç»ææ å¿ï¼ 12ï¼å¿«éç¼å¨ 13ï¼åæ¶å
¥ç¡éç¥ï¼ç¡ç ä¸è¶³ 60 åéåºç¡ä¸æ¥ç¶æï¼ 14ï¼ç»æå°ç¡
+ public var state: Int8 = 0
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryStand.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryStand.swift
new file mode 100644
index 0000000..918a8f8
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryStand.swift
@@ -0,0 +1,33 @@
+//
+// IBHistoryStand.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/28.
+//
+
+import Foundation
+/// ç«ç«å岿¨¡å
+ class IBHistoryStand {
+ /// è®°å½
+ var list:[IBHistoryStandItem] = []
+
+ init(_ data: Data) {
+ var historyList:[IBHistoryStandItem] = []
+ for i in stride(from: 0, to: data.count, by: 4){
+ if data.count > i + 3 {
+ let model = IBHistoryStandItem()
+ model.time = data[i...i+3].int
+ historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+
+/// ç«ç«åå²è®°å½
+public class IBHistoryStandItem {
+ /// æ¶é´æ³
+ public var time: Int = 0
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryStep.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryStep.swift
new file mode 100644
index 0000000..538bc4b
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBHistoryStep.swift
@@ -0,0 +1,36 @@
+//
+// IBHistoryStep.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/28.
+//
+
+import Foundation
+/// æ¥æ°å岿¨¡å
+ class IBHistoryStep {
+ /// è®°å½
+ var list:[IBHistoryStepItem] = []
+
+ init(_ data: Data) {
+ var historyList:[IBHistoryStepItem] = []
+ for i in stride(from: 0, to: data.count, by: 8){
+ if data.count > i + 7 {
+ let model = IBHistoryStepItem()
+ model.time = data[i...i+3].int
+ model.value = data[i+4...i+7].int
+ historyList.append(model)
+ }
+ }
+ list = historyList
+ }
+}
+
+/// æ¥æ°åå²è®°å½
+public class IBHistoryStepItem {
+ /// æ¶é´æ³
+ public var time: Int = 0
+ /// å使¥
+ public var value: Int = 0
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBLanguage.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBLanguage.swift
new file mode 100644
index 0000000..722f730
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBLanguage.swift
@@ -0,0 +1,58 @@
+//
+// IBLanguage.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/20.
+//
+
+import Foundation
+
+/// è¯è¨åå§å¼ä» 0 å¼å§éå¢
+public enum IBLanguage: Int {
+ /// 䏿
+ case chinese = 0
+ /// è±è¯
+ case english
+ /// æ¥æ¬è¯
+ case japanese
+ /// é©è¯
+ case korean
+ /// 西ççè¯
+ case spanish
+ /// ä¿è¯
+ case russian
+ /// å
ç½å°äºè¯
+ case croatian
+ /// å¾·è¯
+ case german
+ /// è¡èçè¯
+ case portuguese
+ /// æ³è¯
+ case french
+ /// è·å
°è¯
+ case dutch
+ /// æå¤§å©è¯
+ case italian
+ /// æ·å
è¯
+ case czech
+ /// å¸è
è¯
+ case greek
+ /// å°åº¦è¯
+ case hindi
+ /// å°åº¦å°¼è¥¿äºè¯
+ case indonesian
+ /// 马æ¥è¥¿äºè¯
+ case malaysian
+ /// æ³¢å
°è¯
+ case polish
+ /// æ³°è¯
+ case thai
+ /// è¶åè¯
+ case vietnamese
+ /// è¬å
°è¯
+ case finnish
+ /// ç½é©¬å°¼äºè¯
+ case romanian
+ /// åè³å
¶è¯
+ case turkish
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBManufacturer.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBManufacturer.swift
new file mode 100644
index 0000000..6300d84
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBManufacturer.swift
@@ -0,0 +1,37 @@
+//
+// IBManufacturer.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/14.
+//
+
+import Foundation
+
+/// å¹¿ææ°æ®å
è§£æ
+struct IBManufacturer {
+ init?(_ data: Data) {
+ guard data.count == 14 else { return nil }
+
+ code = data[0...1].string ?? ""
+ guard code == "JH" else { return nil }
+
+ isBind = data[2].int
+ macAddress = data[3...8].reversedJoined(":")
+ customerID = data[9].int
+ productID = data[10].int
+ softwareVersion = data[11..<14].joined(format: "%d", ".")
+ }
+
+ /// è¯å«ç¬¦
+ let code: String
+ /// æ¯å¦å·²ç»å®(1=å·²ç»å®)
+ let isBind: Int
+ /// mac å°å
+ let macAddress: String
+ /// å®¢æ· ID
+ let customerID: Int
+ /// 产å ID
+ let productID: Int
+ /// è½¯ä»¶çæ¬
+ let softwareVersion: String
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBOtherTarget.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBOtherTarget.swift
new file mode 100644
index 0000000..fd0aaf7
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBOtherTarget.swift
@@ -0,0 +1,41 @@
+//
+// IBUserInfo.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/14.
+//
+
+import Foundation
+/// å
¶ä»ç®æ 设置模å
+public class IBOtherTarget {
+ /// ç®æ å¡è·¯éï¼åä½åå¡
+ public var calorie: Int = 0
+ /// ç®æ éç¨ï¼åä½å
Ž
+ public var mileage: Int = 1
+ /// ç®æ ç«ç«æ¬¡æ°ï¼å使¬¡
+ public var stand: Int = 0
+ /// ç®æ çèæ¶é´ï¼åä½åé
+ public var burning: Int = 0
+ /// é声æé 0ï¼å
³é 1ï¼å¼å¯
+ public var ringsState: Int = 0
+ /// é卿é 0ï¼å
³é 1ï¼å¼å¯
+ public var vibrateState: Int = 0
+ /// éç¥æé 0ï¼å
³é 1ï¼å¼å¯
+ public var noticeState: Int = 0
+
+ public init() { }
+
+ init(_ data: Data) {
+ calorie = data[0...1].int
+ mileage = data[2].int
+ stand = data[3].int
+ burning = data[4].int
+ ringsState = data[5].int
+ vibrateState = data[6].int
+ noticeState = data[7].int
+ }
+
+ var description: String {
+ return "IBOtherTarget(calorie: \(calorie), mileage:\(mileage), stand:\(stand), burning:\(burning), ringsState:\(ringsState), vibrateState:\(vibrateState), noticeState:\(noticeState))"
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBPeripheral.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBPeripheral.swift
new file mode 100644
index 0000000..02fd72c
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBPeripheral.swift
@@ -0,0 +1,55 @@
+//
+// IBPeripheral.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/6.
+//
+
+import Foundation
+import CoreBluetooth
+
+public class IBPeripheral {
+
+ /// ä¿¡å·å¼ºåº¦(åè´)
+ public internal(set) var rssi: Int = 0
+
+ /// å¤å´è®¾å¤å®ä¾
+ public internal(set) var peripheral: CBPeripheral! {
+ didSet {
+ if let name = peripheral.name {
+ self.name = name
+ }
+ uuid = peripheral.identifier
+ }
+ }
+
+ /// mac å°å
+ public internal(set) var macAddress: String = ""
+
+ /// å¹¿ææ°æ®
+ public internal(set) var advertisementData: [String: Any] = [:]
+
+ /// CBPeripheral.identifier
+ public private(set) var uuid: UUID!
+
+ /// åç§°
+ public private(set) var name: String = "Unknown"
+
+ /// è½¯ä»¶çæ¬
+ public internal(set) var softwareVersion: String = ""
+
+ /// çµéï¼è¿æ¥è®¾å¤åå¯ç¨ï¼é»è®¤ä¸º 0
+ public internal(set) var battery: Int = 0
+
+ /// è¯å«ç¬¦
+ var code: String = ""
+
+ /// æ¯å¦ç»å®(1=ç»å®)
+ var isBind: Int = 0
+
+ /// å®¢æ· ID
+ var customerID: Int = 0
+
+ /// 产åID
+ var productID: Int = 0
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBPhoneInfo.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBPhoneInfo.swift
new file mode 100644
index 0000000..0387b03
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBPhoneInfo.swift
@@ -0,0 +1,25 @@
+//
+// IBDeviceInfo.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/23.
+//
+
+import Foundation
+/// ææºä¿¡æ¯æ¨¡å
+public class IBPhoneInfo:Codable {
+ /// ææºåç§°
+ public var name: String = "iphone"
+ /// ææºç±»å 0ï¼å®å 1ï¼è¹æ
+ public var type: Int = 1
+ /// ææºMACå°åæ°ç»ï¼ä»
IOSï¼é
对æåä»æè¡¨è·åï¼æªè·åæ¶ä¸ºç©ºï¼
+ public var mac: [Int]?
+
+ enum CodingKeys: String, CodingKey {
+ case name = "pn"
+ case type = "tp"
+ case mac = "mac"
+ }
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBResponse.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBResponse.swift
new file mode 100644
index 0000000..27891f4
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBResponse.swift
@@ -0,0 +1,77 @@
+//
+// IBResponse.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/15.
+//
+
+import Foundation
+
+public class IBResponseModel {
+ var data:Data!
+ required init(_ data: Data) {
+ self.data = data
+ }
+
+ var pkgData:Data{
+ if(data.count > 18){
+ return data[17...data.count - 2]
+ }
+ return Data()
+ }
+}
+
+
+public class IBResponse:CustomStringConvertible {
+ /// ç¶æç
+ public private(set) var code: IBCode = .success
+ /// åé¦ä¿¡æ¯
+ public private(set) var message: String = "æä½æå"
+ /// å½æåæ¶ä¸º true
+ public private(set) var isSuccess: Bool = false
+ /// å½ç»æä¸ºéåæ¶ï¼åºè¯¥ä»æ¤å段读å
+ public private(set) var items: [Any] = []
+ /// å½ç»æä¸ºééåï¼åºè¯¥ä»æ¤å段读å
+ public private(set) var value: Any?
+
+ static var response: IBResponse { IBResponse() }
+
+ public var description: String {
+ var des = "IBResponse(code: \(code.rawValue),isSuccess: \(isSuccess), massage:\(message), "
+ if let v1 = value {
+ des.append("value:\(v1)ï¼")
+ }
+ else{
+ des.append("items:\(items)ï¼")
+ }
+ return des
+ }
+}
+
+extension IBResponse {
+ @discardableResult
+ func code(_ value: IBCode) -> Self {
+ code = value
+ isSuccess = code == .success
+ message = code.message
+ return self
+ }
+
+ @discardableResult
+ func message(_ value: String) -> Self {
+ message = value
+ return self
+ }
+
+ @discardableResult
+ func items(_ value: [Any]) -> Self {
+ items = value
+ return self
+ }
+
+ @discardableResult
+ func value(_ value: Any) -> Self {
+ self.value = value
+ return self
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBScreen.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBScreen.swift
new file mode 100644
index 0000000..26d3cbd
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBScreen.swift
@@ -0,0 +1,46 @@
+//
+// IBScreen.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/21.
+//
+
+import Foundation
+
+/// å±å¹åæ°
+public class IBScreen {
+ /// 亮度 [0, 255]
+ public var brightness: Int = 10
+
+ /// äº®å±æ¶é¿
+ public var duration: IBDuration = .second10
+
+ /// æ¬è
亮å±(0=å
³éï¼ 1=å¼å¯)
+ public var wrist: Int = 1
+
+ public init() { }
+
+ init(_ data: Data) {
+ brightness = data[0].int
+ duration = IBDuration(rawValue: data[1].int) ?? .second5
+ wrist = data[2].int
+ }
+ var description: String {
+ return "IBScreen(brightness: \(brightness), duration:\(duration), wrist:\(wrist))"
+ }
+}
+
+public enum IBDuration: Int {
+ /// 5 ç§
+ case second5 = 0
+ /// 10 ç§
+ case second10
+ /// 15 ç§
+ case second15
+ /// 30 ç§
+ case second30
+ /// 1 åé
+ case minute
+ /// 5 åé
+ case minute5
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBSendTime.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBSendTime.swift
new file mode 100644
index 0000000..5cb39eb
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBSendTime.swift
@@ -0,0 +1,30 @@
+//
+// IBSendTime.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/23.
+//
+
+import Foundation
+/// åéæ¶é´æ¨¡å
+public class IBSendTime:Codable {
+ /// unixæ¶é´æ³
+ public var time: Int = 0
+ /// 0-6ï¼å¨æ¥-å¨å
+ public var week: Int = 0
+ /// 0-127ï¼å¹´ä»½åå»2000
+ public var year: Int = 0
+ /// 1-12
+ public var month: Int = 1
+ /// 1-31
+ public var day: Int = 1
+ /// 0-24
+ public var hour: Int = 0
+ /// 0-60
+ public var minute: Int = 0
+ /// 0-60
+ public var second: Int = 0
+
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBSleep.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBSleep.swift
new file mode 100644
index 0000000..04e703a
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBSleep.swift
@@ -0,0 +1,56 @@
+//
+// IBSleep.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/15.
+//
+
+import Foundation
+/// ç¡ç 设置模å
+public class IBSleep {
+ /// 0ï¼å
³é 1ï¼å¼å¯ 为0æ¶å颿æé¡¹ç®é½æ é设置ã
+ public var sleepTimeSet: Int = 0
+ /// 就坿¶é´
+ public var sleepTime: IBTimeItem?
+ /// èµ·åºæ¶é´
+ public var getUpTime: IBTimeItem?
+ /// å°±å¯å20åéæé,0ï¼å
³é1ï¼å¼å¯
+ public var alertBeforeMin20: Int = 0
+
+ init(_ data: Data) {
+ sleepTimeSet = data[0].int
+ if sleepTimeSet == 1{
+ sleepTime = IBTimeItem(hour: data[1].int, minute: data[2].int)
+ getUpTime = IBTimeItem(hour: data[3].int, minute: data[4].int)
+ alertBeforeMin20 = data[5].int
+ }
+ }
+ public init() {
+// sleepTimeSet = 1
+// sleepTime = IBTimeItem(hour: 7, minute: 30)
+// getUpTime = IBTimeItem(hour: 15, minute: 50)
+// alertBeforeMin20 = 0
+ }
+
+ var description: String {
+ return "IBSleep(sleepTimeSet: \(sleepTimeSet), sleepTime:\(sleepTime?.description ?? ""), getUpTime:\(getUpTime?.description ?? ""), alertBeforeMin20:\(alertBeforeMin20))"
+ }
+
+}
+
+/// æ¶é´
+public struct IBTimeItem {
+ /// 0~23
+ public var hour: Int
+ /// 0~59
+ public var minute: Int
+
+ public init(hour: Int, minute: Int) {
+ self.hour = hour
+ self.minute = minute
+ }
+
+ var description: String {
+ return "IBTimeItem(hour: \(hour), minute:\(minute)"
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTargetStep.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTargetStep.swift
new file mode 100644
index 0000000..5666ca8
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTargetStep.swift
@@ -0,0 +1,37 @@
+//
+// IBTargetStep.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/21.
+//
+
+import Foundation
+/// ç®æ æ¥æ°æ¨¡å
+public class IBTargetStep {
+
+ /// æ¥æ°
+ public var value: Int = 5000
+
+ /// é声æé(0=å
³éï¼1=å¼å¯)
+ public var ring: Int = 0
+
+ /// é卿é(0=å
³éï¼1=å¼å¯)
+ public var vibrate: Int = 0
+
+ /// éç¥æé(0=å
³éï¼1=å¼å¯)
+ public var notice: Int = 0
+
+ init?(_ data: Data) {
+ guard data.count == 7 else { return nil }
+ value = data[0...3].int
+ ring = data[4].int
+ vibrate = data[5].int
+ notice = data[6].int
+ }
+
+ var description: String {
+ return "IBTargetStep(value: \(value), ring:\(ring), vibrate: \(vibrate), notice:\(notice))"
+ }
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTarinState.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTarinState.swift
new file mode 100644
index 0000000..9e048fe
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTarinState.swift
@@ -0,0 +1,26 @@
+//
+// IBTarinState.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/28.
+//
+
+import Foundation
+/// æ¨éè®ç»ç¶ææ¨¡å
+public class IBTarinState {
+ /// ç¶æ 0ï¼ç»æ 1ï¼å¼å§ 2ï¼æå 3ï¼æ¢å¤
+ public var state: Int = 1
+ /// è®ç»æ¶é¿ï¼åä½ç§
+ public var duration: Int = 0
+
+ public init() { }
+
+ init(_ data: Data) {
+ state = data[0].int
+ duration = data[1...2].int
+ }
+
+ public var description: String {
+ return "IBTarinState(state: \(state), duration:\(duration))"
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTrainTarget.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTrainTarget.swift
new file mode 100644
index 0000000..bbc1946
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTrainTarget.swift
@@ -0,0 +1,46 @@
+//
+// IBaa.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/16.
+//
+
+import Foundation
+/// è®ç»ç®æ 设置模å
+public class IBTrainTarget:Codable {
+ /// ç®æ ç±»å,对åºçç±»åï¼è®¾ç½®å¯¹åºçå¼
+ public var type: IBTrainTargetType = .calorie
+ /// ç®æ è·ç¦»ï¼åä½ç±³
+ public var distance: Int?
+ /// ç®æ å¡è·¯éï¼åä½kcal
+ public var calorie: Int?
+ /// ç®æ æ¶é´ï¼åä½åé
+ public var time: Int?
+ /// ç®æ æ¥æ°ï¼å使¥
+ public var step: Int?
+
+ public init() { }
+
+ enum CodingKeys: String, CodingKey {
+ case type = "ty"
+ case distance = "di"
+ case calorie = "ca"
+ case time = "tm"
+ case step = "st"
+ }
+ var description: String {
+ return "IBTrainTarget(type: \(type), distance:\(distance ?? 0), calorie:\(calorie ?? 0), time:\(time ?? 0), step:\(step ?? 0))"
+ }
+}
+
+/// æéé¢ç
+public enum IBTrainTargetType: Int,Codable {
+ /// è·ç¦»
+ case distance = 0
+ /// å¡è·¯é
+ case calorie = 1
+ /// æ¶é´
+ case time = 2
+ /// æ¥æ°
+ case step = 4
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTrainingData.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTrainingData.swift
new file mode 100644
index 0000000..270c59e
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBTrainingData.swift
@@ -0,0 +1,48 @@
+//
+// IBTrainingData.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/20.
+//
+
+import Foundation
+
+/// è®ç»æ°æ®æ¨¡å
+public struct IBTrainingData {
+ /// è®ç»å¼å§æ¶é´(æ¶é´æ³)
+ public let startTime: Int
+
+ /// 宿¶è®ç»å¿çï¼åä½bpm
+ public let heartRate: Int
+
+ /// 宿¶è®ç»å¡è·¯éï¼åä½kcal
+ public let calorie: Int
+
+ /// 宿¶è®ç»è·ç¦»ï¼åä½ç±³
+ public let distance: Int
+
+ /// 宿¶è®ç»æ¥æ°ï¼å使¥
+ public let stepCount: Int
+
+ /// 宿¶è®ç»å¼ºåº¦
+ ///
+ /// - 0ï¼è¾ä½å¼ºåº¦
+ /// - 1ï¼ä¸ç强度
+ /// - 2ï¼é«ç强度
+ /// - 3ï¼è¶
é«å¼ºåº¦
+ public let intensity: Int
+
+ init?(_ data: Data) {
+ guard let dict = data.jsonObject() as? [String: Int] else { return nil }
+ self.startTime = dict["st"]!
+ self.heartRate = dict["hr"]!
+ self.calorie = dict["ca"]!
+ self.distance = dict["di"]!
+ self.stepCount = dict["stp"]!
+ self.intensity = dict["ti"]!
+ }
+
+ public var description: String {
+ return "IBTrainingData(startTime: \(startTime), heartRate:\(heartRate), calorie:\(calorie), distance:\(distance), stepCount:\(stepCount), intensity:\(intensity))"
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBUserInfo.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBUserInfo.swift
new file mode 100644
index 0000000..34e8192
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBUserInfo.swift
@@ -0,0 +1,45 @@
+//
+// IBUserInfo.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/30.
+//
+
+import Foundation
+/// ç¨æ·æ°æ®æ¨¡å
+public class IBUserInfo {
+ /// å¹´é¾
+ public var age: Int = 0
+ /// æ§å« 0ï¼ç·æ§ 1ï¼å¥³æ§
+ public var gender: Int = 0
+ /// 身é«ï¼ åä½cm
+ public var height: Int = 0
+ /// ä½éï¼ åä½kg
+ public var weight: Int = 0
+ /// ç®æ æ¥æ°
+ public var step: Int = 0
+ /// ç®æ çèæ¶é´ï¼åä½åé
+ public var burning: Int = 0
+ /// ç®æ ç«ç«æ¬¡æ°
+ public var stand: Int = 0
+ /// æ¶å¶ 0:24å°æ¶å¶ 1:12å°æ¶å¶
+ public var hourSystem: Int = 0
+
+
+ public init() { }
+
+ init(_ data: Data) {
+ age = data[0].int
+ gender = data[1].int
+ height = data[2].int
+ weight = data[3...4].int
+ step = data[5...8].int
+ burning = data[9...10].int
+ stand = data[11].int
+ hourSystem = data[12].int
+ }
+
+ public var description: String {
+ return "IBUserInfo(age: \(age), gender:\(gender), height:\(height), weight:\(weight), step:\(step), burning:\(burning), stand:\(stand), hourSystem:\(hourSystem))"
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBVibrateSound.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBVibrateSound.swift
new file mode 100644
index 0000000..802fdc8
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBVibrateSound.swift
@@ -0,0 +1,39 @@
+////
+//// IBVibrateSound.swift
+//// IOTBluetooth
+////
+//// Created by incar on 2024/5/9.
+////
+//
+/// 声é³é卿¨¡å
+public class IBVibrateSound {
+ /// ç³»ç»é³éè°è0~100
+ public var systemValue: Int = 0
+
+ /// é声é³éè°è0~100
+ public var ringsValue: Int = 0
+
+ /// åªä½é³éè°è0~100
+ public var mediaValue: Int = 0
+
+ /// é声å¼å
³0ï¼å
³é 1ï¼å¼å¯
+ public var ringsState: Int = 0
+
+ /// éå¨å¼å
³0ï¼å
³é 1ï¼å¼å¯
+ public var vibrateState: Int = 0
+
+ public init() { }
+
+ init(_ data: Data) {
+ systemValue = data[0].int
+ ringsValue = data[1].int
+ mediaValue = data[2].int
+ ringsState = data[3].int
+ vibrateState = data[4].int
+ }
+
+ var description: String {
+ return "IBVibrateSound(systemValue: \(systemValue), ringsValue:\(ringsValue), mediaValue:\(mediaValue), ringsState:\(ringsState), vibrateState:\(vibrateState))"
+ }
+}
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWatchInfo.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWatchInfo.swift
new file mode 100644
index 0000000..2a7c0c1
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWatchInfo.swift
@@ -0,0 +1,46 @@
+//
+// IBWatchInfo.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/14.
+//
+
+import Foundation
+
+/// æè¡¨ä¿¡æ¯
+struct IBWatchInfo {
+
+ init(_ data: Data) {
+ battery = data[0].int
+ dialID = data[1...2].int
+ firmwareVersion = data[3...5].joined(format: "%d", ".")
+ macAddress = data[6...11].joined(":")
+ messagePush = data[12].int
+ media = data[13].int
+ customerID = data[14].int
+ productID = data[15].int
+ hardwareVersion = data[16...17].joined(format: "%d", ".")
+ bluetoothVersion = data[18...19].joined(format: "%d", ".")
+ }
+
+ /// çµé
+ let battery: Int
+ /// 表çID
+ let dialID: Int
+ /// åºä»¶çæ¬
+ let firmwareVersion: String
+ /// mac å°å
+ let macAddress: String
+ /// æ¶æ¯æ¨é 1=å¼å¯
+ let messagePush: Int
+ /// å¤åªä½ 1=å¼å¯
+ let media: Int
+ /// ç¡¬ä»¶çæ¬
+ let hardwareVersion: String
+ /// èççæ¬
+ let bluetoothVersion: String
+ /// å®¢æ· ID
+ let customerID: Int
+ /// 产å ID
+ let productID: Int
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWater.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWater.swift
new file mode 100644
index 0000000..1da5ebd
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWater.swift
@@ -0,0 +1,45 @@
+//
+// IBWater.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/15.
+//
+
+
+import Foundation
+/// åæ°´æé设置模å
+public class IBWater {
+ /// 0ï¼å
³é 1ï¼å¼å¯ 为0æ¶å颿æé¡¹ç®é½æ é设置ã
+ public var alertState: Int = 0
+ /// æéæ¹å¼0ï¼æ¯å¤©æé䏿¬¡ 1ï¼é´éæé
+ public var alertType: Int = 0
+ /// é¥®æ°´ç®æ 500~5000ml
+ public var drinkingValue: Int = 0
+ /// æéå¼å§æ¶é´
+ public var start:IBTimeItem = IBTimeItem(hour: 0, minute: 0)
+ /// æéç»ææ¶é´ãä»
é´éæééè¦ï¼å
¶ä»æ
åµä¸å¡«
+ public var end:IBTimeItem = IBTimeItem(hour: 0, minute: 0)
+ /// æéé¢çãä»
é´éæééè¦ï¼å
¶ä»æ
åµä¸å¡«
+ public var frequency: IBFrequency = IBFrequency.min30
+
+ public init() { }
+
+ var description: String {
+ return "IBWater(alertState: \(alertState), alertType:\(alertType), drinkingValue:\(drinkingValue), start:\(start.description), end:\(end.description), frequency:\(frequency.rawValue))"
+ }
+}
+
+
+/// æéé¢ç
+public enum IBFrequency: Int {
+ /// 30åé
+ case min30 = 0
+ /// 1å°æ¶
+ case hour1
+ /// 2å°æ¶
+ case hour2
+ /// 3å°æ¶
+ case hour3
+ /// å
¶ä»æ
åµ
+ case none
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWeather.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWeather.swift
new file mode 100644
index 0000000..5409798
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Models/IBWeather.swift
@@ -0,0 +1,70 @@
+//
+// IBWeather.swift
+// IOTBluetooth
+//
+// Created by incar on 2024/5/30.
+//
+
+import Foundation
+/// å¤©æ°æ¨¡å
+public class IBWeather:Codable {
+ /// å½åå®ä½å°å
+ public var address: IBAddress = IBAddress()
+ /// å½å天æ°ä¿¡æ¯
+ public var now: IBWeatherNow = IBWeatherNow()
+ /// ä¸å¤©å¤©æ°ä¿¡æ¯
+ public var daily: [IBWeatherInfo] = []
+
+
+ public init() { }
+}
+
+
+/// å°å模å
+public class IBAddress:Codable {
+ /// åå¸
+ public var city: String = ""
+ /// åº
+ public var subLocality: String = ""
+ /// 纬度ï¼è¯¥å¼é¤ä»¥10000000å¾
+ public var lat: Int = 0
+ /// ç»åº¦ï¼è¯¥å¼é¤ä»¥10000000å¾å°å®é
纬度å¼
+ public var lon: Int = 0
+ /// æ°åï¼åä½hPa
+ public var atm: Int = 0
+
+ public init() { }
+}
+
+/// 天æ°ä¿¡æ¯æ¨¡å
+public class IBWeatherInfo:Codable {
+ /// 颿¥æ¥æï¼æ¶é´æ³
+ public var fxDate: Int = 1654012800
+ /// 颿¥ç½å¤©å¤©æ°ç¶åµç徿 代ç
+ public var iconDay: Int = 0
+ /// 颿¥ç½å¤©å¤©æ°ç¶åµæåæè¿°ï¼å
æ¬é´æ´é¨éªç天æ°ç¶æçæè¿°
+ public var textDay: String = ""
+ /// 颿¥å½å¤©æé«æ¸©åº¦
+ public var tempMax: Int = 0
+ /// 颿¥å½å¤©æä½æ¸©åº¦
+ public var tempMin: Int = 0
+
+ public init() { }
+}
+/// ç°å¨å¤©æ°ä¿¡æ¯æ¨¡å
+public class IBWeatherNow:Codable {
+ /// å½å温度
+ public var temp: Int = 0
+ /// 夿天æ°icon徿
+ public var iconNight: Int = 0
+ /// å¤æå¤©æ°æ
åµ
+ public var textNight: String = ""
+ /// é£å
+ public var windScale: String = ""
+ /// 湿度%
+ public var humidity: Int = 0
+ /// ç´«å¤çº¿å¼ºåº¦ææ°
+ public var uvIndex: Int = 0
+
+ public init() { }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Any.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Any.swift
new file mode 100644
index 0000000..64e712f
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Any.swift
@@ -0,0 +1,181 @@
+//
+// Any.swift
+// MyBase
+//
+// Created by Harvey on 2021/6/2.
+//
+
+import Foundation
+
+/// 夿å¯éç±»åæ¯å¦ä¸º nil
+func isNil(_ any: Any?) -> Bool {
+ switch any {
+ case .none: return true
+ case .some: return false
+ }
+}
+
+/// 夿å¯éç±»åæ¯å¦æå¼
+func isValue(_ any: Any?) -> Bool {
+ return isNil(any) == false
+}
+
+/// for Array
+func isEmpty(_ value: [Any]?) -> Bool {
+ return isNil(value) || value!.count == 0
+}
+
+/// for Array
+func isNotEmpty(_ value: [Any]?) -> Bool {
+ return isEmpty(value) == false
+}
+
+/// for Dictionary
+func isEmpty(_ value: [AnyHashable: Any]?) -> Bool {
+ return isNil(value) || value!.count == 0
+}
+
+/// for Dictionary
+func isNotEmpty(_ value: [AnyHashable: Any]?) -> Bool {
+ return isEmpty(value) == false
+}
+
+/// for String
+func isEmpty(_ value: String?) -> Bool {
+ return isNil(value) || value!.count == 0
+}
+
+/// for String
+func isNotEmpty(_ value: String?) -> Bool {
+ return isEmpty(value) == false
+}
+
+public extension String {
+
+ /// 补足8ä½(é¿åº¦ä¸º8çæ´æ°å)
+ var binary: String {
+ let bytes = (Double(count) / 8.0).upInt
+ let offset = bytes * 8 - count
+ let prefix = Array(repeating: "0", count: offset).joined()
+ return prefix + self
+ }
+}
+
+public extension Double {
+ var upInt: Int { Int(ceil(self)) }
+}
+
+public extension Int {
+ private static let binaryPack = 0b11111111
+
+ /// convert to data with byte (max is 4294967295)
+ ///
+ /// ä½ä½ --> é«ä½
+ var bytes: [UInt8] {
+ var mutatingSelf = self
+ var bytes = [UInt8(mutatingSelf & Self.binaryPack)]
+
+ var count = 1
+ mutatingSelf = mutatingSelf >> (count * 8)
+ while mutatingSelf > 0 {
+ bytes.append(UInt8(mutatingSelf & Self.binaryPack))
+ mutatingSelf = mutatingSelf >> (count * 8)
+ count = count + 1
+ }
+ return bytes
+ }
+
+ /// convert to data with 1 byte
+ var byte: UInt8 {
+ UInt8(self & Self.binaryPack)
+ }
+
+ /// convert to data with 2 byte
+ ///
+ /// ä½ä½ --> é«ä½
+ var byte2: [UInt8] {
+ [
+ UInt8(self & Self.binaryPack),
+ UInt8(self >> 8 & Self.binaryPack)
+ ]
+ }
+
+ /// convert to data with 3 byte
+ ///
+ /// ä½ä½ --> é«ä½
+ var byte3: [UInt8] {
+ [
+ UInt8(self & Self.binaryPack),
+ UInt8(self >> 8 & Self.binaryPack),
+ UInt8(self >> 16 & Self.binaryPack)
+ ]
+ }
+
+ /// convert to data with 4 byte
+ ///
+ /// ä½ä½ --> é«ä½
+ var byte4: [UInt8] {
+ [
+ UInt8(self & Self.binaryPack),
+ UInt8(self >> 8 & Self.binaryPack),
+ UInt8(self >> 16 & Self.binaryPack),
+ UInt8(self >> 24 & Self.binaryPack)
+ ]
+ }
+}
+
+public extension BinaryInteger {
+
+ /// e.g. 0000100110010101
+ var binaryString: String {
+ .init(self, radix: 2).binary
+ }
+}
+
+public extension Array where Element == UInt8 {
+
+ var int: Int {
+ self
+ .map { Int($0) }
+ .enumerated()
+ .map { $1 << ($0 * 8) }
+ .reduce(0, { partialResult, value in
+ partialResult | value
+ })
+ }
+
+ var data: Data { Data(self) }
+}
+
+public extension Data {
+ var bytes: [UInt8] { map { $0 } }
+
+ func joined(format: String = "%02x", _ separator: String = "") -> String {
+ self
+ .map { String(format: format, $0) }
+ .joined(separator: separator)
+ }
+
+ func reversedJoined(format: String = "%02x", _ separator: String = "") -> String {
+ self
+ .map { String(format: format, $0) }
+ .reversed()
+ .joined(separator: separator)
+ }
+
+ var int: Int {
+ self
+ .map { Int($0) }
+ .enumerated()
+ .map { $1 << ($0 * 8) }
+ .reduce(0, { partialResult, value in
+ partialResult | value
+ })
+ }
+
+ var lrc: UInt8 { LRC.calculateLRC(bytes) }
+}
+
+public extension UInt8 {
+ var int: Int { Int(self) }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/CRC16.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/CRC16.swift
new file mode 100644
index 0000000..0025438
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/CRC16.swift
@@ -0,0 +1,44 @@
+//
+// CRC16.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/12.
+//
+
+import Foundation
+
+/// CRC-16/MODBUS
+class CRC16 {
+ static let shared = CRC16()
+ private init() { }
+
+ func result(_ bytes: [UInt8]) -> [UInt8] {
+ var crcValue = crc(bytes)
+ var crcBytes: [UInt8] = [0, 0]
+ for index in (0..<2).reversed() {
+ crcBytes[index] = UInt8(crcValue % 256)
+ crcValue >>= 8
+ }
+ return crcBytes
+ }
+
+ private func crc(_ bytes: [UInt8]) -> Int {
+
+ var crcSum: Int = 0xffff
+ let polynomial: Int = 0xa001
+ let length = bytes.count
+
+ for index in 0..>= 1
+ crcSum ^= polynomial
+ }else{
+ crcSum >>= 1
+ }
+ }
+ }
+ return crcSum
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Date.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Date.swift
new file mode 100644
index 0000000..9fc933d
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Date.swift
@@ -0,0 +1,145 @@
+//
+// Date.swift
+// MyBase
+//
+// Created by Harvey on 2021/5/18.
+//
+
+import Foundation
+
+// MARK: - Extension Date
+extension Date {
+
+ static let formatter = DateFormatter()
+
+ struct Format {
+
+ let rawValue: String
+ init(_ rawValue: String) {
+ self.rawValue = rawValue
+ }
+
+ /// e.g. 01:01:01
+ static let time: Format = .init("HH:mm:ss")
+
+ /// e.g. 01:01
+ static let shortTime: Format = .init("HH:mm")
+
+ /// e.g. 01-01
+ static let date: Format = .init("MM-dd")
+
+ /// e.g. 01æ01æ¥
+ static let date1: Format = .init("MMæddæ¥")
+
+ /// e.g. 2020-01-01
+ static let short: Format = .init("yyyy-MM-dd")
+
+ /// e.g. 2020å¹´01æ01æ¥
+ static let short1: Format = .init("yyyå¹´MMæddæ¥")
+
+ /// e.g. 2020-01-01 01:01
+ static let middle: Format = .init("yyyy-MM-dd HH:mm")
+
+ /// e.g. 2020å¹´01æ01æ¥ 01:01
+ static let middle1: Format = .init("yyyå¹´MMæddæ¥ HH:mm")
+
+ /// e.g. 2020-01-01 01:01:01
+ static let long: Format = .init("yyyy-MM-dd HH:mm:ss")
+
+ /// e.g. 2020å¹´01æ01æ¥ 01:01:01
+ static let long1: Format = .init("yyyyå¹´MMæddæ¥ HH:mm:ss")
+
+ /// e.g. 2020-01-01 01:01:01.088
+ static let full: Format = .init("yyyy-MM-dd HH:mm:ss.SSS")
+
+ /// e.g. 2020å¹´01æ01æ¥ 01:01:01.088
+ static let full1: Format = .init("yyyyå¹´MMæddæ¥ HH:mm:ss.SSS")
+ }
+
+ /// æ ¼å¼åææ¬å°æ¶é´
+ func format(_ format: Date.Format = .middle) -> String {
+ Self.formatter.dateFormat = format.rawValue
+ return Self.formatter.string(from: self)
+ }
+
+ enum Unit {
+ case minute(Int)
+ case hour(Int)
+ case day(Int)
+
+ /// è½¬æ¢æç§
+ var second: TimeInterval {
+ switch self {
+ case .minute(let minute): return 60.0 * Double(minute)
+ case .hour(let hour): return 60.0 * 60.0 * Double(hour)
+ case .day(let day): return 60.0 * 60.0 * 24.0 * Double(day)
+ }
+ }
+ }
+}
+
+let today: Date = .init()
+
+/// æ¬å°å
+extension Date {
+ /// ææå
+ enum Week: Int {
+ /// æææ¥
+ case sun = 1
+ /// ææä¸
+ case mon
+ /// ææäº
+ case tue
+ /// ææä¸
+ case wed
+ /// ææå
+ case thur
+ /// ææäº
+ case fri
+ /// ææå
+ case sat
+ }
+
+// /// å½å¤©ç第ä¸ç§
+// var fromTimeInterval: TimeInterval {
+// let today = format(.short)
+// return today.timeIntervalSince1970(.short)
+// }
+//
+// /// å½å¤©æåä¸ç§
+// var toTimeInterval: TimeInterval { fromTimeInterval + Unit.day(1).second }
+
+ /// åªä¸å¹´
+ var year: Int { component(.year) }
+
+ /// åªä¸ªæ
+ var month: Int { component(.month) }
+
+ /// 彿ç第å 天
+ var day: Int { component(.day) }
+
+ /// 彿ç第å 天
+ var hour: Int { component(.hour)}
+
+ /// 彿ç第å 天
+ var minute: Int { component(.minute)}
+
+ /// 彿ç第å 天
+ var second: Int { component(.second)}
+
+ /// 彿ç第å å¨
+ var weekOfMonth: Int { component(.weekOfMonth) }
+
+ /// ä»å¹´ç第å å¨
+ var weekOfYear: Int { component(.weekOfYear) }
+
+ /// ææå
+ var weekDay: Week { Week(rawValue: component(.weekday))! }
+
+ /// å设å½å¤©æ¯å¨äºï¼è¡¨ç¤ºæ¬æç第å 个å¨äº
+ var weekdayOrdinal: Int { component(.weekdayOrdinal) }
+
+ private func component(_ component: Calendar.Component) -> Int {
+ return Calendar.autoupdatingCurrent.component(component, from: self)
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/IBPeripheralUUID.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/IBPeripheralUUID.swift
new file mode 100644
index 0000000..285800b
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/IBPeripheralUUID.swift
@@ -0,0 +1,23 @@
+//
+// IBPeripheralUUID.swift
+// IOTBluetooth
+//
+// Created by Harvey on 2024/2/5.
+//
+
+import CoreBluetooth
+
+public protocol IBPeripheralUUID {
+ /// CBPeripheral.identifier
+ var uuid: UUID { get }
+}
+
+extension UUID: IBPeripheralUUID {
+
+ public var uuid: UUID { self }
+}
+
+public func == (lhs: IBPeripheralUUID?, rhs: IBPeripheralUUID?) -> Bool {
+ guard let lhs = lhs, let rhs = rhs else { return false }
+ return lhs.uuid == rhs.uuid
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/JSON.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/JSON.swift
new file mode 100644
index 0000000..9c94ed9
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/JSON.swift
@@ -0,0 +1,115 @@
+//
+// JSON.swift
+// MyBase
+//
+// Created by Harvey on 2024/1/7.
+//
+
+import Foundation
+
+ struct JSON { }
+
+ extension Dictionary {
+
+ func jsonString(options: JSONSerialization.WritingOptions = [.fragmentsAllowed]) -> String? {
+ guard JSONSerialization.isValidJSONObject(self) else {
+ Logger.log("æ æç JSONObject")
+ return nil
+ }
+ guard let data = try? JSONSerialization.data(withJSONObject: self, options: options) else { return nil }
+ return data.string
+ }
+}
+
+ extension Array {
+
+ func jsonString(options: JSONSerialization.WritingOptions = [.fragmentsAllowed]) -> String? {
+ guard JSONSerialization.isValidJSONObject(self) else {
+ Logger.log("æ æç JSONObject")
+ return nil
+ }
+ guard let data = try? JSONSerialization.data(withJSONObject: self, options: options) else { return nil }
+ return data.string
+ }
+}
+
+ extension String {
+
+ func jsonObject(options: JSONSerialization.ReadingOptions = [.mutableContainers]) -> Any? {
+ guard let data = self.data else { return nil }
+ return data.jsonObject(options: options)
+ }
+}
+
+ extension Data {
+
+ func jsonObject(options: JSONSerialization.ReadingOptions = [.mutableContainers]) -> Any? {
+ do { return try JSONSerialization.jsonObject(with: self, options: options) }
+ catch { Logger.log(error) }
+ return nil
+ }
+}
+
+// MARK: - Extension Codable
+
+ extension Encodable {
+
+ /// JSON encode
+ var encode: Data? {
+ do {
+ return try JSONEncoder().encode(self)
+ } catch { Logger.log(error) }
+ return nil
+ }
+
+ var jsonString: String? {
+ encode?.string
+ }
+}
+
+ extension Decodable {
+
+ /// JSON decode
+ static func decode(_ from: Data) -> Self? {
+ do {
+ return try JSONDecoder().decode(Self.self, from: from)
+ } catch { Logger.log(error) }
+ return nil
+ }
+
+ /// JSON decode
+ static func decode(_ from: String) -> Self? {
+ guard let data = from.data else { return nil }
+ return decode(data)
+ }
+}
+
+ extension JSON {
+ /// JSON decode
+ static func decode(_ decodable: T.Type, from data: Data) -> T? {
+ do {
+ return try JSONDecoder().decode(decodable.self, from: data)
+ } catch { Logger.log(error) }
+ return nil
+ }
+
+ /// JSON decode
+ static func decode(_ decodable: T.Type, from jsonString: String) -> T? {
+ guard let data = jsonString.data else { return nil }
+ return decode(decodable, from: data)
+ }
+}
+
+ extension Array where Element: Encodable {
+ /// JSON encode
+ var jsonData: Data? {
+ do {
+ return try JSONEncoder().encode(self)
+ } catch { Logger.log(error) }
+ return nil
+ }
+
+ var jsonString: String? {
+ encode?.string
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/LRC.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/LRC.swift
new file mode 100644
index 0000000..8270a6a
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/LRC.swift
@@ -0,0 +1,29 @@
+//
+// LRC.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/13.
+//
+
+import Foundation
+
+public struct LRC {
+
+ public static func calculateLRC(_ bytes: [UInt8]) -> UInt8 {
+ let sum = bytes.map({ Int($0) }).reduce(0) { partialResult, value in
+ partialResult + value
+ }
+
+ let lrc = sum % 256
+ return UInt8(lrc == 0 ? 0 : 256 - lrc)
+ }
+
+ public static func calculate(_ bytes: [UInt8]) -> UInt8 {
+ let sum = bytes.map({ Int($0) }).reduce(into: 0) { partialResult, value in
+ partialResult ^= value
+ }
+ return sum.byte
+ }
+}
+
+
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Logger.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Logger.swift
new file mode 100644
index 0000000..1236c7f
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/Logger.swift
@@ -0,0 +1,33 @@
+//
+// Logger.swift
+//
+//
+// Created by Harvey on 2021/4/27.
+//
+
+import Foundation
+
+/// æ¥è®°ç®¡ç
+class Logger {
+ static var isDebug: Bool = false
+
+ fileprivate static let shared = Logger()
+ private init() { }
+
+ fileprivate var dateString: String { Date().format(.full) }
+
+ static var logs: [String] = []
+}
+
+extension Logger {
+ static func log(_ logs: Any..., line: Int = #line, separator: String = " ", terminator: String = "\n") {
+ objc_sync_enter(Logger.shared)
+ if Logger.isDebug {
+ print(Logger.shared.dateString, terminator: " [IOTBluetooth-\(String(format: "%03d", line))]: ")
+ print(logs, separator: separator, terminator: terminator)
+ let logString = Logger.shared.dateString + " [IOTBluetooth-\(String(format: "%03d", line))]: " + logs.map({ "\($0)" }).joined(separator: separator) + terminator
+ Self.logs.append(logString)
+ }
+ objc_sync_exit(Logger.shared)
+ }
+}
diff --git a/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/UTF8.swift b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/UTF8.swift
new file mode 100644
index 0000000..a88e787
--- /dev/null
+++ b/IOTBluetooth/IOTBluetooth/IOTBluetooth/Tools/UTF8.swift
@@ -0,0 +1,16 @@
+//
+// UTF8.swift
+// IOTBluetooth
+//
+// Created by yaozuopan on 2024/3/6.
+//
+
+import Foundation
+
+public extension Data {
+ var string: String? { String(data: self, encoding: .utf8) }
+}
+
+public extension String {
+ var data: Data? { self.data(using: .utf8) }
+}