487 lines
21 KiB
Kotlin
487 lines
21 KiB
Kotlin
|
|
package com.example.smarthome.data
|
|||
|
|
|
|||
|
|
import android.content.Context
|
|||
|
|
import android.content.SharedPreferences
|
|||
|
|
import android.util.Log
|
|||
|
|
import kotlinx.coroutines.flow.MutableStateFlow
|
|||
|
|
import kotlinx.coroutines.flow.StateFlow
|
|||
|
|
import kotlinx.coroutines.flow.asStateFlow
|
|||
|
|
import org.json.JSONObject
|
|||
|
|
import java.security.MessageDigest
|
|||
|
|
import java.security.NoSuchAlgorithmException
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* MQTT 服务
|
|||
|
|
*
|
|||
|
|
* 依赖库(需要在 build.gradle 中添加):
|
|||
|
|
* implementation("org.eclipse.paho:org.eclipse.paho.client.mqttv3:1.2.5")
|
|||
|
|
* implementation("org.eclipse.paho:org.eclipse.paho.android.service:1.1.1")
|
|||
|
|
*
|
|||
|
|
* AndroidManifest.xml 需要添加:
|
|||
|
|
* <service android:name="org.eclipse.paho.android.service.MqttService" />
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
// ==================== 常量定义(与原代码一致)====================
|
|||
|
|
|
|||
|
|
object MqttConstants {
|
|||
|
|
const val TAG = "MqttService"
|
|||
|
|
|
|||
|
|
// 默认服务器配置
|
|||
|
|
const val HOST_DOMAIN = "mqtt.cd-iot.cn"
|
|||
|
|
const val HOST_DOMAIN_API = "https://www.cd-iot.cn"
|
|||
|
|
const val HOST_PORT = ":1884"
|
|||
|
|
|
|||
|
|
// 主题前缀
|
|||
|
|
const val PUBLISH_HEAD = "bcup/0jnqd7slms9vvaf8/"
|
|||
|
|
const val PUBLISH_TAIL_EVENT = "/event"
|
|||
|
|
const val PUBLISH_TAIL_PROP = "/prop"
|
|||
|
|
const val PUBLISH_TAIL_UPDATEREPLY = "/upgrade/reply"
|
|||
|
|
const val PUBLISH_TAIL_MESSAGEREPLY = "/message/reply"
|
|||
|
|
|
|||
|
|
const val SUBSCRIBE_HEAD = "bcdown/0jnqd7slms9vvaf8/"
|
|||
|
|
const val SUBSCRIBE_TAIL_UPDATE = "/upgrade/set"
|
|||
|
|
const val SUBSCRIBE_TAIL_PROPERTYSET = "/property/set"
|
|||
|
|
const val SUBSCRIBE_TAIL_SERVER = "/service/invoke"
|
|||
|
|
|
|||
|
|
// QoS 等级
|
|||
|
|
const val QOS_DEFAULT = 2
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 数据模型 ====================
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* MQTT 连接状态
|
|||
|
|
*/
|
|||
|
|
enum class MqttConnectionState {
|
|||
|
|
DISCONNECTED,
|
|||
|
|
CONNECTING,
|
|||
|
|
CONNECTED,
|
|||
|
|
CONNECTION_LOST
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 设备信息(与原代码 Door 实体对应)
|
|||
|
|
*/
|
|||
|
|
data class DoorInfo(
|
|||
|
|
val cellName: String = "", // 格口名称
|
|||
|
|
val cabinetName: String = "", // 柜子名称
|
|||
|
|
val cellState: String = "", // 格口状态
|
|||
|
|
val cellVoltageType: String = "", // 电压类型
|
|||
|
|
val cellConnectorType: String = "", // 接口类型
|
|||
|
|
val cellRepairType: String = "", // 格口维修类型
|
|||
|
|
val devType: String = "", // 设备类型
|
|||
|
|
val devCheckType: String = "", // 设备检测类型
|
|||
|
|
val devSn: String = "", // 设备序列号
|
|||
|
|
val devPvd: String = "", // 设备PID/VID
|
|||
|
|
val devPro: String = "", // 设备产品名
|
|||
|
|
val devMfg: String = "", // 设备制造商
|
|||
|
|
val devPwr: String = "", // 设备电量
|
|||
|
|
val devState: String = "", // 设备状态
|
|||
|
|
val devRepairType: String = "" // 设备维修类型
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 借还设备事件
|
|||
|
|
*/
|
|||
|
|
data class DeviceEvent(
|
|||
|
|
val opType: String, // 操作类型
|
|||
|
|
val deviceCode: String, // 设备编码(柜子SN)
|
|||
|
|
val cabinetName: String, // 柜子名称
|
|||
|
|
val devSn: String, // 设备序列号
|
|||
|
|
val doorName: String, // 格口名称
|
|||
|
|
val devType: String, // 设备类型
|
|||
|
|
val userId: String, // 用户ID
|
|||
|
|
val batchId: String, // 批次ID
|
|||
|
|
val opTime: String, // 操作时间
|
|||
|
|
val doorInfo: DoorInfo // 格口信息
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
// ==================== MQTT 服务接口 ====================
|
|||
|
|
|
|||
|
|
interface IMqttService {
|
|||
|
|
val connectionState: StateFlow<MqttConnectionState>
|
|||
|
|
val isMqttConnect: Boolean
|
|||
|
|
|
|||
|
|
// 初始化和连接
|
|||
|
|
fun mqttInit(hostIp: String, deviceSn: String, devicePassword: String)
|
|||
|
|
fun mqttConnect()
|
|||
|
|
fun mqttClose()
|
|||
|
|
|
|||
|
|
// 订阅
|
|||
|
|
fun subscribeUpdate()
|
|||
|
|
fun subscribeLog()
|
|||
|
|
fun subscribeUploadLog()
|
|||
|
|
|
|||
|
|
// 发布 - 设备状态同步
|
|||
|
|
fun publishDb(doorInfo: DoorInfo)
|
|||
|
|
fun publishBorrowdevEvent(event: DeviceEvent)
|
|||
|
|
fun publishReturndevEvent(event: DeviceEvent)
|
|||
|
|
fun publishLosedevEvent(event: DeviceEvent)
|
|||
|
|
|
|||
|
|
// 发布 - 系统消息
|
|||
|
|
fun publishSoftwareVersion(version: String)
|
|||
|
|
fun publishDownLoadReply(code: String, messageId: String, taskId: String)
|
|||
|
|
fun publishLogupload(messageId: String, filename: String, fileUrl: String)
|
|||
|
|
fun publishInitDeviceReply(messageId: String, opType: String)
|
|||
|
|
fun publishCellSetReply(messageId: String)
|
|||
|
|
|
|||
|
|
// 回调设置
|
|||
|
|
fun setMessageCallback(callback: (topic: String, message: String) -> Unit)
|
|||
|
|
fun setConnectionCallback(callback: (MqttConnectionState) -> Unit)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== MQTT 服务实现(模拟)====================
|
|||
|
|
|
|||
|
|
class MqttServiceImpl private constructor(
|
|||
|
|
private val context: Context
|
|||
|
|
) : IMqttService {
|
|||
|
|
|
|||
|
|
companion object {
|
|||
|
|
@Volatile
|
|||
|
|
private var instance: MqttServiceImpl? = null
|
|||
|
|
|
|||
|
|
fun getInstance(context: Context): MqttServiceImpl {
|
|||
|
|
return instance ?: synchronized(this) {
|
|||
|
|
instance ?: MqttServiceImpl(context.applicationContext).also { instance = it }
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 状态
|
|||
|
|
private val _connectionState = MutableStateFlow(MqttConnectionState.DISCONNECTED)
|
|||
|
|
override val connectionState: StateFlow<MqttConnectionState> = _connectionState.asStateFlow()
|
|||
|
|
override val isMqttConnect: Boolean get() = _connectionState.value == MqttConnectionState.CONNECTED
|
|||
|
|
|
|||
|
|
// 配置
|
|||
|
|
private var hostIp: String = ""
|
|||
|
|
private var deviceSn: String = ""
|
|||
|
|
private var clientId: String = ""
|
|||
|
|
private var username: String = ""
|
|||
|
|
private var password: String = ""
|
|||
|
|
|
|||
|
|
// 主题
|
|||
|
|
private var topicPublishDb: String = ""
|
|||
|
|
private var topicPublishSoftwareVersion: String = ""
|
|||
|
|
private var topicPublishUpdateReply: String = ""
|
|||
|
|
private var topicPublishLogUpload: String = ""
|
|||
|
|
private var topicPublishInitDeviceReply: String = ""
|
|||
|
|
private var topicPublishBorrowDev: String = ""
|
|||
|
|
private var topicPublishReturnDev: String = ""
|
|||
|
|
private var topicPublishLoseDev: String = ""
|
|||
|
|
private var topicSubscribeUpdate: String = ""
|
|||
|
|
private var topicSubscribePropertySet: String = ""
|
|||
|
|
private var topicSubscribeServer: String = ""
|
|||
|
|
|
|||
|
|
// 回调
|
|||
|
|
private var messageCallback: ((String, String) -> Unit)? = null
|
|||
|
|
private var connectionCallback: ((MqttConnectionState) -> Unit)? = null
|
|||
|
|
|
|||
|
|
// SharedPreferences
|
|||
|
|
private val sharedPreferences: SharedPreferences by lazy {
|
|||
|
|
context.getSharedPreferences("mqtt_prefs", Context.MODE_PRIVATE)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// TODO: 真实 MQTT 客户端
|
|||
|
|
// private var mqttAndroidClient: MqttAndroidClient? = null
|
|||
|
|
// private var mqttConnectOptions: MqttConnectOptions? = null
|
|||
|
|
|
|||
|
|
// ==================== 初始化 ====================
|
|||
|
|
|
|||
|
|
override fun mqttInit(hostIp: String, deviceSn: String, devicePassword: String) {
|
|||
|
|
if (hostIp.isEmpty()) {
|
|||
|
|
Log.w(MqttConstants.TAG, "mqttInit: hostIp is empty")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Log.d(MqttConstants.TAG, "mqttInit")
|
|||
|
|
this.hostIp = hostIp
|
|||
|
|
this.deviceSn = deviceSn
|
|||
|
|
|
|||
|
|
// 初始化主题(与原代码一致)
|
|||
|
|
topicPublishDb = "${MqttConstants.PUBLISH_HEAD}$deviceSn${MqttConstants.PUBLISH_TAIL_EVENT}"
|
|||
|
|
topicPublishSoftwareVersion = "${MqttConstants.PUBLISH_HEAD}$deviceSn${MqttConstants.PUBLISH_TAIL_PROP}"
|
|||
|
|
topicPublishUpdateReply = "${MqttConstants.PUBLISH_HEAD}$deviceSn${MqttConstants.PUBLISH_TAIL_UPDATEREPLY}"
|
|||
|
|
topicPublishLogUpload = "${MqttConstants.PUBLISH_HEAD}$deviceSn${MqttConstants.PUBLISH_TAIL_MESSAGEREPLY}"
|
|||
|
|
topicPublishInitDeviceReply = "${MqttConstants.PUBLISH_HEAD}$deviceSn${MqttConstants.PUBLISH_TAIL_MESSAGEREPLY}"
|
|||
|
|
topicPublishBorrowDev = "${MqttConstants.PUBLISH_HEAD}$deviceSn${MqttConstants.PUBLISH_TAIL_EVENT}"
|
|||
|
|
topicPublishReturnDev = "${MqttConstants.PUBLISH_HEAD}$deviceSn${MqttConstants.PUBLISH_TAIL_EVENT}"
|
|||
|
|
topicPublishLoseDev = "${MqttConstants.PUBLISH_HEAD}$deviceSn${MqttConstants.PUBLISH_TAIL_EVENT}"
|
|||
|
|
topicSubscribeUpdate = "${MqttConstants.SUBSCRIBE_HEAD}$deviceSn${MqttConstants.SUBSCRIBE_TAIL_UPDATE}"
|
|||
|
|
topicSubscribePropertySet = "${MqttConstants.SUBSCRIBE_HEAD}$deviceSn${MqttConstants.SUBSCRIBE_TAIL_PROPERTYSET}"
|
|||
|
|
topicSubscribeServer = "${MqttConstants.SUBSCRIBE_HEAD}$deviceSn${MqttConstants.SUBSCRIBE_TAIL_SERVER}"
|
|||
|
|
|
|||
|
|
// 生成认证信息(与原代码一致)
|
|||
|
|
clientId = deviceSn
|
|||
|
|
username = "$deviceSn|${System.currentTimeMillis()}"
|
|||
|
|
password = md5("$username|$devicePassword")
|
|||
|
|
|
|||
|
|
Log.d(MqttConstants.TAG, "CLIENTID: $clientId")
|
|||
|
|
Log.d(MqttConstants.TAG, "USERNAME: $username")
|
|||
|
|
|
|||
|
|
val serverUri = "tcp://$hostIp${MqttConstants.HOST_PORT}"
|
|||
|
|
Log.d(MqttConstants.TAG, "serverURI: $serverUri")
|
|||
|
|
|
|||
|
|
// TODO: 初始化真实 MQTT 客户端
|
|||
|
|
// mqttAndroidClient = MqttAndroidClient(context, serverUri, clientId)
|
|||
|
|
// mqttAndroidClient?.setCallback(mqttCallback)
|
|||
|
|
// mqttConnectOptions = MqttConnectOptions().apply {
|
|||
|
|
// isCleanSession = true
|
|||
|
|
// connectionTimeout = 10
|
|||
|
|
// keepAliveInterval = 20
|
|||
|
|
// userName = this@MqttServiceImpl.username
|
|||
|
|
// password = this@MqttServiceImpl.password.toCharArray()
|
|||
|
|
// }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun mqttConnect() {
|
|||
|
|
Log.d(MqttConstants.TAG, "mqttConnect")
|
|||
|
|
_connectionState.value = MqttConnectionState.CONNECTING
|
|||
|
|
connectionCallback?.invoke(MqttConnectionState.CONNECTING)
|
|||
|
|
|
|||
|
|
// TODO: 真实连接
|
|||
|
|
// try {
|
|||
|
|
// mqttAndroidClient?.connect(mqttConnectOptions, null, object : IMqttActionListener {
|
|||
|
|
// override fun onSuccess(asyncActionToken: IMqttToken?) {
|
|||
|
|
// Log.d(TAG, "MQTT连接成功!")
|
|||
|
|
// _connectionState.value = MqttConnectionState.CONNECTED
|
|||
|
|
// connectionCallback?.invoke(MqttConnectionState.CONNECTED)
|
|||
|
|
// publishSoftwareVersion(getSoftwareVersion())
|
|||
|
|
// subscribeUpdate()
|
|||
|
|
// subscribeLog()
|
|||
|
|
// subscribeUploadLog()
|
|||
|
|
// }
|
|||
|
|
// override fun onFailure(asyncActionToken: IMqttToken?, exception: Throwable?) {
|
|||
|
|
// Log.d(TAG, "MQTT连接失败!")
|
|||
|
|
// mqttClose()
|
|||
|
|
// }
|
|||
|
|
// })
|
|||
|
|
// } catch (e: MqttException) {
|
|||
|
|
// e.printStackTrace()
|
|||
|
|
// }
|
|||
|
|
|
|||
|
|
// 模拟连接成功
|
|||
|
|
_connectionState.value = MqttConnectionState.CONNECTED
|
|||
|
|
connectionCallback?.invoke(MqttConnectionState.CONNECTED)
|
|||
|
|
sharedPreferences.edit().putBoolean("connected", true).apply()
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun mqttClose() {
|
|||
|
|
Log.d(MqttConstants.TAG, "mqttClose")
|
|||
|
|
_connectionState.value = MqttConnectionState.DISCONNECTED
|
|||
|
|
connectionCallback?.invoke(MqttConnectionState.DISCONNECTED)
|
|||
|
|
sharedPreferences.edit().putBoolean("connected", false).apply()
|
|||
|
|
|
|||
|
|
// TODO: 断开真实连接
|
|||
|
|
// try {
|
|||
|
|
// mqttAndroidClient?.disconnect()
|
|||
|
|
// } catch (e: MqttException) {
|
|||
|
|
// e.printStackTrace()
|
|||
|
|
// }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 订阅 ====================
|
|||
|
|
|
|||
|
|
override fun subscribeUpdate() {
|
|||
|
|
if (!isMqttConnect) return
|
|||
|
|
Log.d(MqttConstants.TAG, "subscribeUpdate: $topicSubscribeUpdate")
|
|||
|
|
// TODO: mqttAndroidClient?.subscribe(topicSubscribeUpdate, MqttConstants.QOS_DEFAULT)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun subscribeLog() {
|
|||
|
|
if (!isMqttConnect) return
|
|||
|
|
Log.d(MqttConstants.TAG, "subscribeLog: $topicSubscribePropertySet")
|
|||
|
|
// TODO: mqttAndroidClient?.subscribe(topicSubscribePropertySet, MqttConstants.QOS_DEFAULT)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun subscribeUploadLog() {
|
|||
|
|
if (!isMqttConnect) return
|
|||
|
|
Log.d(MqttConstants.TAG, "subscribeUploadLog: $topicSubscribeServer")
|
|||
|
|
// TODO: mqttAndroidClient?.subscribe(topicSubscribeServer, MqttConstants.QOS_DEFAULT)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 发布 - 设备状态 ====================
|
|||
|
|
|
|||
|
|
override fun publishDb(doorInfo: DoorInfo) {
|
|||
|
|
val message = buildDoorInfoSyncEvent(doorInfo)
|
|||
|
|
publish(topicPublishDb, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun publishBorrowdevEvent(event: DeviceEvent) {
|
|||
|
|
val message = buildBorrowDeviceEvent(event)
|
|||
|
|
publish(topicPublishBorrowDev, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun publishReturndevEvent(event: DeviceEvent) {
|
|||
|
|
val message = buildReturnDeviceEvent(event)
|
|||
|
|
publish(topicPublishReturnDev, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun publishLosedevEvent(event: DeviceEvent) {
|
|||
|
|
val message = buildLoseDeviceEvent(event)
|
|||
|
|
publish(topicPublishLoseDev, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 发布 - 系统消息 ====================
|
|||
|
|
|
|||
|
|
override fun publishSoftwareVersion(version: String) {
|
|||
|
|
val message = """{"identifier":"firmware_version","firmware_version":"$version"}"""
|
|||
|
|
publish(topicPublishSoftwareVersion, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun publishDownLoadReply(code: String, messageId: String, taskId: String) {
|
|||
|
|
val replyMsg = when (code) {
|
|||
|
|
"0" -> "等待升级"
|
|||
|
|
"1" -> "已发送设备"
|
|||
|
|
"2" -> "设备收到"
|
|||
|
|
"3" -> "升级成功"
|
|||
|
|
"4" -> "升级失败"
|
|||
|
|
"5" -> "设备离线停止推送"
|
|||
|
|
else -> "未知错误码"
|
|||
|
|
}
|
|||
|
|
val message = """{"messageId":"$messageId","result":{"code":"$code","msg":"$replyMsg","taskId":"$taskId"}}"""
|
|||
|
|
publish(topicPublishUpdateReply, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun publishLogupload(messageId: String, filename: String, fileUrl: String) {
|
|||
|
|
val message = """{"messageId":"$messageId","result":{"code":"200","msg":{"type":"upload_log_reply","fileName":"$filename","fileUrl":"$fileUrl"}}}"""
|
|||
|
|
publish(topicPublishLogUpload, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun publishInitDeviceReply(messageId: String, opType: String) {
|
|||
|
|
val dstr = getDataString()
|
|||
|
|
val message = """{"messageId":"$messageId","result":{"code":"200","msg":{"type":"init_device_reply","status":"ok","optype":"$opType","time":"$dstr"}}}"""
|
|||
|
|
publish(topicPublishInitDeviceReply, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun publishCellSetReply(messageId: String) {
|
|||
|
|
val dstr = getDataString()
|
|||
|
|
val message = """{"messageId":"$messageId","result":{"code":"200","msg":{"type":"door_set_reply","status":"ok","time":"$dstr"}}}"""
|
|||
|
|
publish(topicPublishInitDeviceReply, message)
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 回调 ====================
|
|||
|
|
|
|||
|
|
override fun setMessageCallback(callback: (topic: String, message: String) -> Unit) {
|
|||
|
|
messageCallback = callback
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
override fun setConnectionCallback(callback: (MqttConnectionState) -> Unit) {
|
|||
|
|
connectionCallback = callback
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 内部方法 ====================
|
|||
|
|
|
|||
|
|
private fun publish(topic: String, message: String) {
|
|||
|
|
if (!isMqttConnect) {
|
|||
|
|
Log.w(MqttConstants.TAG, "publish failed: not connected")
|
|||
|
|
return
|
|||
|
|
}
|
|||
|
|
Log.d(MqttConstants.TAG, "publish to $topic: $message")
|
|||
|
|
|
|||
|
|
// TODO: 真实发布
|
|||
|
|
// try {
|
|||
|
|
// mqttAndroidClient?.publish(topic, message.toByteArray(), MqttConstants.QOS_DEFAULT, false)
|
|||
|
|
// } catch (e: MqttException) {
|
|||
|
|
// e.printStackTrace()
|
|||
|
|
// }
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
/**
|
|||
|
|
* 处理收到的消息(由 MqttCallback 调用)
|
|||
|
|
*/
|
|||
|
|
internal fun handleMessage(topic: String, payload: String) {
|
|||
|
|
Log.d(MqttConstants.TAG, "MQTT收到消息:topic:$topic msg:$payload")
|
|||
|
|
messageCallback?.invoke(topic, payload)
|
|||
|
|
|
|||
|
|
try {
|
|||
|
|
when (topic) {
|
|||
|
|
topicSubscribeUpdate -> handleUpdateMessage(payload)
|
|||
|
|
topicSubscribePropertySet -> handlePropertySetMessage(payload)
|
|||
|
|
topicSubscribeServer -> handleServerMessage(payload)
|
|||
|
|
}
|
|||
|
|
} catch (e: Exception) {
|
|||
|
|
Log.e(MqttConstants.TAG, "handleMessage error", e)
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private fun handleUpdateMessage(payload: String) {
|
|||
|
|
val jsonObject = JSONObject(payload)
|
|||
|
|
val body = jsonObject.getString("body")
|
|||
|
|
val bodyJson = JSONObject(body)
|
|||
|
|
|
|||
|
|
val messageId = bodyJson.getString("messageId")
|
|||
|
|
val taskId = bodyJson.getString("taskId")
|
|||
|
|
val firmwareVersion = bodyJson.getString("firmwareVersion")
|
|||
|
|
val url = bodyJson.getString("url")
|
|||
|
|
|
|||
|
|
sharedPreferences.edit().apply {
|
|||
|
|
putString("fw", firmwareVersion)
|
|||
|
|
putString("url", url)
|
|||
|
|
putString("mid", messageId)
|
|||
|
|
putString("tid", taskId)
|
|||
|
|
putString("vcheck", "1")
|
|||
|
|
apply()
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private fun handlePropertySetMessage(payload: String) {
|
|||
|
|
val jsonObject = JSONObject(payload)
|
|||
|
|
val identifier = jsonObject.getString("identifier")
|
|||
|
|
val body = jsonObject.getString("body")
|
|||
|
|
Log.d(MqttConstants.TAG, "PropertySet: $identifier = $body")
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private fun handleServerMessage(payload: String) {
|
|||
|
|
val jsonObject = JSONObject(payload)
|
|||
|
|
val identifier = jsonObject.getString("identifier")
|
|||
|
|
Log.d(MqttConstants.TAG, "Server identifier: $identifier")
|
|||
|
|
// 根据 identifier 处理不同的服务调用
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 消息构建 ====================
|
|||
|
|
|
|||
|
|
private fun buildDoorInfoSyncEvent(info: DoorInfo): String {
|
|||
|
|
return """{"door_info_sync_event":{"devType":"${info.devType}","devSn":"${info.devSn}","devCheckType":"${info.devCheckType}","cabinetName":"${info.cabinetName}","doorState":"${info.cellState}","connectorType":"${info.cellConnectorType}","devPvd":"${info.devPvd}","doorName":"${info.cellName}","doorRepairType":"${info.cellRepairType}","devRepairType":"${info.devRepairType}","devPro":"${info.devPro}","devState":"${info.devState}","devMfg":"${info.devMfg}","devPwr":"${info.devPwr}","doorVoltageType":"${info.cellVoltageType}"}}"""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private fun buildBorrowDeviceEvent(event: DeviceEvent): String {
|
|||
|
|
val doorInfo = event.doorInfo
|
|||
|
|
return """{"borrow_device_event":{"opType":"${event.opType}","deviceCode":"${event.deviceCode}","cabinetName":"${event.cabinetName}","devSn":"${event.devSn}","doorName":"${event.doorName}","devType":"${event.devType}","userId":"${event.userId}","batchId":"${event.batchId}","borrowTime":"${event.opTime}","doorInfo":${buildDoorInfoJson(doorInfo)}}}"""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private fun buildReturnDeviceEvent(event: DeviceEvent): String {
|
|||
|
|
val doorInfo = event.doorInfo
|
|||
|
|
return """{"return_device_event":{"opType":"${event.opType}","deviceCode":"${event.deviceCode}","cabinetName":"${event.cabinetName}","devSn":"${event.devSn}","doorName":"${event.doorName}","devType":"${event.devType}","userId":"${event.userId}","batchId":"${event.batchId}","doorRepairType":"${doorInfo.cellRepairType}","devRepairType":"${doorInfo.devRepairType}","returnTime":"${event.opTime}","doorInfo":${buildDoorInfoJson(doorInfo)}}}"""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private fun buildLoseDeviceEvent(event: DeviceEvent): String {
|
|||
|
|
val doorInfo = event.doorInfo
|
|||
|
|
return """{"lose_device_event":{"opType":"${event.opType}","deviceCode":"${event.deviceCode}","cabinetName":"${event.cabinetName}","devSn":"${event.devSn}","doorName":"${event.doorName}","devType":"${event.devType}","userId":"${event.userId}","batchId":"${event.batchId}","doorRepairType":"${doorInfo.cellRepairType}","devRepairType":"${doorInfo.devRepairType}","loseTime":"${event.opTime}","doorInfo":${buildDoorInfoJson(doorInfo)}}}"""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private fun buildDoorInfoJson(info: DoorInfo): String {
|
|||
|
|
return """{"devType":"${info.devType}","devSn":"${info.devSn}","devCheckType":"${info.devCheckType}","cabinetName":"${info.cabinetName}","doorState":"${info.cellState}","connectorType":"${info.cellConnectorType}","devPvd":"${info.devPvd}","doorName":"${info.cellName}","doorRepairType":"${info.cellRepairType}","devRepairType":"${info.devRepairType}","devPro":"${info.devPro}","devState":"${info.devState}","devMfg":"${info.devMfg}","devPwr":"${info.devPwr}","doorVoltageType":"${info.cellVoltageType}"}"""
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 工具方法 ====================
|
|||
|
|
|
|||
|
|
private fun md5(input: String): String {
|
|||
|
|
return try {
|
|||
|
|
val md = MessageDigest.getInstance("MD5")
|
|||
|
|
val digest = md.digest(input.toByteArray())
|
|||
|
|
digest.joinToString("") { "%02x".format(it) }
|
|||
|
|
} catch (e: NoSuchAlgorithmException) {
|
|||
|
|
""
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
private fun getDataString(): String {
|
|||
|
|
val sdf = java.text.SimpleDateFormat("yyyy-MM-dd HH:mm:ss", java.util.Locale.getDefault())
|
|||
|
|
return sdf.format(java.util.Date())
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// ==================== 便捷扩展 ====================
|
|||
|
|
|
|||
|
|
fun Context.getMqttService(): IMqttService = MqttServiceImpl.getInstance(this)
|