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;
|