设备管理业务拓展

更新时间:2024-01-08 09:17:48下载pdf

本文介绍设备管理业务拓展,包括接入设备信息和接入设备定时。

接入设备信息

关于设备信息,前往 设备信息 了解更多。本章节演示如何展示设备信息。

定义数据模型

class CellModel: NSObject {
    var title: String
    var detail: String

    init(title: String, detail: String) {
        self.title = title
        self.detail = detail
    }
}

该模型用于列表的展示,界面 UI 大致如下:

设备管理业务拓展

创建控制器

class DeviceDetailKitInfoVC: UITableViewController {

    var items: [CellModel] = []
    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
        self.tableView.reloadData()
    }
}

extension DeviceDetailKitInfoVC {
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .value1, reuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
        cell.textLabel?.text = self.items[indexPath.row].title
        cell.detailTextLabel?.text = self.items[indexPath.row].detail
        return cell
    }
}

创建了一个控制器,用于展示设备信息。然后用 items 存放数据,最后将它显示到界面上。

获取数据

  1. 获取设备信息需要用到设备 ID。因此,需要传入设备 ID。调整代码:

    class DeviceDetailKitInfoVC: UITableViewController {
        var deviceId: String
    
        init(deviceId: String) {
            self.deviceId = deviceId
            super.init(nibName: nil, bundle: nil)
        }
    }
    
    
  2. 通过 ThingDeviceInfoManager 获取设备信息,因此需要构建一个 ThingDeviceInfoManager 对象。继续调整代码:

    class DeviceDetailKitInfoVC: UITableViewController {
        var manager: ThingDeviceInfoManager
    
        init(deviceId: String) {
            self.deviceId = deviceId
            self.manager = ThingDeviceInfoManager(deviceId: deviceId)
            super.init(nibName: nil, bundle: nil)
        }
    }
    
  3. 现在已经有 ThingDeviceInfoManager 对象,可以进行数据请求。

    class DeviceDetailKitInfoVC: UITableViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
            self.loadData()
        }
    
        func loadData() {
            SVProgressHUD.show()
            self.manager.fetchDataSuccess { [weak self] info, hardware in
                var list = [CellModel]()
                list.append(CellModel(title: "devId", detail: info.devId))
                list.append(CellModel(title: "iccid", detail: info.iccid ?? ""))
                list.append(CellModel(title: "netStrength", detail: info.netStrength ?? ""))
                list.append(CellModel(title: "lanIp", detail: info.lanIp ?? ""))
                list.append(CellModel(title: "ip", detail: info.ip ?? ""))
                list.append(CellModel(title: "mac", detail: info.mac ?? ""))
                list.append(CellModel(title: "timezone", detail: info.timezone ?? ""))
                list.append(CellModel(title: "channel", detail: info.channel ?? ""))
                list.append(CellModel(title: "rsrp", detail: info.rsrp != nil ? "\(info.rsrp!)" : ""))
                list.append(CellModel(title: "wifiSignal", detail: info.wifiSignal != nil ? "\(info.wifiSignal!)" : ""))
                list.append(CellModel(title: "homekitCode", detail: info.homekitCode ?? ""))
                list.append(CellModel(title: "connectAbility", detail: "\(info.connectAbility)"))
                list.append(CellModel(title: "vendorName", detail: info.vendorName ?? ""))
                self?.items = list
                self?.tableView.reloadData()
                SVProgressHUD.dismiss()
            } failure: { e in
                SVProgressHUD.dismiss()
            }
        }
    }
    
    1. 定义了 loadData 方法。
    2. 在该方法里,通过 ThingDeviceInfoManager.fetchDataSuccess:failure: 获取数据并构造 items,然后刷新界面。
    3. 最后,在 viewDidLoad 方法里调用 loadData

    UI 大致展示如下:

    设备管理业务拓展

监听信号变化

虽然在上一步获取了设备信息数据,但是设备的信号值是设备通过 MQTT 上报的,因此还需要注册信号的监听,用于动态响应设备信号变化。

class DeviceDetailKitInfoVC: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
        self.manager.add(self)
        self.loadData()
    }

}

