/** * MQTT服务模块 * 处理MQTT消息的接收和发送,包括设备管理、人员管理、权限管理等功能 */ import common from "../../dxmodules/dxCommon.js"; import config from "../../dxmodules/dxConfig.js"; import logger from "../../dxmodules/dxLogger.js"; import ota from "../../dxmodules/dxOta.js"; import std from "../../dxmodules/dxStd.js"; import dxMap from '../../dxmodules/dxMap.js' import driver from "../driver.js"; import configService from "./configService.js"; import sqliteService from "./sqliteService.js"; import sqlite from "../../dxmodules/dxSqlite.js"; import utils from '../common/utils/utils.js' const mqttService = {} let map = dxMap.get("faceAccesss") /** * 接收MQTT消息并处理 * @param {object} data - MQTT消息数据 * @param {string} data.topic - 消息主题 * @param {string} data.payload - 消息载荷 */ mqttService.receiveMsg = function (data) { // {"topic":"ddddd","payload":"{\n \"msg\": \"world\"\n}"} logger.info('[mqttService] receiveMsg :' + JSON.stringify(data.topic)) // 提取主题的最后部分作为函数名 if (typeof mqttService[data.topic.match(/[^/]+$/)[0]] == 'function') { mqttService[data.topic.match(/[^/]+$/)[0]](data) } else { logger.error("未实现的topic", data.topic) } } // =================================权限增删改查================================= /** * 添加权限 * @param {object} event - MQTT事件对象 */ mqttService.insertPermission = function (event) { try { logger.info('[mqttService] 接收到insertPermission命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.insertPermissionAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] insertPermission失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] insertPermission成功') return reply(event) } catch (error) { logger.error('[mqttService] insertPermission error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 添加权限通用协议格式 * @param {array} data - 权限数据数组 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.insertPermissionAgreement = function (data) { let permissions = [] for (let i = 0; i < data.length; i++) { const permission = data[i]; if (!permission.permissionId || !permission.userId) { return "id or userId cannot be empty" } if (!permission.extra) { permission.extra = "" } if (!permission.time) { return "time and type cannot be empty" } if (permission.time.type != 0 && permission.time.type != 1 && permission.time.type != 2 && permission.time.type != 3) { return "time type is not supported" } let record = {} record.permissionId = permission.permissionId record.userId = permission.userId record.door = isEmpty(permission.index) ? 0 : permission.index record.extra = isEmpty(permission.extra) ? JSON.stringify({}) : JSON.stringify(permission.extra) record.timeType = permission.time.type record.beginTime = permission.time.type == 0 ? 0 : permission.time.range.beginTime record.endTime = permission.time.type == 0 ? 0 : permission.time.range.endTime record.repeatBeginTime = permission.time.type != 2 ? 0 : permission.time.beginTime record.repeatEndTime = permission.time.type != 2 ? 0 : permission.time.endTime record.period = permission.time.type != 3 ? 0 : JSON.stringify(permission.time.weekPeriodTime) let ret = sqliteService.d1_permission.save(record) if (ret != 0) { // 如果保存失败,尝试删除后重新保存 sqliteService.d1_permission.deleteByPermissionId(record.permissionId) ret = sqliteService.d1_permission.save(record) if (ret != 0) { return "sql error ret:" + ret } else { continue } } } return true } /** * 查询权限 * @param {object} event - MQTT事件对象 */ mqttService.getPermission = function (event) { try { logger.info('[mqttService] 接收到getPermission命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的查询参数:', JSON.stringify(data)) let res = this.getPermissionAgreement(data) logger.info('[mqttService] 查询结果:', JSON.stringify(res)) return reply(event, res) } catch (error) { logger.error('[mqttService] getPermission error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 查询权限通用协议格式 * @param {object} data - 查询参数 * @returns {object} 查询结果 */ mqttService.getPermissionAgreement = function (data) { try { // 确保data参数不为undefined data = data || {} data.page = isEmpty(data.page) ? 0 : data.page data.size = isEmpty(data.size) ? 10 : data.size let totalCount = sqliteService.d1_permission.count(data) let permissions = sqliteService.d1_permission.findAll(data) // 构建返回结果 let content = permissions.map(permission => ({ permissionId: permission.permissionId, userId: permission.userId, extra: JSON.parse(permission.extra ? permission.extra : "{}"), time: { type: permission.timeType, beginTime: permission.timeType != 2 ? undefined : permission.repeatBeginTime, endTime: permission.timeType != 2 ? undefined : permission.repeatEndTime, range: permission.timeType === 0 ? undefined : { beginTime: permission.beginTime, endTime: permission.endTime }, weekPeriodTime: permission.timeType != 3 ? undefined : JSON.parse(permission.period) } })) return { content: content, page: data.page, size: data.size, total: totalCount, totalPage: Math.ceil(totalCount / data.size), count: content.length } } catch (error) { logger.error('[mqttService] getPermissionAgreement error:', error) throw error } } /** * 删除权限 * @param {object} event - MQTT事件对象 */ mqttService.delPermission = function (event) { try { logger.info('[mqttService] 接收到delPermission命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.delPermissionAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] delPermission失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] delPermission成功') return reply(event) } catch (error) { logger.error('[mqttService] delPermission error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 删除权限通用协议格式 * @param {object} data - 删除参数 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.delPermissionAgreement = function (data) { if (data.permissionIds && data.permissionIds.length > 0) { let ret = sqliteService.d1_permission.deleteByPermissionIdInBatch(data.permissionIds) if (ret != 0) { return "sql error ret:" + ret } } if (data.userIds && data.userIds.length > 0) { let ret = sqliteService.d1_permission.deleteByUserIdInBatch(data.userIds) if (ret != 0) { return "sql error ret:" + ret } } return true } /** * 清空权限 * @param {object} event - MQTT事件对象 */ mqttService.clearPermission = function (event) { try { logger.info('[mqttService] 接收到clearPermission命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let ret = sqliteService.d1_permission.deleteAll() if (ret == 0) { logger.info('[mqttService] clearPermission成功') return reply(event) } else { logger.error('[mqttService] clearPermission失败:', "sql error ret:" + ret) return reply(event, "sql error ret:" + ret, CODE.E_100) } } catch (error) { logger.error('[mqttService] clearPermission error:', error) return reply(event, { error: error.message }, CODE.E_100) } } // =================================人员增删改查================================= /** * 添加人员 * @param {object} event - MQTT事件对象 */ mqttService.insertUser = function (event) { try { logger.info('[mqttService] 接收到insertUser命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : [] logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.insertUserAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] insertUser失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] insertUser成功') return reply(event) } catch (error) { logger.error('[mqttService] insertUser error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 添加人员通用协议格式 * @param {array} data - 人员数据数组 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.insertUserAgreement = function (data) { let persons = [] for (let i = 0; i < data.length; i++) { const person = data[i]; // 严格检查数据格式 if (!person.userId || !person.name || person.type === undefined || !person.idCard) { return "数据格式错误,缺少必要字段(userId、name、type、idCard)" } // 检查type字段类型 if (typeof person.type !== 'number') { return "数据格式错误,type字段必须是数字" } // 检查type字段值范围 if (person.type < 0 || person.type > 1) { return "数据格式错误,type字段值必须在0-1之间" } let record = {} record.userId = person.userId record.name = person.name // 处理人员类型字段和身份证号 let extra = {} extra.type = person.type extra.idCard = person.idCard record.extra = JSON.stringify(extra) persons.push(record) // 处理人脸信息 if (person.face) { try { logger.info('[mqttService] 开始处理人脸信息:', person.userId) let faceFilePath = person.face // 检查是否是base64编码的图片数据 if (person.face.startsWith('data:image/')) { logger.info('[mqttService] 检测到base64编码的图片数据') // 提取base64数据 let base64Data = person.face.split(',')[1] // 创建临时文件 faceFilePath = '/app/data/user/temp_face_' + person.userId + '.jpg' std.ensurePathExists(faceFilePath) // 将base64数据转换为文件 common.base64_2binfile(faceFilePath, base64Data) logger.info('[mqttService] 已将base64数据保存为文件:', faceFilePath) } else { return "数据格式错误,face字段必须是base64编码的图片数据" } // 检查文件是否存在 let fileExists = common.systemWithRes(`test -e "${faceFilePath}" && echo "OK" || echo "NO"`, 2) logger.info('[mqttService] 人脸图片文件存在:', fileExists.includes('OK')) if (fileExists.includes('OK')) { // 注册人脸 logger.info('[mqttService] 开始注册人脸:', person.userId) let ret = driver.face.registerFaceByPicFile(person.userId, faceFilePath) logger.info('[mqttService] 注册人脸结果:', ret) if (ret == 0) { // 注册成功后移动图片到用户目录 let src = "/app/data/user/" + person.userId + "/register.jpg" std.ensurePathExists(src) logger.info('[mqttService] 移动人脸图片到用户目录:', faceFilePath, '->', src) common.systemBrief('mv ' + faceFilePath + " " + src) // 保存人脸凭证 logger.info('[mqttService] 保存人脸凭证:', person.userId) let voucherRet = sqliteService.d1_voucher.save({ keyId: std.genRandomStr(32), type: "300", code: src, userId: person.userId, extra: JSON.stringify({ faceType: 0 }) }); logger.info('[mqttService] 保存人脸凭证结果:', voucherRet) } else { logger.error('[mqttService] 注册人脸失败,返回码:', ret) } } else { logger.error('[mqttService] 人脸图片文件不存在:', faceFilePath) } } catch (error) { logger.error('[mqttService] 处理人脸信息错误:', error) return "处理人脸信息错误: " + error.message } finally { logger.info('[mqttService] 人脸信息处理完成:', person.userId) } } } let ret = sqliteService.d1_person.saveAll(persons) if (ret != 0) { //失败了 把这些人全都删除后在新增一下 let userIds = persons.map(obj => obj.userId); sqliteService.d1_person.deleteByUserIdInBatch(userIds) //重新新增 let ret = sqliteService.d1_person.saveAll(persons) if (ret != 0) { return "sql error ret:" + ret } } // 为用户添加对应权限 for (let i = 0; i < data.length; i++) { const person = data[i]; let userId = person.userId let userType = person.type // 只有保管员(0)和科长(1)需要添加权限 if (userType == 0 || userType == 1) { try { // 检查是否已存在权限记录 let existingPermissions = sqliteService.d1_permission.findByUserId(userId) if (existingPermissions && existingPermissions.length == 0) { // 添加永久权限 let permissionRet = sqliteService.d1_permission.save({ permissionId: std.genRandomStr(32), userId: userId, timeType: 0, // 永久权限 beginTime: 0, endTime: 0, repeatBeginTime: 0, repeatEndTime: 0, period: "" }); logger.info('[mqttService] 为用户添加权限结果:', permissionRet) } else { logger.info('[mqttService] 用户已存在权限记录,跳过权限添加:', userId) } } catch (error) { logger.error('[mqttService] 添加权限时出错:', error) } } } return true } /** * 查询人员 * @param {object} event - MQTT事件对象 */ mqttService.getUser = function (event) { try { logger.info('[mqttService] 接收到getUser命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} let res = this.getUserAgreement(data) logger.info('[mqttService] 查询结果:', JSON.stringify(res)) return reply(event, res) } catch (error) { logger.error('[mqttService] getUser error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 查询人员通用协议格式 * @param {object} data - 查询参数 * @returns {object} 查询结果 */ mqttService.getUserAgreement = function (data) { try { data.page = isEmpty(data.page) ? 0 : data.page data.size = isEmpty(data.size) ? 10 : data.size let totalCount = sqliteService.d1_person.count(data) let persons = sqliteService.d1_person.findAll(data) // 解析 extra 字段,JSON字符串转化为JSON对象,消除转义字符 persons.forEach(person => { try { if (person.extra) { person.extra = JSON.parse(person.extra) } } catch (error) { logger.error('[mqttService] 解析 extra 字段错误:', error) } }) let result = { content: persons, page: data.page, size: data.size, total: totalCount, totalPage: Math.ceil(totalCount / data.size), count: persons.length } return result } catch (error) { logger.error('[mqttService] getUserAgreement error:', error) throw error } } /** * 删除人员 * @param {object} event - MQTT事件对象 */ mqttService.delUser = function (event) { try { logger.info('[mqttService] 接收到delUser命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : [] logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.delUserAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] delUser失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] delUser成功') return reply(event) } catch (error) { logger.error('[mqttService] delUser error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 删除人员通用协议格式 * @param {array} data - 人员ID数组 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.delUserAgreement = function (data) { if (data && data.length > 0) { sqliteService.transaction() let ret1 = sqliteService.d1_person.deleteByUserIdInBatch(data) let ret2 = sqliteService.d1_permission.deleteByUserIdInBatch(data) let ret3 = sqliteService.d1_voucher.deleteByUserIdInBatch(data) if (ret1 != 0 || ret2 != 0 || ret3 != 0) { sqliteService.rollback() return "sql error" } sqliteService.commit() // 删除人员的人脸数据 data.forEach(element => { driver.face.delete(element) }); } return true } /** * 清空人员 * @param {object} event - MQTT事件对象 */ mqttService.clearUser = function (event) { try { logger.info('[mqttService] 接收到clearUser命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let persons = sqliteService.d1_person.findAll() // 删除所有人员的人脸数据 logger.info('[mqttService] 开始删除人脸数据,共', persons.length, '条') persons.forEach(element => { driver.face.delete(element.userId) }); let ret1 = sqliteService.d1_person.deleteAll() let ret2 = sqliteService.d1_permission.deleteAll() let ret3 = sqliteService.d1_voucher.deleteAll() if (ret1 == 0 && ret2 == 0 && ret3 == 0) { logger.info('[mqttService] clearUser成功') return reply(event) } else { let errorMsg = "sql error ret: " + ret1 + ", " + ret2 + ", " + ret3 logger.error('[mqttService] clearUser失败:', errorMsg) return reply(event, errorMsg, CODE.E_100) } } catch (error) { logger.error('[mqttService] clearUser error:', error) return reply(event, { error: error.message }, CODE.E_100) } } // =================================凭证增删改查================================= /** * 添加凭证 * @param {object} event - MQTT事件对象 */ mqttService.insertKey = function (event) { try { logger.info('[mqttService] 接收到insertKey命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.insertKeyAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] insertKey失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] insertKey成功') return reply(event) } catch (error) { logger.error('[mqttService] insertKey error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 添加凭证通用协议格式 * @param {array} data - 凭证数据数组 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.insertKeyAgreement = function (data) { let vouchers = [] for (let i = 0; i < data.length; i++) { const voucher = data[i]; if (!voucher.keyId || !voucher.type || !voucher.code || !voucher.userId) { return "keyId or type or code or userId cannot be empty" } // 凭证重复 let ret = sqliteService.d1_voucher.findAllBycode(voucher.code) if (ret.length != 0) { return "Duplicate vouchers" } if (voucher.type == 300) { if (voucher.extra) { if (voucher.extra.faceType != 0 && voucher.extra.faceType != 1) { return "faceType Incorrect format" } } else { return "faceType is required" } } let record = {} record.keyId = voucher.keyId record.type = voucher.type if (voucher.type == "400") { if (voucher.code.length > 6) { return "Password length cannot exceed 6 digits" } } if (voucher.type == "300") { if (voucher.extra.faceType == 0) { record.code = `/app/data/user/${voucher.userId}/register.jpg` // 保存base64图片 std.ensurePathExists(record.code) common.base64_2binfile(record.code, voucher.code) // 注册人脸 let weq = driver.face.registerFaceByPicFile(voucher.userId, record.code) if (weq == 0) { logger.info("注册人脸成功") } else { logger.info("第一次人脸注册失败") //删除重新注册 driver.face.delete(voucher.userId) let res = driver.face.registerFaceByPicFile(voucher.userId, record.code) if (res == 0) { logger.info("第二次注册人脸成功") sqliteService.d1_voucher.deleteByKeyId(record.keyId) } else { return "Face registration failed" } } } else { record.code = voucher.code //特征值注册 let res = driver.face.reg(voucher.userId, voucher.code) if (res != 0) { return "Face registration failed" } } } else { record.code = voucher.code let ret = sqliteService.d1_voucher.findAllByCodeAndType(voucher.code, voucher.type) if (ret.length != 0) { return "Duplicate vouchers" } } record.userId = voucher.userId record.extra = isEmpty(voucher.extra) ? JSON.stringify({ type: 0 }) : JSON.stringify(voucher.extra) vouchers.push(record) } let ret = sqliteService.d1_voucher.saveAll(vouchers) if (ret == 0) { return true } else { return "sql error ret:" + ret } } /** * 查询凭证 * @param {object} event - MQTT事件对象 */ mqttService.getKey = function (event) { try { logger.info('[mqttService] 接收到getKey命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的查询参数:', JSON.stringify(data)) let res = this.getKeyAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] getKey失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] 查询结果:', JSON.stringify(res)) return reply(event, res) } catch (error) { logger.error('[mqttService] getKey error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 查询凭证通用协议格式 * @param {object} data - 查询参数 * @returns {object|string} 查询结果或错误信息 */ mqttService.getKeyAgreement = function (data) { if (!data.type) { return "type is required" } if (data.type == 300) { data.size = 1 } else { data.page = isEmpty(data.page) ? 0 : data.page data.size = isEmpty(data.size) ? 10 : data.size } let totalCount = sqliteService.d1_voucher.count(data) let vouchers = sqliteService.d1_voucher.findAll(data) vouchers.forEach(element => { if (element.type == 300 && element.extra && JSON.parse(element.extra).faceType == 0) { //人脸特殊处理一下 element.code = driver.face.fileToBase64(element.code) } }); return { content: vouchers, page: data.page, size: data.size, total: totalCount, totalPage: Math.ceil(totalCount / data.size), count: vouchers.length } } /** * 删除凭证 * @param {object} event - MQTT事件对象 */ mqttService.delKey = function (event) { try { logger.info('[mqttService] 接收到delKey命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.delKeyAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] delKey失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] delKey成功') return reply(event) } catch (error) { logger.error('[mqttService] delKey error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 删除凭证通用协议格式 * @param {object} data - 删除参数 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.delKeyAgreement = function (data) { if (data.keyIds && data.keyIds.length > 0) { let userIds = [] for (let i = 0; i < data.keyIds.length; i++) { const element = data.keyIds[i]; let res = sqliteService.d1_voucher.findAllByKeyId(element) if (res.length <= 0) { continue } if (res[0].type == 300) { userIds.push(res[0].userId) } } let ret = sqliteService.d1_voucher.deleteByKeyIdInBatch(data.keyIds) if (ret != 0) { return "sql error ret:" + ret } // 删除人脸数据 userIds.forEach(element => { driver.face.delete(element) }); } if (data.userIds && data.userIds.length > 0) { let ret = sqliteService.d1_voucher.deleteByUserIdInBatch(data.userIds) if (ret != 0) { return "sql error ret:" + ret } // 删除人脸数据 data.userIds.forEach(element => { driver.face.delete(element) }); } return true } /** * 清空凭证 * @param {object} event - MQTT事件对象 */ mqttService.clearKey = function (event) { try { logger.info('[mqttService] 接收到clearKey命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let res = sqliteService.d1_voucher.findAll() let userIds = [] res.forEach(element => { if (element.type == 300) { userIds.push(element.userId) } }); logger.info('[mqttService] 找到需要删除的人脸数据,共', userIds.length, '条') let ret = sqliteService.d1_voucher.deleteAll() if (ret == 0) { // 删除人脸数据 logger.info('[mqttService] 开始删除人脸数据') userIds.forEach((element, index) => { driver.face.delete(element) }); logger.info('[mqttService] clearKey成功') reply(event) } else { logger.error('[mqttService] clearKey失败:', "sql error ret:" + ret) reply(event, "sql error ret:" + ret, CODE.E_100) } } catch (error) { logger.error('[mqttService] clearKey error:', error) return reply(event, { error: error.message }, CODE.E_100) } } // =================================应急开仓密码增删改查================================= /** * 添加应急开仓密码 * @param {object} event - MQTT事件对象 */ mqttService.insertEmergencyPassword = function (event) { try { logger.info('[mqttService] 接收到insertEmergencyPassword命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.insertEmergencyPasswordAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] insertEmergencyPassword失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] insertEmergencyPassword成功') return reply(event) } catch (error) { logger.error('[mqttService] insertEmergencyPassword error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 添加应急开仓密码通用协议格式 * @param {object} data - 应急开仓密码数据对象 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.insertEmergencyPasswordAgreement = function (data) { // 应急开仓密码在设备中仅有唯一的1个,所以先清空表 let deleteRet = sqliteService.d1_emergency_password.deleteAll() if (deleteRet != 0) { return "清空旧密码失败: " + deleteRet } // 检查密码是否有效 if (!data.password) { return "password cannot be empty" } // 检查密码长度是否大于等于8位 if (data.password.length < 8) { return "Password length must be at least 8 digits" } // 构建密码记录 let record = {} record.id = data.id || 'emergency_' + Date.now() // 如果没有id,自动生成 record.password = data.password record.description = data.description || "" record.createTime = Date.now() record.updateTime = Date.now() record.status = data.status || 1 // 保存密码 let ret = sqliteService.d1_emergency_password.save(record) if (ret == 0) { return true } else { return "sql error ret:" + ret } } /** * 查询应急开仓密码 * @param {object} event - MQTT事件对象 */ mqttService.getEmergencyPassword = function (event) { try { logger.info('[mqttService] 接收到getEmergencyPassword命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let res = this.getEmergencyPasswordAgreement() logger.info('[mqttService] 查询结果:', JSON.stringify(res)) return reply(event, res) } catch (error) { logger.error('[mqttService] getEmergencyPassword error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 时间戳转日期字符串 * @param {number} timestamp - 时间戳 * @returns {string} 日期字符串,格式:YYYY-MM-DD HH:MM:SS */ function timestampToDateString(timestamp) { const date = new Date(timestamp); const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hours = String(date.getHours()).padStart(2, '0'); const minutes = String(date.getMinutes()).padStart(2, '0'); const seconds = String(date.getSeconds()).padStart(2, '0'); return `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; } /** * 查询应急开仓密码通用协议格式 * @returns {object} 查询结果 */ mqttService.getEmergencyPasswordAgreement = function () { let passwords = sqliteService.d1_emergency_password.findAll() if (passwords && passwords.length > 0) { let password = passwords[0]; // 转换时间戳为字符串格式 password.createTime = timestampToDateString(password.createTime); password.updateTime = timestampToDateString(password.updateTime); return password; } return {}; } /** * 清空应急开仓密码 * @param {object} event - MQTT事件对象 */ mqttService.clearEmergencyPassword = function (event) { try { logger.info('[mqttService] 接收到clearEmergencyPassword命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let ret = sqliteService.d1_emergency_password.deleteAll() if (ret == 0) { logger.info('[mqttService] clearEmergencyPassword成功') return reply(event) } else { logger.error('[mqttService] clearEmergencyPassword失败:', "sql error ret:" + ret) return reply(event, "sql error ret:" + ret, CODE.E_100) } } catch (error) { logger.error('[mqttService] clearEmergencyPassword error:', error) return reply(event, { error: error.message }, CODE.E_100) } } // =================================密钥增删改查================================= /** * 添加密钥 * @param {object} event - MQTT事件对象 */ mqttService.insertSecurity = function (event) { try { logger.info('[mqttService] 接收到insertSecurity命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.insertSecurityAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] insertSecurity失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] insertSecurity成功') return reply(event) } catch (error) { logger.error('[mqttService] insertSecurity error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 添加密钥通用协议格式 * @param {array} data - 密钥数据数组 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.insertSecurityAgreement = function (data) { let securities = [] for (let i = 0; i < data.length; i++) { const security = data[i]; let record = [] record.securityId = security.securityId record.type = security.type record.key = security.key record.value = security.value record.startTime = security.startTime record.endTime = security.endTime securities.push(record) } let ret = sqliteService.d1_security.saveAll(securities) if (ret == 0) { return true } else { return "sql error ret:" + ret } } /** * 查询密钥 * @param {object} event - MQTT事件对象 */ mqttService.getKey = function (event) { try { logger.info('[mqttService] 接收到getKey命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的查询参数:', JSON.stringify(data)) let res = this.getKeyAgreement(data) logger.info('[mqttService] 查询结果:', JSON.stringify(res)) return reply(event, res) } catch (error) { logger.error('[mqttService] getKey error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 查询密钥通用协议格式 * @param {object} data - 查询参数 * @returns {object} 查询结果 */ mqttService.getSecurityAgreement = function (data) { data.page = isEmpty(data.page) ? 0 : data.page data.size = isEmpty(data.size) ? 10 : data.size let totalCount = sqliteService.d1_security.count(data) let securities = sqliteService.d1_security.findAll(data) return { content: securities, page: data.page, size: data.size, total: totalCount, totalPage: Math.ceil(totalCount / data.size), count: securities.length } } /** * 删除密钥 * @param {object} event - MQTT事件对象 */ mqttService.delSecurity = function (event) { try { logger.info('[mqttService] 接收到delSecurity命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.delSecurityAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] delSecurity失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] delSecurity成功') return reply(event) } catch (error) { logger.error('[mqttService] delSecurity error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 删除密钥通用协议格式 * @param {array} data - 密钥ID数组 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.delSecurityAgreement = function (data) { if (data.length > 0) { let ret = sqliteService.d1_security.deleteBySecurityIdInBatch(data) if (ret != 0) { return "sql error ret:" + ret } } return true } /** * 清空密钥 * @param {object} event - MQTT事件对象 */ mqttService.clearSecurity = function (event) { try { logger.info('[mqttService] 接收到clearSecurity命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let ret = sqliteService.d1_key.deleteAll() if (ret == 0) { logger.info('[mqttService] clearSecurity成功') return reply(event) } else { logger.error('[mqttService] clearSecurity失败:', "sql error ret:" + ret) return reply(event, "sql error ret:" + ret, CODE.E_100) } } catch (error) { logger.error('[mqttService] clearSecurity error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 远程控制 * @param {object} event - MQTT事件对象 */ mqttService.control = function (event) { try { logger.info('[mqttService] 接收到control命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload.data || {} switch (data.command) { case 0: //重启 logger.info('[mqttService] 执行重启命令') reply(event) common.asyncReboot(2) return case 1: //远程开门 logger.info('[mqttService] 执行远程开门命令') driver.gpio.open() break case 4: //重置 logger.info('[mqttService] 执行重置命令') common.systemBrief("rm -rf /app/data/config/*") common.systemBrief("rm -rf /app/data/db/*") common.systemBrief("rm -rf /app/data/user/*") common.systemBrief("rm -rf /app/data/user/*") common.systemBrief("rm -rf /vgmj.db") reply(event) common.asyncReboot(2) return case 5: //播放语音 logger.info('[mqttService] 执行播放语音命令') if (data.extra) { let res = common.systemWithRes(`test -e "/app/code/resource/wav/${data.extra.wav}.wav" && echo "OK" || echo "NO"`, 2) if (res.includes('OK')) { driver.alsa.play(`/app/code/resource/wav/${data.extra.wav}.wav`) } } break case 6: // 6:屏幕展示图片 // TODO logger.info('[mqttService] 执行屏幕展示图片命令') break case 7: // 7:屏幕展示文字 // TODO logger.info('[mqttService] 执行屏幕展示文字命令') break case 10: logger.info('[mqttService] 执行二维码展示命令') if (!isEmpty(data.extra.qrCodeBase64) && typeof data.extra.qrCodeBase64 == 'string') { //base64转图片保存 let src = `/app/code/resource/image/app_qrcode.png` std.ensurePathExists(src) common.base64_2binfile(src, data.extra.qrCodeBase64) logger.info('[mqttService] 二维码保存成功') return reply(event) } break default: logger.info('[mqttService] 未知命令:', data.command) break } logger.info('[mqttService] control命令执行完成') return reply(event) } catch (error) { logger.error('[mqttService] control error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 查询配置 * @param {object} event - MQTT事件对象 */ mqttService.getConfig = function (event) { try { logger.info('[mqttService] 接收到getConfig命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let configAll = config.getAll() let res = {} // 配置分组 for (const key in configAll) { const value = configAll[key]; const keys = key.split(".") if (keys.length == 2) { if (!res[keys[0]]) { res[keys[0]] = {} } res[keys[0]][keys[1]] = value } else { res[keys[0]] = value } } res.sys = { // 保留原有的 sysInfo 中的其他值 ...res.sys, totalmem: common.getTotalmem(), freemem: common.getFreemem(), totaldisk: common.getTotaldisk(), freedisk: common.getFreedisk(), freecpu: common.getFreecpu() }; if (isEmpty(data) || typeof data != "string" || data == "") { // 查询全部 logger.info('[mqttService] getConfig成功,返回全部配置,配置数量:', Object.keys(res).length) return reply(event, res) } // 单条件查询"data": "mqttInfo.clientId" let keys = data.split(".") let search = {} if (keys.length == 2) { if (res[keys[0]]) { search[keys[0]] = {} search[keys[0]][keys[1]] = res[keys[0]][keys[1]] } } else { search[keys[0]] = res[keys[0]] } logger.info('[mqttService] getConfig成功,返回指定配置:', JSON.stringify(search)) return reply(event, search) } catch (error) { logger.error('[mqttService] getConfig error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 修改配置 * @param {object} event - MQTT事件对象 */ mqttService.setConfig = function (event) { try { logger.info('[mqttService] 接收到setConfig命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) if (!data || typeof data != 'object') { logger.error('[mqttService] setConfig失败: data should not be empty') return reply(event, "data should not be empty", CODE.E_100) } let res = configService.configVerifyAndSave(data) if (typeof res != 'boolean') { // 返回错误信息 logger.error('[mqttService] setConfig失败:', res) return reply(event, res, CODE.E_100) } if (res) { logger.info('[mqttService] setConfig成功') return reply(event) } else { logger.error('[mqttService] setConfig失败: unknown failure') return reply(event, "unknown failure", CODE.E_100) } } catch (error) { logger.error('[mqttService] setConfig error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 升级固件 * @param {object} event - MQTT事件对象 */ mqttService.upgradeFirmware = function (event) { try { logger.info('[mqttService] 接收到upgradeFirmware命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) if (!data || typeof data != 'object' || typeof data.type != 'number' || typeof data.url != 'string' || typeof data.md5 != 'string') { logger.error('[mqttService] upgradeFirmware失败: data\'s params error') return reply(event, "data's params error", CODE.E_100) } if (data.type == 0) { try { logger.info('[mqttService] 开始固件升级,url:', data.url, 'md5:', data.md5) driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgrading" }) ota.updateHttp(data.url, data.md5, 300) driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgradeSuccess" }) logger.info('[mqttService] 固件升级成功') reply(event) common.asyncReboot(3) return } catch (error) { logger.error('[mqttService] 固件升级失败:', error) driver.screen.upgrade({ title: "confirm.upgrade", content: "confirm.upgradeFail" }) return reply(event, "upgrade failure", CODE.E_100) } } logger.error('[mqttService] upgradeFirmware失败: 不支持的升级类型') return reply(event, "upgrade failure", CODE.E_100) } catch (error) { logger.error('[mqttService] upgradeFirmware error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 查询识别记录 * @param {object} event - MQTT事件对象 */ mqttService.getRecords = function (event) { try { logger.info('[mqttService] 接收到getRecords命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的查询参数:', JSON.stringify(data)) let res = this.getRecordsAgreement(data) logger.info('[mqttService] 查询结果:', JSON.stringify(res)) return reply(event, res) } catch (error) { logger.error('[mqttService] getRecords error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 将日期字符串转换为时间戳(秒) * @param {string} dateString - 日期字符串,格式:YYYY-MM-DD HH:MM:SS * @returns {number} 时间戳(秒) */ function dateStringToTimestamp(dateString) { if (!dateString) return null // 将YYYY-MM-DD HH:MM:SS格式转换为YYYY-MM-DDTHH:MM:SS格式,以便new Date()正确解析 const formattedDateString = dateString.replace(' ', 'T') const date = new Date(formattedDateString) return Math.floor(date.getTime() / 1000) } /** * 查询识别记录通用协议格式 * @param {object} data - 查询参数 * @returns {object} 查询结果 */ mqttService.getRecordsAgreement = function (data) { data.page = isEmpty(data.page) ? 0 : data.page data.size = isEmpty(data.size) ? 10 : data.size // 处理时间参数,将字符串格式转换为时间戳 let startTime = null let endTime = null if (data.startTime) { if (typeof data.startTime === 'string') { startTime = dateStringToTimestamp(data.startTime) } else { startTime = Math.floor(data.startTime / 1000) // 转换为秒级时间戳 } } if (data.endTime) { if (typeof data.endTime === 'string') { endTime = dateStringToTimestamp(data.endTime) } else { endTime = Math.floor(data.endTime / 1000) // 转换为秒级时间戳 } } // 构建查询条件 let queryData = {} let nameFilter = null // 复制其他查询参数 for (const key in data) { if (key !== 'startTime' && key !== 'endTime' && key !== 'name') { queryData[key] = data[key] } else if (key === 'name') { nameFilter = data[key] } } // 构建SQL条件 let whereClause = '' if (startTime) { whereClause += `time >= ${startTime} ` } if (endTime) { if (whereClause) { whereClause += `AND ` } whereClause += `time <= ${endTime} ` } // 复制其他条件 for (const key in queryData) { if (key !== 'page' && key !== 'size') { if (whereClause) { whereClause += `AND ` } if (typeof queryData[key] === 'string') { whereClause += `${key} = '${queryData[key]}' ` } else { whereClause += `${key} = ${queryData[key]} ` } } } // 执行查询 let totalCount = 0 let securities = [] try { // 构建count SQL let countSql = `SELECT COUNT(*) FROM d1_pass_record ` if (whereClause) { countSql += `WHERE ${whereClause} ` } countSql += `;` let countResult = sqlite.select(countSql) if (countResult && countResult[0] && countResult[0]['COUNT(*)']) { totalCount = countResult[0]['COUNT(*)'] } // 构建findAll SQL let findSql = `SELECT * FROM d1_pass_record ` if (whereClause) { findSql += `WHERE ${whereClause} ` } findSql += `ORDER BY time DESC ` if (queryData.page !== undefined && queryData.size !== undefined) { findSql += `LIMIT ${queryData.size} OFFSET ${queryData.page * queryData.size} ` } findSql += `;` securities = sqlite.select(findSql) } catch (error) { logger.error('[mqttService] 查询记录失败:', error) } // 处理每条记录 let processedSecurities = securities.map(record => { // 解析extra字段 let extraData = {} try { if (record.extra && record.extra !== '') { extraData = JSON.parse(record.extra) } } catch (error) { logger.error('[mqttService] 解析extra失败:', error) } // 解析extra2字段 let extra2Data = {} try { if (record.extra2 && record.extra2 !== '') { extra2Data = JSON.parse(record.extra2) } } catch (error) { logger.error('[mqttService] 解析extra2失败:', error) } // 构建新记录 return { id: record.id, keyId: record.keyId, permissionId: record.permissionId, permissionId2: record.permissionId2, userId: record.userId, userId2: record.userId2, type: record.type, code: record.code, door: record.door, time: timestampToDateString(record.time * 1000), // 将秒级时间戳转换为毫秒级,再转换为日期字符串 result: record.result, name: extraData.name || '', idCard: extraData.idCard || '', name2: extra2Data.name || '', idCard2: extra2Data.idCard || '', message: record.message } }) // 应用name过滤 if (nameFilter) { processedSecurities = processedSecurities.filter(record => record.name.toLowerCase().includes(nameFilter.toLowerCase()) ) // 更新总数和总页数 totalCount = processedSecurities.length } return { content: processedSecurities, page: data.page, size: data.size, total: totalCount, totalPage: Math.ceil(totalCount / data.size), count: processedSecurities.length } } /** * 删除记录 * @param {object} event - MQTT事件对象 */ mqttService.delRecords = function (event) { try { logger.info('[mqttService] 接收到delRecords命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) let data = payload.payload && payload.payload.data ? payload.payload.data : {} logger.info('[mqttService] 解析后的参数:', JSON.stringify(data)) let res = this.delRecordsAgreement(data) if (typeof res == 'string') { logger.error('[mqttService] delRecords失败:', res) return reply(event, res, CODE.E_100) } logger.info('[mqttService] delRecords成功') return reply(event) } catch (error) { logger.error('[mqttService] delRecords error:', error) return reply(event, { error: error.message }, CODE.E_100) } } /** * 删除记录通用协议格式 * @param {object} data - 删除参数 * @returns {boolean|string} true表示成功,string表示错误信息 */ mqttService.delRecordsAgreement = function (data) { // 根据时间范围删除记录 if (data.startTime || data.endTime) { logger.info('[mqttService] 时间范围: startTime=' + data.startTime + ', endTime=' + data.endTime) try { // 构建查询条件 let query = {}; if (data.startTime) { query.startTime = data.startTime; } if (data.endTime) { query.endTime = data.endTime; } // 使用getRecordsAgreement函数的查询逻辑来获取符合条件的记录 let result = mqttService.getRecordsAgreement(query); let records = result.content || []; // 逐个删除记录 let deletedCount = 0; for (let record of records) { // 如果是人脸记录,删除对应的图片文件 if (record.type == 300 && record.code) { try { common.systemBrief(`rm -rf ${record.code}`); } catch (error) { logger.error('[mqttService] 删除图片文件出错: ' + error.message); } } // 删除记录 sqliteService.d1_pass_record.delete({ id: record.id }); deletedCount++; } logger.info('[mqttService] 成功删除 ' + deletedCount + ' 条记录'); } catch (error) { logger.error('[mqttService] 删除记录出错: ' + error.message); // 忽略错误,返回成功 } } return true } /** * 通行上报回复 * @param {object} event - MQTT事件对象 */ mqttService.access_reply = function (event) { try { logger.info('[mqttService] 接收到access_reply命令:', JSON.stringify(event.topic)) logger.info('[mqttService] 命令payload:', event.payload) let payload = JSON.parse(event.payload) logger.info('[mqttService] 解析后的参数:', JSON.stringify(payload)) let serialNo = map.get(payload.serialNo) if (serialNo) { logger.info('[mqttService] 清理临时文件:', serialNo) common.systemBrief(`rm -rf ${serialNo}`) map.del(payload.serialNo) } logger.info('[mqttService] 清空通行记录') sqliteService.d1_pass_record.deleteAll() logger.info('[mqttService] access_reply处理完成') } catch (error) { logger.error('[mqttService] access_reply error:', error) } } /** * 在线验证回复 * @param {object} raw - MQTT事件对象 */ mqttService.access_online_reply = function (raw) { try { logger.info('[mqttService] 接收到access_online_reply命令:', JSON.stringify(raw.topic)) logger.info('[mqttService] 命令payload:', raw.payload) let payload = JSON.parse(raw.payload) logger.info('[mqttService] 解析后的参数:', JSON.stringify(payload)) let map = dxMap.get("VERIFY") let data = map.get(payload.serialNo) if (data) { logger.info('[mqttService] 处理在线验证回复,serialNo:', payload.serialNo) map.del(payload.serialNo) driver.mqtt.getOnlinecheckReply(payload) } logger.info('[mqttService] access_online_reply处理完成') } catch (error) { logger.error('[mqttService] access_online_reply error:', error) } } /** * 错误代码定义 */ const CODE = { // 成功 S_000: "000000", // 未知错误 E_100: "100000", // 设备已被禁用 E_101: "100001", // 设备正忙,请稍后再试 E_102: "100002", // 签名检验失败 E_103: "100003", // 超时错误 E_104: "100004", // 设备离线 E_105: "100005", } mqttService.CODE = CODE /** * 上报设备信息和通行记录 */ mqttService.report = function () { // 在线上报 let payloadReply = mqttReply(std.genRandomStr(10), { mac: config.get("sys.mac") || '', version: config.get("sys.version"), appVersion: config.get("sys.version"), releaseTime: config.get("sys.createTime"), type: config.get("net.type"), }, CODE.S_000) driver.mqtt.send("access_device/v2/event/connect", JSON.stringify(payloadReply)) //通行记录上报 - 已关闭 // let res = sqliteService.d1_pass_record.findAll() // if (res.length <= 0) { // return // } // // 筛选出 type === 300 的对象(人脸记录) // let faceArray = res.filter(item => item.type == 300); // // 筛选出 type !== 300 的对象(其他记录) // let recordArray = res.filter(item => item.type != 300); // if (recordArray.length > 0) { // driver.mqtt.send("access_device/v2/event/access", JSON.stringify(mqttReply(std.genRandomStr(10), recordArray, CODE.S_000))) // } // if (faceArray.length > 0) { // let index = 0 // let timer = std.setInterval(() => { // let serialNo = std.genRandomStr(10) // //缓存放入要删除的人脸照片 src // map.del(serialNo) // map.put(serialNo, faceArray[index].code) // // // 检查faceArray[index].code是否有效 // if (faceArray[index].code) { // faceArray[index].code = driver.face.fileToBase64(faceArray[index].code) // } else { // faceArray[index].code = "" // logger.info("人脸记录中code字段为空,跳过Base64转换") // } // // driver.mqtt.send("access_device/v2/event/access", JSON.stringify(mqttReply(serialNo, [faceArray[index]], CODE.S_000))) // index++ // if (!faceArray[index]) { // std.clearInterval(saveTimer) // std.clearInterval(timer) // } // }, 1000) // // 每隔500ms检查一次mqtt连接状态,如果断开,则停止上报 // let saveTimer = std.setInterval(() => { // if (!driver.mqtt.getStatus()) { // std.clearInterval(saveTimer) // std.clearInterval(timer) // } // }, 500) // } } /** * mqtt请求统一回复 * @param {object} event - MQTT事件对象 * @param {any} data - 回复数据 * @param {string} code - 错误代码 */ function reply(event, data, code) { try { let topic = getReplyTopic(event) let payload = JSON.parse(event.payload) let serialNo = payload.serialNo || std.genRandomStr(10) let reply = JSON.stringify(mqttReply(serialNo, data, isEmpty(code) ? CODE.S_000 : code)) driver.mqtt.send(topic, reply) } catch (error) { logger.error('[mqttService] reply error:', error) } } /** * 获取回复主题 * @param {object} data - MQTT事件对象 * @returns {string} 回复主题 */ function getReplyTopic(data) { // return data.topic.replace("/" + config.get("sys.sn"), '') + "_reply"; try { let sn = config.get("mqtt.clientId") return data.topic.replace("/" + sn, '') + "_reply"; } catch (error) { logger.error('[mqttService] getReplyTopic error:', error) // 回退到使用固定格式 return data.topic + "_reply" } } /** * mqtt回复格式构建 * @param {string} serialNo - 序列号 * @param {any} data - 回复数据 * @param {string} code - 错误代码 * @returns {object} 回复格式对象 */ function mqttReply(serialNo, data, code) { // 生成当前时间的字符串格式 const now = new Date(); const year = now.getFullYear(); const month = String(now.getMonth() + 1).padStart(2, '0'); const day = String(now.getDate()).padStart(2, '0'); const hours = String(now.getHours()).padStart(2, '0'); const minutes = String(now.getMinutes()).padStart(2, '0'); const seconds = String(now.getSeconds()).padStart(2, '0'); const timeString = `${year}-${month}-${day} ${hours}:${minutes}:${seconds}`; return { serialNo: serialNo, uuid: config.get("sys.uuid"), sign: '', code: code, data: data, time: timeString } } mqttService.mqttReply = mqttReply /** * 获取所有订阅的topic * @returns {array} 订阅的topic列表 */ mqttService.getTopics = function () { // 获取所有订阅的topic let sn = config.get("mqtt.clientId") const topics = [ "control", "getConfig", "setConfig", "upgradeFirmware", "test", "getPermission", "insertPermission", "delPermission", "clearPermission", "getKey", "insertKey", "delKey", "clearKey", "getUser", "insertUser", "delUser", "clearUser", "getSecurity", "insertSecurity", "delSecurity", "clearSecurity", "getRecords", "delRecords", "insertEmergencyPassword", "delEmergencyPassword", "clearEmergencyPassword", "getEmergencyPassword" ] const eventReplies = ["connect_reply", "alarm_reply", "access_reply", "access_online_reply"] let flag = 'access_device/v2/cmd/' + sn + "/" let eventFlag = 'access_device/v2/event/' + sn + "/" return topics.map(item => flag + item).concat(eventReplies.map(item => eventFlag + item)); } /** * 判空函数 * @param {any} value - 要判断的值 * @returns {boolean} 是否为空 */ function isEmpty(value) { return value === undefined || value === null || value === "" } export default mqttService /* `mqttService.getTopics()` 函数返回的所有 topic 如下: ### 命令 topic(用于接收服务器下发的命令): - `access_device/v2/cmd/{sn}/control` - 控制命令 - `access_device/v2/cmd/{sn}/getConfig` - 获取配置 - `access_device/v2/cmd/{sn}/setConfig` - 设置配置 - `access_device/v2/cmd/{sn}/upgradeFirmware` - 固件升级 - `access_device/v2/cmd/{sn}/test` - 测试命令 - `access_device/v2/cmd/{sn}/getPermission` - 获取权限 - `access_device/v2/cmd/{sn}/insertPermission` - 插入权限 - `access_device/v2/cmd/{sn}/delPermission` - 删除权限 - `access_device/v2/cmd/{sn}/clearPermission` - 清除权限 - `access_device/v2/cmd/{sn}/getKey` - 获取密钥 - `access_device/v2/cmd/{sn}/insertKey` - 插入密钥 - `access_device/v2/cmd/{sn}/delKey` - 删除密钥 - `access_device/v2/cmd/{sn}/clearKey` - 清除密钥 - `access_device/v2/cmd/{sn}/getUser` - 获取用户 - `access_device/v2/cmd/{sn}/insertUser` - 插入用户 - `access_device/v2/cmd/{sn}/delUser` - 删除用户 - `access_device/v2/cmd/{sn}/clearUser` - 清除用户 - `access_device/v2/cmd/{sn}/getSecurity` - 获取安全信息 - `access_device/v2/cmd/{sn}/insertSecurity` - 插入安全信息 - `access_device/v2/cmd/{sn}/delSecurity` - 删除安全信息 - `access_device/v2/cmd/{sn}/clearSecurity` - 清除安全信息 - `access_device/v2/cmd/{sn}/getRecords` - 获取记录 - `access_device/v2/cmd/{sn}/delRecords` - 删除记录 ### 事件回复 topic(用于接收服务器对事件的回复): - `access_device/v2/event/{sn}/connect_reply` - 连接回复 - `access_device/v2/event/{sn}/alarm_reply` - 告警回复 - `access_device/v2/event/{sn}/access_reply` - 通行回复 - `access_device/v2/event/{sn}/access_online_reply` - 在线验证回复 其中 `{sn}` 是设备的序列号,会被替换为实际的设备序列号。 */