const aliyunIot = require("aliyun-iot-device-sdk"); const logger = require("./logger"); const config = require("./config"); const { getAliyunDeviceSecret } = require("./api"); // 阿里云物联网对接管理器:按设备号获取三元组、建立 iotDevice,并在每次收到数据时上报属性 function createAliyunManager({ propertyMapper }) { if (!config.aliyun || !config.aliyun.enabled) { logger.info("Aliyun IoT is disabled by config"); return { reportDeviceData: () => {}, closeAll: () => {} }; } // 设备号 -> { iotDevice, productKey, deviceName } const deviceMap = new Map(); async function ensureIotDevice(deviceNumber) { let entry = deviceMap.get(deviceNumber); if (entry && entry.iotDevice) { return entry; } try { logger.info("Request Aliyun device secret", { deviceNumber }); // 复用旧项目的 api.js 约定:第一个参数是相对路径 const resp = await getAliyunDeviceSecret( "device/info/getAliyunDeviceSecret", deviceNumber ); const body = resp && resp.data ? resp.data : null; if (!body || !body.data) { logger.warn("Aliyun device secret response invalid", { deviceNumber, body }); return null; } const data = body.data; if (!data.productKey || !data.deviceName || !data.deviceSecret) { logger.warn("Aliyun device secret missing fields", { deviceNumber, data }); return null; } const productKey = data.productKey; const deviceName = data.deviceName; const deviceSecret = data.deviceSecret; logger.info("Creating Aliyun IoT device", { deviceNumber, productKey, deviceName }); const iotDevice = aliyunIot.device({ ProductKey: productKey, DeviceName: deviceName, DeviceSecret: deviceSecret }); iotDevice.on("connect", () => { logger.info("Aliyun IoT connected", { deviceNumber, productKey, deviceName }); }); iotDevice.on("error", (err) => { logger.error("Aliyun IoT error", { deviceNumber, error: err.message || err }); }); iotDevice.on("close", () => { logger.warn("Aliyun IoT connection closed", { deviceNumber }); }); entry = { iotDevice, productKey, deviceName }; deviceMap.set(deviceNumber, entry); return entry; } catch (err) { logger.error("ensureIotDevice error", { deviceNumber, error: err.message || err }); return null; } } async function reportDeviceData(deviceNumber, rawData) { try { const entry = await ensureIotDevice(deviceNumber); if (!entry || !entry.iotDevice) { return; } // 使用 PropertyMapper 将内部字段转换为阿里云物模型属性对象 let props = rawData; if (propertyMapper && typeof propertyMapper.transformForAliyun === "function") { try { props = propertyMapper.transformForAliyun(rawData); } catch (e) { logger.error("transformForAliyun error", { deviceNumber, error: e.message || e }); props = rawData; } } // 记录准备上报到阿里云的物模型数据,便于和设备原始数据对照 logger.info("Aliyun postProps payload", { deviceNumber, productKey: entry.productKey, deviceName: entry.deviceName, props }); entry.iotDevice.postProps(props, (res) => { if (res && res.message === "success") { logger.info("Aliyun postProps success", { deviceNumber }); } else { logger.error("Aliyun postProps failed", { deviceNumber, res }); } }); } catch (err) { logger.error("reportDeviceData error", { deviceNumber, error: err.message || err }); } } function closeAll() { for (const [deviceNumber, entry] of deviceMap.entries()) { try { if (entry.iotDevice && typeof entry.iotDevice.end === "function") { entry.iotDevice.end(); } } catch (err) { logger.error("Close Aliyun device error", { deviceNumber, error: err.message || err }); } deviceMap.delete(deviceNumber); } } return { reportDeviceData, closeAll }; } module.exports = createAliyunManager;