extension DeviceDetailKitInfoVC: ThingDeviceInfoManagerListener {
    func deviceInfoManager(_ manager: ThingDeviceInfoManager, wifiSignalDidUpdate wifiSignal: Int32) {
        let item = self.items.first { item in
            return item.title == "wifiSignal"
        }
        item?.detail = "\(wifiSignal)"
        self.tableView.reloadData()
    }
}

viewDidLoad 中注册了监听,然后实现了 ThingDeviceInfoManagerListener 协议。当设备上报信号时,您就能收到,然后更新到界面上。

完整的代码

class DeviceDetailKitInfoVC: UITableViewController {

    var items: [CellModel] = []
    var deviceId: String

    var manager: ThingDeviceInfoManager

    init(deviceId: String) {
        self.deviceId = deviceId
        self.manager = ThingDeviceInfoManager(deviceId: deviceId)
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }


    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
        self.manager.add(self)
        self.loadData()
    }

    func loadData() {
        SVProgressHUD.show()
        self.manager.fetchDataSuccess { [weak self] info, hardware in
            var list = [CellModel]()
            list.append(CellModel(title: "devId", detail: info.devId))
            list.append(CellModel(title: "iccid", detail: info.iccid ?? ""))
            list.append(CellModel(title: "netStrength", detail: info.netStrength ?? ""))
            list.append(CellModel(title: "lanIp", detail: info.lanIp ?? ""))
            list.append(CellModel(title: "ip", detail: info.ip ?? ""))
            list.append(CellModel(title: "mac", detail: info.mac ?? ""))
            list.append(CellModel(title: "timezone", detail: info.timezone ?? ""))
            list.append(CellModel(title: "channel", detail: info.channel ?? ""))
            list.append(CellModel(title: "rsrp", detail: info.rsrp != nil ? "\(info.rsrp!)" : ""))
            list.append(CellModel(title: "wifiSignal", detail: info.wifiSignal != nil ? "\(info.wifiSignal!)" : ""))
            list.append(CellModel(title: "homekitCode", detail: info.homekitCode ?? ""))
            list.append(CellModel(title: "connectAbility", detail: "\(info.connectAbility)"))
            list.append(CellModel(title: "vendorName", detail: info.vendorName ?? ""))
            self?.items = list
            self?.tableView.reloadData()
            SVProgressHUD.dismiss()
        } failure: { e in
            SVProgressHUD.dismiss()
        }

    }
}

extension DeviceDetailKitInfoVC {
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .value1, reuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
        cell.textLabel?.text = self.items[indexPath.row].title
        cell.detailTextLabel?.text = self.items[indexPath.row].detail
        return cell
    }
}

extension DeviceDetailKitInfoVC: ThingDeviceInfoManagerListener {
    func deviceInfoManager(_ manager: ThingDeviceInfoManager, wifiSignalDidUpdate wifiSignal: Int32) {
        let item = self.items.first { item in
            return item.title == "wifiSignal"
        }
        item?.detail = "\(wifiSignal)"
        self.tableView.reloadData()
    }
}

接入设备定时

关于设备定时,前往 设备定时 了解更多。本章节演示如何展示设备定时。

创建控制器

创建一个新的控制器,用来展示设备或群组的定时列表,并处理单击 cell 事件。

class DeviceDetailKitTimerVC: UITableViewController {

    var items: [ThingTimerModel] = []

    override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
        super.init(nibName: nil, bundle: nil)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
        self.tableView.reloadData()
    }

    func handle(timer: ThingTimerModel) {
        //处理单击事件
    }
}

extension DeviceDetailKitTimerVC {
    override func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return items.count
    }

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = UITableViewCell(style: .value1, reuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
        cell.textLabel?.text = self.items[indexPath.row].time
        cell.detailTextLabel?.text = self.items[indexPath.row].status ? "on" : "off"
        return cell
    }

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        self.handle(timer: self.items[indexPath.row])
    }
}

获取定时数据

  1. 需要明确获取的是设备还是群组的定时,因此需要设备或者群组的 ID,并传入数据。

    class DeviceDetailKitTimerVC: UITableViewController {
    
        var bizId: String //设备 ID 或者 群组 ID
        var isGroup: Bool //是否是群组
    
        init(bizId: String, isGroup: Bool) {
            self.bizId = bizId
            self.isGroup = isGroup
            super.init(nibName: nil, bundle: nil)
        }
    }
    
  2. 群组的操作需要依赖 ThingDeviceTimerManager,因此需要实例化一个 ThingDeviceTimerManager 对象。

    class DeviceDetailKitTimerVC: UITableViewController {
    
        var bizId: String
        var isGroup: Bool
        var manager: ThingDeviceTimerManager
    
        var items: [ThingTimerModel] = []
    
        init(bizId: String, isGroup: Bool) {
            self.bizId = bizId
            self.isGroup = isGroup
            self.manager = ThingDeviceTimerManager()
            super.init(nibName: nil, bundle: nil)
        }
    }
    
  3. 拉取数据。

    class DeviceDetailKitTimerVC: UITableViewController {
    
        override func viewDidLoad() {
            super.viewDidLoad()
            self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
            self.loadData()
        }
    
        func loadData() {
            SVProgressHUD.show()
            self.getTimerList { [weak self] list in
                self?.items = list
                self?.tableView.reloadData()
                SVProgressHUD.dismiss()
    
                guard let self = self, self.isGroup == false && self.manager.isDeviceCanSync(bizId) else {return}
                manager.syncTimers(list, toDevice: bizId) {} failure: { _ in }
    
            } failure: { e in
                SVProgressHUD.dismiss()
            }
        }
    
        func getTimerList(success: @escaping ([ThingTimerModel]) -> Void, failure: @escaping (Error) -> Void) {
            let params = ThingDeviceTimerGetParams(bizType: isGroup ? .group : .device, bizId: bizId, category: "")
            self.manager.getTimers(params, success: success, failure: failure)
        }
    }
    
    • 因为复用的关系,定义了 getTimerList(success:failure:) 方法,内部会调用ThingDeviceTimerManager.getTimers(_:success:failure) 方法。
    • 定义 loadData 方法,该方法会在 viewDidLoad 的时候仅被调用一次。通过封装的 getTimerList(success:failure:) 接口,拉取定时列表数据。
    • loadData 方法内部,除了保存数据并刷新界面外,还在设备支持定时同步时通过 ThingDeviceTimerManager.syncTimers(_:toDevice:success:failure) 方法将定时数据同步给设备。

    至此,就可以展示设备定时列表了。

添加定时

虽然上文展示了定时列表,但是没有数据,因此有必要增加一个按钮用来给设备或群组添加定时。

class DeviceDetailKitTimerVC: UITableViewController {

    func setUpNavigationItem() {
        let title = "添加"
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: title, style: .plain, target: self, action: #selector(add))
    }

    @objc func add() {
        SVProgressHUD.show()

        var dps: [AnyHashable: Any] = ["1": true]
        let params = ThingDeviceTimerAddParams(bizType: isGroup ? .group : .device, bizId: bizId, category: "", loops: "0000000", time: "12:30", dps: dps, aliasName: "新加的定时", isAppPush: true, status: true)
        self.manager.addTimer(params) { [weak self] timerId in
            self?.getTimerList(success: { list in
                self?.items = list
                self?.tableView.reloadData()
                SVProgressHUD.dismiss()
            }, failure: { e in
                SVProgressHUD.dismiss()
            })
        } failure: { e in
            SVProgressHUD.dismiss()
        }
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "DeviceDetailListViewControllerReuseIdentifier")
        self.setUpNavigationItem()
        self.loadData()
    }
}
  1. 在导航栏上增加了一个添加的按钮。

  2. 按钮单击后,调用 ThingDeviceTimerManager.addTimer(_:success:failure:) 方法添加定时。

  3. 添加成功后,通过前面封装的 getTimerList(success:failure:) 接口刷新定时列表。

    您需要根据实际情况,构造 ThingDeviceTimerAddParams 参数。

更新定时

class DeviceDetailKitTimerVC: UITableViewController {
    func handle(timer: ThingTimerModel) {
        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        alert.addAction(UIAlertAction(title: "更新", style: .default, handler: { action in
            self.update(timer: timer)
        }))

        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        self.present(alert, animated: true)
    }

