客流数据接入

parent 8874fba1
......@@ -19,7 +19,8 @@
<mqttsrv>
<mqttHost>10.100.48.16</mqttHost>
<mqttPort>1883</mqttPort>
<mqttTopic>/milesight/uplink/2026</mqttTopic>
<mqttTopic1>/milesight/uplink/2026</mqttTopic1>
<mqttTopic2>/milesight/uplink/2026_crowd</mqttTopic2>
<username>admin</username>
<password>admin123</password>
</mqttsrv>
......
......@@ -38,7 +38,7 @@ export async function processDeviceData(message) {
console.log('收到数据:', data);
// 提取关键字段
const devEUI = data.devEUI;
const devEUI = data.devEUI ? data.devEUI.toUpperCase() : null;
if (!devEUI) {
console.warn('消息缺少devEUI字段,跳过');
return;
......@@ -93,6 +93,122 @@ export async function processDeviceData(message) {
}
}
/**
* 处理接收到的客流设备数据,并存入数据库
*
* 消息示例:
* {
* device_info: {
* device_mac: 'C0:BA:1F:02:98:F6',
* device_name: 'People Counter',
* device_sn: '6537F53875140008',
* firmware_version: 'V_125-LW.1.0.3-r4',
* hardware_version: 'V1.1',
* ip_address: '192.168.125.114',
* running_time: 4764787,
* wlan_mac: 'C0:BA:1F:02:98:F7'
* },
* region_trigger_data: { region_count_data: [ { region: 1, region_name: 'Region1', region_uuid: 'b63ffafc-857f-4d12-9dc7-d7fddfeb5f0f', total: { current_total: 9 } } ] },
* time_info: {
* dst_status: false,
* enable_dst: false,
* time: '2026-06-18T05:19:23-00:00',
* time_zone: 'UTC-0:00 Western European Time (WET), Greenwich Mean Time (GMT)'
* }
* }
*/
export async function customerDeviceData(message) {
try {
// 解析JSON消息
const msgStr = message.toString();
let data: any;
try {
data = JSON.parse(msgStr);
} catch (e) {
console.error('消息不是合法JSON,跳过:', msgStr);
return;
}
console.log('收到客流数据:', data);
// 提取设备信息
const deviceInfo = data.device_info;
if (!deviceInfo) {
console.warn('消息缺少device_info字段,跳过');
return;
}
const deviceSn = deviceInfo.device_sn ? deviceInfo.device_sn.toUpperCase() : null; // 设备序列号,转大写作为设备标识
if (!deviceSn) {
console.warn('消息缺少device_info.device_sn字段,跳过');
return;
}
const deviceMac = deviceInfo.device_mac;
const deviceName = deviceInfo.device_name || `客流设备_${deviceSn.slice(-6)}`;
// 提取设备时间
const timeInfo = data.time_info;
const deviceTime = timeInfo && timeInfo.time ? new Date(timeInfo.time) : new Date();
// ===== 提取客流数据 =====
const regionTriggerData = data.region_trigger_data;
if (!regionTriggerData || !regionTriggerData.region_count_data || regionTriggerData.region_count_data.length === 0) {
console.warn('消息缺少客流区域数据,跳过');
return;
}
const regionCountData = regionTriggerData.region_count_data;
const now = new Date();
// ===== 设备校验/新增 =====
const deviceRow = await selectOneDataByParam(
TABLENAME.设备表, { device_id: deviceSn }
);
if (!deviceRow) {
// 设备不存在,为每个区域创建一条设备记录
for (const regionData of regionCountData) {
await addData(
TABLENAME.设备表,
{
device_id: deviceSn,
region_key: regionData.region,
device_type: '客流传感器',
device_name: deviceName,
control_params: data,
created_at: now,
updated_at: now,
}
);
console.log(`客流设备已创建: ${deviceSn}, 区域 ${regionData.region}`);
}
}
// 遍历每个区域的客流数据,逐条入库
for (const regionData of regionCountData) {
const regionUuid = regionData.region_uuid;
const regionName = regionData.region_name || '';
const regionNumber = regionData.region;
const currentTotal = regionData.total?.current_total ?? 0;
await addData(
TABLENAME.设备数据表,
{
device_id: deviceSn,
data: regionData.total,
received_time: now,
device_time: deviceTime,
created_at: now,
}
);
console.log(`客流数据入库成功: 设备 ${deviceSn}, 区域 ${regionName || regionUuid}, 当前人数 ${currentTotal}`);
}
console.log(`客流数据处理完成: 设备 ${deviceSn}, 共入库 ${regionCountData.length} 条区域数据`);
} catch (error) {
console.error('客流数据处理失败:', error);
}
}
// ==================== 数据解析与入库函数 ====================
/**
* 将Base64编码的payload解码为十六进制字符串
......
......@@ -659,7 +659,7 @@ export async function controlAcRunning(params: {}) {
let device = await selectOneDataByParam(
TABLENAME.设备表,
{ device_id: deviceId },
["device_id", "region_key", "device_name", "device_ad", "control_params"]
["id", "device_id", "region_key", "device_name", "device_ad", "control_params"]
);
if (!device.data || !device.data.id) {
throw new BizError(ERRORENUM.未找到数据, `设备 ${deviceId} 未注册`);
......
......@@ -40,12 +40,13 @@ export async function initConfig() {
// mqtt
if (mqttsrv) {
let configInfo = mqttsrv[0];
systemConfig.mqttsrv = { host: '', port: 0, topic: '', username: '', password: '' };
systemConfig.mqttsrv = { host: '', port: 0, topic_env: '', topic_crowd: '', username: '', password: '' };
if (configInfo.mqttHost && configInfo.mqttPort && configInfo.mqttTopic) {
if (configInfo.mqttHost && configInfo.mqttPort && (configInfo.mqttTopic1 || configInfo.mqttTopic2)) {
systemConfig.mqttsrv.host = configInfo.mqttHost[0];
systemConfig.mqttsrv.port = parseInt(configInfo.mqttPort[0]);
systemConfig.mqttsrv.topic = configInfo.mqttTopic[0];
systemConfig.mqttsrv.topic_env = configInfo.mqttTopic1[0];
systemConfig.mqttsrv.topic_crowd = configInfo.mqttTopic2[0];
systemConfig.mqttsrv.username = configInfo.username[0];
systemConfig.mqttsrv.password = configInfo.password[0];
}
......
......@@ -18,7 +18,8 @@ export class ServerConfig {
mqttsrv: {
host:string,
port:number,
topic:string,
topic_env:string,
topic_crowd:string,
username:string,
password:string
}
......
......@@ -38,6 +38,8 @@ export function setRouter(httpServer) {
/** 停止数据集成 */
httpServer.post('/api/qdm/run/stop/schedule', asyncHandler(stopSchedule));
/** 获取环境监测数据 */
httpServer.post('/api/qdm/device/environment', asyncHandler(getEnvironmentData));
}
/**
......@@ -157,6 +159,18 @@ async function stopSchedule(req, res) {
res.success(result);
}
/**
* 获取环境监测数据
*/
async function getEnvironmentData(req, res) {
let reqConf = {regionGroup:'String', regionType:'String', regionKey:'Number', deviceId:'String'};
const NotMustHaveKeys = ["regionGroup", "regionType", "regionKey", "deviceId"];
let { regionGroup, regionType, regionKey, deviceId } = eccReqParamater(reqConf, req.body, NotMustHaveKeys);
const result = await deviceBiz.getEnvironmentData(regionGroup, regionType, regionKey, deviceId);
res.success(result);
}
......
import { processDeviceData } from "../biz/mqttClient";
import { processDeviceData, customerDeviceData} from "../biz/mqttClient";
import { systemConfig } from "../config/serverConfig";
const mqtt = require('mqtt');
......@@ -21,12 +21,20 @@ export async function startMqttClient() {
client.on('connect', () => {
console.log('MQTT客户端已连接,正在订阅主题...');
// 订阅网关的上行主题
client.subscribe(systemConfig.mqttsrv.topic, (err) => {
client.subscribe(systemConfig.mqttsrv.topic_env, (err) => {
if (err) {
console.error('订阅失败:', err);
console.error('环境订阅失败:', err);
} else {
console.log(`成功订阅主题: ${systemConfig.mqttsrv.topic}`);
console.log('等待设备数据...');
console.log(`成功订阅环境主题: ${systemConfig.mqttsrv.topic_env}`);
console.log('等待环境设备数据...');
}
});
client.subscribe(systemConfig.mqttsrv.topic_crowd, (err) => {
if (err) {
console.error('客流订阅失败:', err);
} else {
console.log(`成功订阅客流主题: ${systemConfig.mqttsrv.topic_crowd}`);
console.log('等待客流设备数据...');
}
});
});
......@@ -34,9 +42,12 @@ export async function startMqttClient() {
// 当收到消息时触发处理
client.on('message', (topic, message) => {
// 只处理配置的上行主题
if (topic === systemConfig.mqttsrv.topic) {
if (topic === systemConfig.mqttsrv.topic_env) {
processDeviceData(message);
}
if (topic === systemConfig.mqttsrv.topic_crowd) {
customerDeviceData(message);
}
});
client.on('error', (err) => {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment