소스 검색

refactor(更新) :
- 修改钥匙连接策略以及钥匙信息获取时机,增加定时获取钥匙电量任务

周文健 3 달 전
부모
커밋
e29cdb17d9
23개의 변경된 파일426개의 추가작업 그리고 80개의 파일을 삭제
  1. 1 0
      app/build.gradle
  2. 4 1
      app/src/main/AndroidManifest.xml
  3. 110 17
      app/src/main/java/com/grkj/iscs_mars/BusinessManager.kt
  4. 6 0
      app/src/main/java/com/grkj/iscs_mars/MyApplication.kt
  5. 49 26
      app/src/main/java/com/grkj/iscs_mars/ble/BleConnectionManager.kt
  6. 13 0
      app/src/main/java/com/grkj/iscs_mars/ble/BleIndicateListener.kt
  7. 4 2
      app/src/main/java/com/grkj/iscs_mars/ble/BleUtil.kt
  8. 3 2
      app/src/main/java/com/grkj/iscs_mars/modbus/DockBean.kt
  9. 49 19
      app/src/main/java/com/grkj/iscs_mars/modbus/ModBusController.kt
  10. 25 7
      app/src/main/java/com/grkj/iscs_mars/model/Constants.kt
  11. 5 0
      app/src/main/java/com/grkj/iscs_mars/model/UrlConsts.kt
  12. 2 0
      app/src/main/java/com/grkj/iscs_mars/model/eventmsg/MsgEventConstants.kt
  13. 76 0
      app/src/main/java/com/grkj/iscs_mars/service/CheckKeyInfoTask.kt
  14. 18 0
      app/src/main/java/com/grkj/iscs_mars/util/NetApi.kt
  15. 1 0
      app/src/main/java/com/grkj/iscs_mars/view/activity/HomeActivity.kt
  16. 2 0
      app/src/main/java/com/grkj/iscs_mars/view/activity/LoginActivity.kt
  17. 2 0
      app/src/main/java/com/grkj/iscs_mars/view/fragment/JobProgressFragment.kt
  18. 6 2
      app/src/main/java/com/grkj/iscs_mars/view/fragment/StepFragment.kt
  19. 1 0
      app/src/main/java/com/grkj/iscs_mars/view/fragment/TechnologySopFragment.kt
  20. 11 0
      app/src/main/java/com/grkj/iscs_mars/view/presenter/HomePresenter.kt
  21. 13 2
      app/src/main/java/com/grkj/iscs_mars/view/presenter/JobProgressPresenter.kt
  22. 14 2
      app/src/main/java/com/grkj/iscs_mars/view/presenter/StepPresenter.kt
  23. 11 0
      app/src/main/java/com/grkj/iscs_mars/view/presenter/TechnologySopPresenter.kt

+ 1 - 0
app/build.gradle

@@ -143,4 +143,5 @@ dependencies {
     implementation 'com.github.SilverIceKey.SIKExtension:SIKCore:1.1.56'
     implementation 'com.github.SilverIceKey.SIKExtension:SIKAndroid:1.1.56'
     implementation 'com.github.liangjingkanji:BRV:1.6.1'
+    implementation("com.github.SilverIceKey:SIKCronJob:1.0.5")
 }

+ 4 - 1
app/src/main/AndroidManifest.xml

@@ -92,7 +92,10 @@
         <activity
             android:name=".view.activity.test.WebSocketActivity"
             android:exported="false" />
-
+        <service
+            android:name="com.sik.cronjob.services.TaskService"
+            android:exported="false"
+            android:process=":CronJobService"/>
         <meta-data
             android:name="design_width_in_dp"
             android:value="640" />

+ 110 - 17
app/src/main/java/com/grkj/iscs_mars/BusinessManager.kt

@@ -24,6 +24,7 @@ import com.grkj.iscs_mars.modbus.DockBean
 import com.grkj.iscs_mars.modbus.ModBusController
 import com.grkj.iscs_mars.modbus.ModBusController.dockList
 import com.grkj.iscs_mars.modbus.ModBusController.getOneKey
+import com.grkj.iscs_mars.model.Constants
 import com.grkj.iscs_mars.model.Constants.USER_TYPE_LOCKER
 import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_CARD
 import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_FINGERPRINT
@@ -63,6 +64,7 @@ import com.grkj.iscs_mars.model.vo.lock.LockPageRespVO
 import com.grkj.iscs_mars.model.vo.lock.LockTakeUpdateReqVO
 import com.grkj.iscs_mars.model.vo.ticket.LockPointUpdateReqVO
 import com.grkj.iscs_mars.model.vo.ticket.TicketDetailRespVO
+import com.grkj.iscs_mars.service.CheckKeyInfoTask
 import com.grkj.iscs_mars.util.ActivityUtils
 import com.grkj.iscs_mars.util.CommonUtils
 import com.grkj.iscs_mars.util.Executor
@@ -73,6 +75,7 @@ import com.grkj.iscs_mars.util.log.LogUtil
 import com.grkj.iscs_mars.view.activity.LoginActivity
 import com.grkj.iscs_mars.view.base.BaseActivity
 import com.grkj.iscs_mars.view.dialog.TipDialog
+import com.sik.cronjob.managers.CronJobScanner
 import com.sik.sikcore.SIKCore
 import com.sik.sikcore.date.TimeUtils
 import com.sik.sikcore.thread.ThreadUtils
@@ -103,6 +106,11 @@ object BusinessManager {
 
     private var initListener: (() -> Unit)? = null
 
+    /**
+     * 断开连接任务
+     */
+    private val disconnectJob: HashMap<String, String> = hashMapOf()
+
     // 归还设备是否需要登录
     var NEED_AUTH = true
 
@@ -143,6 +151,11 @@ object BusinessManager {
                 MSG_EVENT_DEVICE_TAKE_UPDATE -> {
                     handleDeviceTake(it.data as DeviceTakeUpdateMsg)
                 }
+
+                MsgEventConstants.MSG_EVENT_INIT_KEY_COMPLETE -> {
+                    val job = CronJobScanner.scanJobs(CheckKeyInfoTask())
+                    MyApplication.cronJobManager.registerJobs(job)
+                }
                 // 钥匙当前模式
                 MSG_EVENT_CURRENT_MODE -> {
                     handleCurrentMode(it.data as CurrentModeMsg)
@@ -230,8 +243,16 @@ object BusinessManager {
     /**
      * 连接一把存在的可连接的钥匙
      */
-    private fun connectExistsKey(exceptKeyMac: String) {
+    fun connectExistsKey(exceptKeyMac: List<String> = listOf()) {
         ThreadUtils.runOnIO {
+            cancelDisconnectAllJob()
+            val connectedDevice = BleManager.getInstance().allConnectedDevice
+            if (connectedDevice.isNotEmpty() && connectedDevice.subtract(exceptKeyMac.toSet())
+                    .isNotEmpty()
+            ) {
+                LogUtil.i("已有钥匙连接")
+                return@runOnIO
+            }
             // —— 串行请求1 & 2 ——
             val slotsPage = getSlotsPage()
 
@@ -255,7 +276,7 @@ object BusinessManager {
                     }?.toMutableList() ?: mutableListOf(),
                     (keyPage?.records?.filter { it.exStatus == keyStatusList.find { d -> d.dictLabel == "异常" }?.dictValue }
                         ?.map { it.keyNfc ?: "" }?.toMutableList() ?: mutableListOf()),
-                    mutableListOf(exceptKeyMac)
+                    exceptKeyMac
                 )
             }
         }
@@ -324,6 +345,13 @@ object BusinessManager {
         }
     }
 
+    /**
+     * 获取最多电量的钥匙
+     */
+    fun getMaxPowerKey(): DockBean.KeyBean {
+        return ModBusController.getMaxPowerKey()
+    }
+
     /**
      * 硬件状态
      * 1、检测到有钥匙
@@ -838,6 +866,55 @@ object BusinessManager {
         return null
     }
 
+    /**
+     * 启动断连任务
+     */
+    fun launchDisconnectJob(mac: String) {
+        val jobId = ThreadUtils.runOnIODelayed(Constants.BLE_DISCONNECT_DELAY_TIME) {
+            val bleBean = getBleDeviceByMac(mac)
+            bleBean?.bleDevice?.let {
+                BleManager.getInstance().disconnect(it)
+            }
+        }
+        disconnectJob[mac] = jobId
+    }
+
+    /**
+     * 启动断连所有设备任务
+     */
+    fun launchDisconnectAllJob() {
+        deviceList.forEach { bleBean ->
+            val jobId = ThreadUtils.runOnIODelayed(Constants.BLE_DISCONNECT_DELAY_TIME) {
+                val bleBean = getBleDeviceByMac(bleBean.bleDevice.mac)
+                bleBean?.bleDevice?.let {
+                    BleManager.getInstance().disconnect(it)
+                    deviceList.removeIf { it == bleBean }
+
+                }
+            }
+            disconnectJob[bleBean.bleDevice.mac] = jobId
+        }
+    }
+
+    /**
+     * 取消断连所有设备任务
+     */
+    fun cancelDisconnectAllJob() {
+        disconnectJob.forEach {
+            ThreadUtils.cancel(it.value)
+        }
+    }
+
+    /**
+     * 取消断连任务
+     */
+    fun cancelDisconnectJob(mac: String) {
+        val jobId = disconnectJob[mac]
+        jobId?.let {
+            ThreadUtils.cancel(it)
+        }
+    }
+
     /**
      * 下发工作票
      */
@@ -1118,14 +1195,11 @@ object BusinessManager {
 
             byteArray.startsWith(BleConst.RSP_POWER_STATUS) -> {
                 val power = byteArray[4].toInt()
+                ModBusController.getKeyByMac(bleBean.bleDevice.mac)?.power = power
                 if (power < 50) {//如果电量小于50就打开仓位充电
                     ModBusController.controlKeyCharge(true, bleBean.bleDevice.mac) {
                         LogUtil.i("钥匙: ${bleBean.bleDevice.mac} 开始充电")
                     }
-                } else {
-                    ModBusController.controlKeyCharge(false, bleBean.bleDevice.mac) {
-                        LogUtil.i("钥匙: ${bleBean.bleDevice.mac} 关闭充电")
-                    }
                 }
             }
         }
@@ -1630,13 +1704,17 @@ object BusinessManager {
                                     unregisterConnectListener(it)
                                 }
                                 //待机数不够就再连一把,但不能是原来那把
-                                if (BleManager.getInstance().allConnectedDevice.size < BleConst.MAX_KEY_STAND_BY) {
-                                    ModBusController.getKeyByRfid(
-                                        info.nfc
-                                    )?.mac?.let {
-                                        connectExistsKey(
-                                            it
-                                        )
+                                NetApi.getMySelfState {
+                                    if (it) {
+                                        ModBusController.getKeyByRfid(
+                                            info.nfc
+                                        )?.mac?.let {
+                                            val maxPowerMac = getMaxPowerKey().mac
+                                            if (maxPowerMac != it) {
+                                                connectExistsKey(listOf(it ?: ""))
+                                                launchDisconnectJob(it ?: "")
+                                            }
+                                        }
                                     }
                                 }
                             }
@@ -1830,9 +1908,21 @@ object BusinessManager {
                         )
                         sendLoadingEventMsg(null, false)
                         //连上之后没有工作票要下发就断开 看是否还有设备等待连接,没有就不断开,有就让路,一般是初始化的时候
-                        if (BleConnectionManager.hasConnectWait()) {
-                            BleManager.getInstance().disconnect(currentModeMsg.bleBean.bleDevice)
-                            deviceList.removeIf { device -> device.bleDevice.mac == currentModeMsg.bleBean.bleDevice.mac }
+                        launchDisconnectJob(currentModeMsg.bleBean.bleDevice.mac)
+                        NetApi.getMySelfState {
+                            if (it) {
+                                val maxPowerMac = getMaxPowerKey().mac
+                                if (maxPowerMac != currentModeMsg.bleBean.bleDevice.mac) {
+                                    connectExistsKey(
+                                        listOf(
+                                            currentModeMsg.bleBean.bleDevice.mac ?: ""
+                                        )
+                                    )
+                                    launchDisconnectJob(currentModeMsg.bleBean.bleDevice.mac ?: "")
+                                }
+                            } else {
+                                launchDisconnectJob(currentModeMsg.bleBean.bleDevice.mac ?: "")
+                            }
                         }
                     }
                 }
@@ -1986,8 +2076,11 @@ object BusinessManager {
                     }
                 }
             }
+        launchDisconnectAllJob()
         sendLoadingEventMsg(null, false)
-        context.startActivity(Intent(context, LoginActivity::class.java))
+        context.startActivity(Intent(context, LoginActivity::class.java).apply {
+            flags = Intent.FLAG_ACTIVITY_NEW_TASK
+        })
     }
 
     /**

+ 6 - 0
app/src/main/java/com/grkj/iscs_mars/MyApplication.kt

@@ -15,12 +15,18 @@ import com.grkj.iscs_mars.util.NetApi
 import com.grkj.iscs_mars.util.NetHttpManager
 import com.grkj.iscs_mars.util.SPUtils
 import com.grkj.iscs_mars.util.log.LogUtil
+import com.sik.cronjob.managers.CronJobManager
 import com.sik.sikcore.SIKCore
 
 class MyApplication : Application() {
 
     companion object {
         var instance: MyApplication? = null
+
+        /**
+         * 任务管理器
+         */
+        val cronJobManager: CronJobManager by lazy { CronJobManager.getInstance(instance!!) }
     }
 
     override fun onCreate() {

+ 49 - 26
app/src/main/java/com/grkj/iscs_mars/ble/BleConnectionManager.kt

@@ -20,6 +20,7 @@ import com.grkj.iscs_mars.model.Constants.PERMISSION_REQUEST_CODE
 import com.grkj.iscs_mars.model.eventmsg.LoadingMsg
 import com.grkj.iscs_mars.model.eventmsg.MsgEvent
 import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants.MSG_EVENT_LOADING
+import com.grkj.iscs_mars.service.CheckKeyInfoTask
 import com.grkj.iscs_mars.util.ActivityUtils
 import com.grkj.iscs_mars.util.CommonUtils
 import com.grkj.iscs_mars.util.Executor
@@ -63,6 +64,11 @@ object BleConnectionManager {
     @Volatile
     private var currentConnectingMac: MutableList<String> = mutableListOf()
 
+    /**
+     * 蓝牙监听
+     */
+    private var bleIndicateListeners: MutableMap<Any, BleIndicateListener> = mutableMapOf()
+
     /**
      * 注册连接监听:
      * - 如果设备已在 deviceList 且拥有 token,立即回调并返回
@@ -502,31 +508,31 @@ object BleConnectionManager {
     suspend fun tryConnectWithOptionalCharge(mac: String, withOpenCharge: Boolean = true): Boolean =
         withContext(Dispatchers.IO) {
             // -------- 第一次尝试 --------
-            LogUtil.i("蓝牙连接-第一次尝试")
-            val firstTry = suspendCancellableCoroutine<Boolean> { cont ->
-                // 1. 定义一个 flag,确保只 resume 一次
-                var isCalled = false
-                BusinessManager.registerConnectListener(mac, true) { isDone, _ ->
-                    if (isCalled) {
-                        return@registerConnectListener
-                    }
-                    isCalled = true
-                    if (isDone && cont.isActive) {
-                        // 连接成功后,把电关掉(以防万一)
-                        controlKeyCharge(false, mac) { }
-                        cont.resume(true)
-                    } else {
-                        cont.resume(false)
-                    }
-                }
-            }
-            LogUtil.i("蓝牙连接-第一次连接:${firstTry},是否继续尝试上电连接${withOpenCharge}")
-            if (firstTry) {
-                return@withContext true
-            }
-            if (!withOpenCharge) {
-                return@withContext false
-            }
+//            LogUtil.i("蓝牙连接-第一次尝试")
+//            val firstTry = suspendCancellableCoroutine<Boolean> { cont ->
+//                // 1. 定义一个 flag,确保只 resume 一次
+//                var isCalled = false
+//                BusinessManager.registerConnectListener(mac, true) { isDone, _ ->
+//                    if (isCalled) {
+//                        return@registerConnectListener
+//                    }
+//                    isCalled = true
+//                    if (isDone && cont.isActive) {
+//                        // 连接成功后,把电关掉(以防万一)
+//                        controlKeyCharge(false, mac) { }
+//                        cont.resume(true)
+//                    } else {
+//                        cont.resume(false)
+//                    }
+//                }
+//            }
+//            LogUtil.i("蓝牙连接-第一次连接:${firstTry},是否继续尝试上电连接${withOpenCharge}")
+//            if (firstTry) {
+//                return@withContext true
+//            }
+//            if (!withOpenCharge) {
+//                return@withContext false
+//            }
             // -------- 第二次尝试:先开电,再连 --------
             // 开电,并等待回调
             suspendCoroutine<Unit> { unitCont ->
@@ -552,7 +558,7 @@ object BleConnectionManager {
                     }
                     isCalled = true
                     // 无论成功或失败,都先把电关掉
-                    controlKeyCharge(false, mac) { }
+//                    controlKeyCharge(false, mac) { }
                     if (cont.isActive) {
                         cont.resume(isDone)
                     }
@@ -737,6 +743,23 @@ object BleConnectionManager {
         })
     }
 
+    /**
+     * 添加蓝牙监听
+     */
+    fun addBLeIndicateListener(
+        tag: Any,
+        listener: BleIndicateListener
+    ) {
+        bleIndicateListeners[tag] = listener
+    }
+
+    /**
+     * 移除蓝牙监听
+     */
+    fun removeBLeIndicateListener(tag: Any) {
+        bleIndicateListeners.remove(tag)
+    }
+
     // 蓝牙连接准备监听
     data class ConnectListener(
         val mac: String,

+ 13 - 0
app/src/main/java/com/grkj/iscs_mars/ble/BleIndicateListener.kt

@@ -0,0 +1,13 @@
+package com.grkj.iscs_mars.ble
+
+interface BleIndicateListener {
+    /**
+     * 处理返回
+     */
+    fun handleRsp(
+        bleBean: BleBean,
+        byteArray: ByteArray,
+        isNeedLoading: Boolean = false,
+        prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
+    )
+}

+ 4 - 2
app/src/main/java/com/grkj/iscs_mars/ble/BleUtil.kt

@@ -38,8 +38,8 @@ class BleUtil private constructor() {
         try {
             BleManager.getInstance().init(application)
             BleManager.getInstance().enableLog(false)
-                .setConnectOverTime(10 * 1000L)
-                .setReConnectCount(3, 300) // 设置重新连接次数和间隔时间,默认为0次,不重连
+                .setConnectOverTime(5 * 1000L)
+                .setReConnectCount(0, 0)
                 .setSplitWriteNum(500)
                 .operateTimeout =
                 OPERATE_TIMEOUT // 设置操作readRssi、setMtu、write、read、notify、indicate的超时时间(毫秒)
@@ -47,6 +47,8 @@ class BleUtil private constructor() {
                 //Android 12及以上不允许添加过滤器
                 val bleScanRuleConfig = BleScanRuleConfig.Builder()
 //                .setServiceUuids(arrayOf(UUID.fromString(BLUETOOTH_SERVICEUUID)))
+                    .setAutoConnect(false)
+                    .setScanTimeOut(3_000L)
                     .setDeviceName(true, BLE_LOCAL_NAME)
                     .build()
                 BleManager.getInstance().initScanRule(bleScanRuleConfig)

+ 3 - 2
app/src/main/java/com/grkj/iscs_mars/modbus/DockBean.kt

@@ -563,14 +563,15 @@ class DockBean(
         lockEnabled: Boolean = false,
         var rfid: String?,
         var mac: String?,
+        var power: Int = 0,
         var isReady: Boolean = false    // 钥匙是否准备好(连接上且为待机模式)
     ) : DeviceBean(DEVICE_TYPE_KEY, idx, isExist, lockEnabled) {
         override fun toString(): String {
-            return "KeyBean(isLeft=$isLeft, isCharging=$isCharging, rfid=$rfid, mac=$mac, isReady=$isReady, idx=$idx, isExist=$isExist)"
+            return "KeyBean(isLeft=$isLeft, isCharging=$isCharging, rfid=$rfid, mac=$mac, isReady=$isReady, idx=$idx, power=$power, isExist=$isExist)"
         }
 
         fun clone(): KeyBean {
-            return KeyBean(idx, isExist, isLeft, isCharging, lockEnabled, rfid, mac, isReady)
+            return KeyBean(idx, isExist, isLeft, isCharging, lockEnabled, rfid, mac, power, isReady)
         }
     }
 

+ 49 - 19
app/src/main/java/com/grkj/iscs_mars/modbus/ModBusController.kt

@@ -8,6 +8,7 @@ import com.grkj.iscs_mars.R
 import com.grkj.iscs_mars.ble.BleConnectionManager
 import com.grkj.iscs_mars.extentions.removeLeadingZeros
 import com.grkj.iscs_mars.extentions.toHexStrings
+import com.grkj.iscs_mars.model.DeviceConst
 import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_CARD
 import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_FINGERPRINT
 import com.grkj.iscs_mars.model.DeviceConst.DEVICE_TYPE_KEY
@@ -17,6 +18,8 @@ import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_ELEC_LOCK_BOARD
 import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_KEY
 import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_LOCK
 import com.grkj.iscs_mars.model.DeviceConst.DOCK_TYPE_PORTABLE
+import com.grkj.iscs_mars.model.eventmsg.MsgEvent
+import com.grkj.iscs_mars.model.eventmsg.MsgEventConstants
 import com.grkj.iscs_mars.model.vo.hardware.CabinetSlotsRecord
 import com.grkj.iscs_mars.util.CommonUtils
 import com.grkj.iscs_mars.util.Executor
@@ -228,30 +231,30 @@ object ModBusController {
                                     // 更新mac
                                     updateKeyMac(dockBean.addr, key.isLeft, keyInfo.macAddress)
                                     controlKeyCharge(true, key.isLeft, dockBean.addr)
-                                    ThreadUtils.runOnMain {
-                                        delay(500)
-                                        val isConnect =
-                                            BleConnectionManager.tryConnectWithOptionalCharge(
-                                                keyInfo.macAddress
-                                            )
-                                        if (isConnect) {
-                                            val bleBean =
-                                                BusinessManager.getBleDeviceByMac(keyInfo.macAddress)
-                                            bleBean?.let {
-                                                Executor.delayOnMain(500) {
-                                                    BusinessManager.getCurrentStatus(
-                                                        3, it.bleDevice
-                                                    )
-                                                    BusinessManager.getBatteryPower(it.bleDevice)
-                                                }
-                                            }
-                                        }
-                                    }
                                     controlKeyBuckle(false, key.isLeft, dockBean.addr)
                                 } else {
                                     ToastUtils.tip(R.string.get_key_info_fail)
                                     controlKeyBuckle(true, key.isLeft, dockBean.addr)
                                 }
+                                val isKeyReady =
+                                    dockList.filter { it.type == DeviceConst.DOCK_TYPE_KEY || it.type == DeviceConst.DOCK_TYPE_PORTABLE }
+                                        .all {
+                                            it.deviceList.filter { it.type == DeviceConst.DEVICE_TYPE_KEY }
+                                                .filterIsInstance<DockBean.KeyBean>()
+                                                .filter { it.isExist }
+                                                .all {
+                                                    LogUtil.i("钥匙否是准备完毕:${it.rfid}")
+                                                    it.rfid != null
+                                                }
+                                        }
+                                if (isKeyReady) {
+                                    BusinessManager.sendEventMsg(
+                                        MsgEvent(
+                                            MsgEventConstants.MSG_EVENT_INIT_KEY_COMPLETE,
+                                            null
+                                        )
+                                    )
+                                }
                             }
                         }
                     } else {
@@ -272,6 +275,19 @@ object ModBusController {
         return dockB?.parseStatus(byteArray)
     }
 
+    /**
+     * 获取存在的钥匙
+     */
+    fun getExistsKey(): List<DockBean.KeyBean> {
+        return dockList.filter {
+            it.type in listOf(
+                DeviceConst.DOCK_TYPE_KEY,
+                DeviceConst.DOCK_TYPE_PORTABLE
+            )
+        }
+            .flatMap { it.deviceList }.filterIsInstance<DockBean.KeyBean>()
+    }
+
     /**
      * 更新所有锁仓状态
      */
@@ -1041,6 +1057,7 @@ object ModBusController {
                 BleManager.getInstance().isConnected(it.mac)
             }    // 主键:在线优先
                 .thenByDescending { BusinessManager.getBleDeviceByMac(it.mac)?.token != null } // 次键:有 token 优先
+                .thenByDescending { it.power }
         )
 
         for (kb in keyList) {
@@ -1129,4 +1146,17 @@ object ModBusController {
             }
         }
     }
+
+    /**
+     * 获取最多电量的钥匙
+     */
+    fun getMaxPowerKey(): DockBean.KeyBean {
+        return dockList.filter {
+            it.type in listOf(
+                DeviceConst.DOCK_TYPE_KEY,
+                DeviceConst.DOCK_TYPE_PORTABLE
+            )
+        }
+            .flatMap { it.deviceList }.filterIsInstance<DockBean.KeyBean>().maxBy { it.power }
+    }
 }

+ 25 - 7
app/src/main/java/com/grkj/iscs_mars/model/Constants.kt

@@ -15,6 +15,8 @@ object Constants {
     const val PERMISSION_REQUEST_CODE = 1
     const val BLE_LOCAL_NAME = "keyLock"
 
+    const val BLE_DISCONNECT_DELAY_TIME = 60_000L
+
     const val USER_TYPE_LOCKER = "0"                // 上锁人
     const val USER_TYPE_COLOCKER = "1"              // 共锁人
 
@@ -75,12 +77,21 @@ object Constants {
     data class SopType(val icon: Int, val type: Int, val title: String)
 
     val SOP_REPAIR = SopType(R.mipmap.repair, 0, CommonUtils.getStr(R.string.repair)!!)
-    val SOP_PRE_MAINTENANCE = SopType(R.mipmap.pre_maintenance, 1, CommonUtils.getStr(R.string.pre_maintenance)!!)
-    val SOP_CHANGE_SHIFTS = SopType(R.mipmap.change_shifts, 2, CommonUtils.getStr(R.string.change_shifts)!!)
+    val SOP_PRE_MAINTENANCE =
+        SopType(R.mipmap.pre_maintenance, 1, CommonUtils.getStr(R.string.pre_maintenance)!!)
+    val SOP_CHANGE_SHIFTS =
+        SopType(R.mipmap.change_shifts, 2, CommonUtils.getStr(R.string.change_shifts)!!)
     val SOP_CLEAN = SopType(R.mipmap.clean, 3, CommonUtils.getStr(R.string.clean)!!)
-    val SOP_SWITCH_PRODUCT = SopType(R.mipmap.switch_product, 4, CommonUtils.getStr(R.string.switch_product)!!)
+    val SOP_SWITCH_PRODUCT =
+        SopType(R.mipmap.switch_product, 4, CommonUtils.getStr(R.string.switch_product)!!)
 
-    val mSopTypeList = mutableListOf(SOP_REPAIR, SOP_PRE_MAINTENANCE, SOP_CHANGE_SHIFTS, SOP_CLEAN, SOP_SWITCH_PRODUCT)
+    val mSopTypeList = mutableListOf(
+        SOP_REPAIR,
+        SOP_PRE_MAINTENANCE,
+        SOP_CHANGE_SHIFTS,
+        SOP_CLEAN,
+        SOP_SWITCH_PRODUCT
+    )
 
     /*************************  虹软ArcSoft  *************************/
     const val APP_ID = "FTN3G4pk8n2RKwjD955sRapRjbYQFefwhHd4sBZMYEz6"
@@ -95,9 +106,16 @@ object Constants {
     private val TICKET_CHANGE_SHIFTS = TicketType(2, "icon.permit.shift")
     private val TICKET_CLEAN = TicketType(3, "icon.permit.clean")
     private val TICKET_SWITCH_PRODUCT = TicketType(4, "icon.permit.changeover")
-    private val TICKET_MORE =  TicketType(5, "icon.permit.more")
-
-    private val mTicketTypeList = mutableListOf(TICKET_REPAIR, TICKET_PRE_MAINTENANCE, TICKET_CHANGE_SHIFTS, TICKET_CLEAN, TICKET_SWITCH_PRODUCT, TICKET_MORE)
+    private val TICKET_MORE = TicketType(5, "icon.permit.more")
+
+    private val mTicketTypeList = mutableListOf(
+        TICKET_REPAIR,
+        TICKET_PRE_MAINTENANCE,
+        TICKET_CHANGE_SHIFTS,
+        TICKET_CLEAN,
+        TICKET_SWITCH_PRODUCT,
+        TICKET_MORE
+    )
 
     fun getTicketKey(type: Int?): String? {
         return mTicketTypeList.find { it.type == type }?.key

+ 5 - 0
app/src/main/java/com/grkj/iscs_mars/model/UrlConsts.kt

@@ -352,4 +352,9 @@ object UrlConsts {
      * 机柜录入rfid标签(需要参数rfid)
      */
     const val INSERT_IS_RFID_BY_CABINET = "/iscs/token/insertIsRfidTokenByCabinet"
+
+    /**
+     * 检查我是否需要连接钥匙
+     */
+    const val GET_MY_SELF_STATE = "/iscs/hardware-api/getMySelfState"
 }

+ 2 - 0
app/src/main/java/com/grkj/iscs_mars/model/eventmsg/MsgEventConstants.kt

@@ -8,6 +8,8 @@ object MsgEventConstants {
     // ------------------------------ 设备 1-002-000 ------------------------------
     const val MSG_EVENT_DEVICE_TAKE_UPDATE = 1_002_000  // 设备取出
 
+    const val MSG_EVENT_INIT_KEY_COMPLETE = 1_002_001 //钥匙初始化完成
+
     // ------------------------------ 作业票 1-003-000 ------------------------------
     const val MSG_EVENT_GET_TICKET_STATUS = 1_003_000   // 获取设备工作票完成情况
     const val MSG_EVENT_UPDATE_TICKET_PROGRESS = 1_003_001  // 更新作业票进度(页面刷新)

+ 76 - 0
app/src/main/java/com/grkj/iscs_mars/service/CheckKeyInfoTask.kt

@@ -0,0 +1,76 @@
+package com.grkj.iscs_mars.service
+
+import com.clj.fastble.BleManager
+import com.grkj.iscs_mars.BusinessManager
+import com.grkj.iscs_mars.ble.BleBean
+import com.grkj.iscs_mars.ble.BleConnectionManager
+import com.grkj.iscs_mars.ble.BleConst
+import com.grkj.iscs_mars.ble.BleIndicateListener
+import com.grkj.iscs_mars.extentions.startsWith
+import com.grkj.iscs_mars.modbus.ModBusController
+import com.grkj.iscs_mars.util.log.LogUtil
+import com.sik.cronjob.annotations.CronJob
+import com.sik.sikcore.thread.ThreadUtils
+import kotlinx.coroutines.delay
+
+/**
+ * 检查钥匙信息任务
+ */
+
+class CheckKeyInfoTask {
+
+    /**
+     * 是检查信息
+     */
+    private var isCheckInfo: Boolean = false
+
+    /**
+     * 已经检查的钥匙
+     */
+    private var checkedKey: MutableList<String> = mutableListOf()
+
+    /**
+     * 检查钥匙信息
+     */
+    @CronJob(intervalMillis = 30 * 60_000L, initialDelay = 0, runOnMainThread = false)
+    fun checkKeyInfo() {
+        LogUtil.i("开始检查钥匙信息")
+        val existsKey = ModBusController.getExistsKey()
+        BleConnectionManager.addBLeIndicateListener(this, object : BleIndicateListener {
+            override fun handleRsp(
+                bleBean: BleBean,
+                byteArray: ByteArray,
+                isNeedLoading: Boolean,
+                prepareDoneCallBack: ((Boolean, BleBean?) -> Unit)?
+            ) {
+                when {
+                    byteArray.startsWith(BleConst.RSP_POWER_STATUS) -> {
+                        if (isCheckInfo) {
+                            BleManager.getInstance().disconnect(bleBean.bleDevice)
+                            BusinessManager.deviceList.removeIf { it.bleDevice.mac == bleBean.bleDevice.mac }
+                            LogUtil.i("断开连接检查信息:${bleBean.bleDevice.mac}")
+                            checkedKey.add(bleBean.bleDevice.mac)
+                            if (checkedKey.joinToString(",") == existsKey.joinToString(",") {
+                                    it.mac ?: ""
+                                }) {
+                                BleConnectionManager.removeBLeIndicateListener(this)
+                                isCheckInfo = false
+                            }
+                        }
+                    }
+                }
+            }
+        })
+        checkedKey.clear()
+        isCheckInfo = true
+        ThreadUtils.runOnIO {
+            existsKey.forEach {
+                it.mac?.let {
+                    BleConnectionManager.tryConnectWithOptionalCharge(it)
+                    delay(2000)
+                }
+            }
+        }
+
+    }
+}

+ 18 - 0
app/src/main/java/com/grkj/iscs_mars/util/NetApi.kt

@@ -1529,4 +1529,22 @@ object NetApi {
             }, isGet = false, isAuth = true
         )
     }
+
+    /**
+     * 检查我是否需要连接钥匙
+     */
+    fun getMySelfState(callBack: (Boolean) -> Unit) {
+        NetHttpManager.getInstance().doRequestNet(
+            UrlConsts.GET_MY_SELF_STATE,
+            false,
+            mapOf<String, String>(),
+            { res, _, _ ->
+                res?.let {
+                    callBack.invoke(true)
+                } ?: run {
+                    callBack.invoke(false)
+                }
+            }, isGet = true, isAuth = true
+        )
+    }
 }

+ 1 - 0
app/src/main/java/com/grkj/iscs_mars/view/activity/HomeActivity.kt

@@ -59,6 +59,7 @@ class HomeActivity : BaseMvpActivity<IHomeView, HomePresenter, ActivityHomeBindi
         presenter?.registerStatusListener()
         presenter?.updateKeyData()
         presenter?.getAndSaveCabinetId()
+        presenter?.getMySelfState()
         val userInfo = intent.getSerializableExtra("userInfo")
 
         BusinessManager.isTestMode = false

+ 2 - 0
app/src/main/java/com/grkj/iscs_mars/view/activity/LoginActivity.kt

@@ -6,6 +6,7 @@ import android.view.InputDevice
 import android.view.KeyEvent
 import android.widget.ImageView
 import com.grkj.iscs_mars.BusinessManager
+import com.grkj.iscs_mars.MyApplication.Companion.cronJobManager
 import com.grkj.iscs_mars.R
 import com.grkj.iscs_mars.databinding.ActivityLoginBinding
 import com.grkj.iscs_mars.extentions.toByteArrays
@@ -35,6 +36,7 @@ class LoginActivity : BaseMvpActivity<ILoginView, LoginPresenter, ActivityLoginB
 
     override fun initView() {
         MMKV.initialize(SIKCore.getApplication())
+        cronJobManager.bindService()
         mBinding?.tvVersion?.text = "v${AppUtils.getPkgVerName(this)}"
 
         mBinding?.tvVersion?.setOnClickListener {

+ 2 - 0
app/src/main/java/com/grkj/iscs_mars/view/fragment/JobProgressFragment.kt

@@ -190,6 +190,7 @@ class JobProgressFragment(val goBack: () -> Unit, val changePage: (PageChangeBO)
                     val ticketId = (newData.data as UpdateTicketProgressMsg).ticketId
                     LogUtil.i("Update progress msg, ticketId : $ticketId")
                     if (ticketId == mPageChangeBO?.ticketId) {
+                        presenter?.getMySelfState()
                         mPageChangeBO?.let {
                             refreshPage(it)
                         }
@@ -319,6 +320,7 @@ class JobProgressFragment(val goBack: () -> Unit, val changePage: (PageChangeBO)
                             cardNo,
                             "5"
                         ) {
+                            presenter?.getMySelfState()
                             refreshPage(mPageChangeBO!!)
                         }
                     }

+ 6 - 2
app/src/main/java/com/grkj/iscs_mars/view/fragment/StepFragment.kt

@@ -117,7 +117,10 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
             }
             if (mStep in 1..5) {
                 presenter?.cancelTicket(mChangePage?.ticketId!!) {
-                    if (it) changePage(PageChangeBO(-1))
+                    if (it) {
+                        presenter?.getMySelfState()
+                        changePage(PageChangeBO(-1))
+                    }
                 }
             } else if (mStep == 8) {
                 if (mStepList.find { it.index == 8 }?.stepDetail?.conflictJobNum != 0) {
@@ -396,7 +399,7 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
                     ToastUtils.tip(
                         getString(
                             R.string.please_done_operation,
-                            mStepList.find { it.index == mStep+1 }?.title
+                            mStepList.find { it.index == mStep + 1 }?.title
                         )
                     )
                     return
@@ -431,6 +434,7 @@ class StepFragment(val goBack: () -> Unit, val changePage: (PageChangeBO) -> Uni
                                 presenter?.updateStep(
                                     mStepList.find { it.index == step }?.stepDetail?.stepId!!, "1"
                                 ) {
+                                    presenter?.getMySelfState()
                                     mChangePage?.let {
                                         refreshPage(it)
                                     }

+ 1 - 0
app/src/main/java/com/grkj/iscs_mars/view/fragment/TechnologySopFragment.kt

@@ -92,6 +92,7 @@ class TechnologySopFragment(val changePage: (PageChangeBO) -> Unit) :
         mBinding?.cbStart?.setOnClickListener {
             presenter?.createTicket(mMachineryIdx, mSopTypeIdx, mMachineryList) {
                 it?.let {
+                    presenter?.getMySelfState()
                     changePage(
                         PageChangeBO(
                             2,

+ 11 - 0
app/src/main/java/com/grkj/iscs_mars/view/presenter/HomePresenter.kt

@@ -123,4 +123,15 @@ class HomePresenter : BasePresenter<IHomeView>() {
                 }
         }
     }
+
+    /**
+     * 获取是否需要我连接钥匙
+     */
+    fun getMySelfState() {
+        NetApi.getMySelfState {
+            if (it){
+                BusinessManager.connectExistsKey()
+            }
+        }
+    }
 }

+ 13 - 2
app/src/main/java/com/grkj/iscs_mars/view/presenter/JobProgressPresenter.kt

@@ -75,8 +75,8 @@ class JobProgressPresenter : BasePresenter<IJobProgressView>() {
             ToastUtils.tip(mContext!!.resources.getString(R.string.ticket_id_is_null))
             return
         }
-        NetApi.getTicketDetail(ticketId) {it,_->
-            if (it==null){
+        NetApi.getTicketDetail(ticketId) { it, _ ->
+            if (it == null) {
                 return@getTicketDetail
             }
             Executor.runOnMain {
@@ -416,4 +416,15 @@ class JobProgressPresenter : BasePresenter<IJobProgressView>() {
             }
         }
     }
+
+    /**
+     * 获取是否需要我连接钥匙
+     */
+    fun getMySelfState() {
+        NetApi.getMySelfState {
+            if (it) {
+                BusinessManager.connectExistsKey()
+            }
+        }
+    }
 }

+ 14 - 2
app/src/main/java/com/grkj/iscs_mars/view/presenter/StepPresenter.kt

@@ -1,6 +1,7 @@
 package com.grkj.iscs_mars.view.presenter
 
 import android.content.Context
+import com.grkj.iscs_mars.BusinessManager
 import com.grkj.iscs_mars.R
 import com.grkj.iscs_mars.modbus.DockBean
 import com.grkj.iscs_mars.modbus.ModBusController
@@ -72,8 +73,8 @@ class StepPresenter : BasePresenter<IStepView>() {
             ToastUtils.tip(mContext!!.resources.getString(R.string.ticket_id_is_null))
             return
         }
-        NetApi.getTicketDetail(ticketId) {it,_->
-            if (it==null){
+        NetApi.getTicketDetail(ticketId) { it, _ ->
+            if (it == null) {
                 return@getTicketDetail
             }
             Executor.runOnMain {
@@ -180,4 +181,15 @@ class StepPresenter : BasePresenter<IStepView>() {
             }
         }
     }
+
+    /**
+     * 获取是否需要我连接钥匙
+     */
+    fun getMySelfState() {
+        NetApi.getMySelfState {
+            if (it) {
+                BusinessManager.connectExistsKey()
+            }
+        }
+    }
 }

+ 11 - 0
app/src/main/java/com/grkj/iscs_mars/view/presenter/TechnologySopPresenter.kt

@@ -51,4 +51,15 @@ class TechnologySopPresenter : BasePresenter<ITechnologySopView>() {
             }
         }
     }
+    
+    /**
+     * 获取是否需要我连接钥匙
+     */
+    fun getMySelfState() {
+        NetApi.getMySelfState {
+            if (it){
+                BusinessManager.connectExistsKey()
+            }
+        }
+    }
 }