    func update(timer: ThingTimerModel) {
        let params = ThingDeviceTimerUpdateParams(timerId: timer.timerId, bizType: self.isGroup ? .group : .device, bizId: self.bizId, loops: timer.loops, time: timer.time, dps: timer.dps, aliasName: timer.aliasName, isAppPush: !timer.isAppPush, status: !timer.status)

        SVProgressHUD.show()

        self.manager.updateTimer(params) { [weak self] in
            self?.getTimerList { list in
                self?.items = list
                self?.tableView.reloadData()
                SVProgressHUD.dismiss()
            } failure: { e in
                SVProgressHUD.dismiss()
            }
        } failure: { e in
            SVProgressHUD.dismiss()
        }
    }
}

实现之前预埋的 cell 单击事件的方法。

  1. 用一个 actionSheet,添加一个更新的 action

  2. 单击后,跳转到 update(timer:) 方法,该方法内部会调用 ThingDeviceTimerManager.updateTimer(_:success:failure:) 方法更新定时。

  3. 更新成功后,通过前面封装的 getTimerList(success:failure:) 接口刷新定时列表。

    您需要根据实际情况,构造 ThingDeviceTimerUpdateParams 参数。

更新定时状态

class DeviceDetailKitTimerVC: UITableViewController {
    func handle(timer: ThingTimerModel) {
        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        alert.addAction(UIAlertAction(title: "更新", style: .default, handler: { action in
            self.update(timer: timer)
        }))

        alert.addAction(UIAlertAction(title: "更新状态", style: .default, handler: { action in
            self.updateStatus(timer: timer)
        }))

        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        self.present(alert, animated: true)
    }

    func updateStatus(timer: ThingTimerModel) {
        let params = ThingDeviceTimerStatusUpdateParams(timerId: timer.timerId, bizType: self.isGroup ? .group : .device, bizId: self.bizId, loops: timer.loops, time: timer.time, dps: timer.dps, aliasName: timer.aliasName, isAppPush: timer.isAppPush, status: !timer.status)

        SVProgressHUD.show()

        self.manager.updateTimerStatus(params) { [weak self] in
            self?.getTimerList { list in
                self?.items = list
                self?.tableView.reloadData()
                SVProgressHUD.dismiss()
            } failure: { e in
                SVProgressHUD.dismiss()
            }
        } failure: { e in
            SVProgressHUD.dismiss()
        }
    }
}
  1. 添加一个更新状态的 action

  2. 单击后,跳转到 updateStatus(timer:) 方法,该方法内部会调用 ThingDeviceTimerManager.updateTimerStatus(_:success:failure:) 方法更新定时状态。

  3. 更新成功后,通过前面封装的 getTimerList(success:failure:) 接口刷新定时列表。

    您需要根据实际情况,构造 ThingDeviceTimerStatusUpdateParams 参数。

删除定时

class DeviceDetailKitTimerVC: UITableViewController {
    func handle(timer: ThingTimerModel) {
        let alert = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)

        alert.addAction(UIAlertAction(title: "更新", style: .default, handler: { action in
            self.update(timer: timer)
        }))

        alert.addAction(UIAlertAction(title: "更新状态", style: .default, handler: { action in
            self.updateStatus(timer: timer)
        }))

        alert.addAction(UIAlertAction(title: "删除", style: .default, handler: { action in
            self.delete(timer: timer)
        }))

        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        self.present(alert, animated: true)
    }

    func delete(timer: ThingTimerModel) {
        let params = ThingDeviceTimerRemoveParams(timerId: timer.timerId, bizType: self.isGroup ? .group : .device, bizId: self.bizId)

        SVProgressHUD.show()

        self.manager.removeTimer(params) { [weak self] in
            self?.getTimerList { list in
                self?.items = list
                self?.tableView.reloadData()
                SVProgressHUD.dismiss()
            } failure: { e in
                SVProgressHUD.dismiss()
            }
        } failure: { e in
            SVProgressHUD.dismiss()
        }
    }
}
  1. 添加一个删除的 action

  2. 单击后,跳转到 updateStatus(timer:) 方法,该方法内部会调用 ThingDeviceTimerManager.updateTimerStatus(_:success:failure:) 方法删除定时状态。

  3. 删除成功后,通过前面封装的 getTimerList(success:failure:) 接口刷新定时列表。

    您需要根据实际情况,构造 ThingDeviceTimerRemoveParams 参数。