背景:客户要求。
留作记录。
const express = require('express');
const Vue = require('vue');
const app = express();
const port = 9090;
const fs = require('fs');
const configFile = "config.json";
const scheduleFile = Vue.ref();
const times = Vue.ref();
const heatingdevicelist = Vue.ref([]);
const mqtt = require('mqtt');
const getMQTTClient = (mydevice) => {
const client = mqtt.connect(mydevice.serveraddress, {
username: mydevice.account,
password: mydevice.password
});
client.on('connect', () => {
client.subscribe(mydevice.subtopic, (err) => {
if (err) {
console.error('Error subscribing to topic', err);
} else {
//console.log('Subscribed to topic');
}
});
});
client.on('message', (topic, message) => {
const messageString = message.toString()
const messageObject = JSON.parse(messageString)
if (messageObject.rs4853h !== undefined) {
for (let j = 0; j < mydevice.Time_strategy_data.length; j++) {
const range = mydevice.Time_strategy_data[j].timeRange
const [startStr, endStr] = range.split('-');
const now = new Date();
const start = new Date();
const end = new Date();
// 设置开始时间
const [startHour, startMinute] = startStr.split(':');
start.setHours(parseInt(startHour, 10));
start.setMinutes(parseInt(startMinute, 10));
// 设置结束时间
const [endHour, endMinute] = endStr.split(':');
end.setHours(parseInt(endHour, 10));
end.setMinutes(parseInt(endMinute, 10));
if (end < start) {
end.setDate(now.getDate() + 1);
}
// 检查当前时间是否在开始时间和结束时间之间
if (now >= start && now <= end) {
const valvePositionModbus = generateDirectives(mydevice.Time_strategy_data[j].valvePosition);
const actValvePosition = modbusToValvePosition(messageObject.rs4853h)
console.log("actValvePosition "+actValvePosition)
console.log("valvePosition "+mydevice.Time_strategy_data[j].valvePosition)
if (Math.abs(mydevice.Time_strategy_data[j].valvePosition - actValvePosition) >= 1) {
const msg = {
rs4853h: valvePositionModbus
};
client.publish(mydevice.pubtopic, JSON.stringify(msg))
}
}
}
}
});
// 处理错误
client.on('error', (err) => {
console.error('Error with MQTT client:', err);
});
return client;
}
const calculateCRC = (data) => {
let crc = 0xffff // Initial CRC value
for (let i = 0; i < data.length; i += 2) {
const byte = parseInt(data.substr(i, 2), 16)
crc ^= byte
for (let j = 0; j < 8; j++) {
if (crc & 0x0001) {
crc = (crc >> 1) ^ 0xa001
} else {
crc >>= 1
}
}
}
// Swap bytes
const crcHigh = (crc & 0xff00) >> 8
const crcLow = crc & 0x00ff
const crcSwapped = (crcLow << 8) | crcHigh
return crcSwapped.toString(16).toUpperCase().padStart(4, '0')
}
const generateDirectives = (value) => {
if (value < 0 || value > 100) {
throw new Error('Value must be between 0 and 100')
}
const multipliedValue = value * 10
const hexValue = `03060001${multipliedValue.toString(16).toUpperCase().padStart(4, '0')}`
const crcChecksum = calculateCRC(hexValue)
const directives = `${hexValue}${crcChecksum}`
// return `拼接后的HEX字符串: ${hexValue}, CRC校验码: ${crcChecksum},最终指令:${directives}`;
return directives
}
const modbusToValvePosition = (modbusData) => {
// Extract the 7th to 10th characters (4 characters) which represent the valve position in hex
const fourthChar = modbusData.charAt(3)
let hexString
if (fourthChar === '6') {
hexString = modbusData.slice(8, 12)
} else {
hexString = modbusData.slice(6, 10)
}
// Convert the hex string to a decimal number
const decimalValue = parseInt(hexString, 16) / 10
return decimalValue
}
const initialize = async () => {
const data = fs.readFileSync(configFile, "utf-8");
const mydata = JSON.parse(data);
scheduleFile.value = mydata.filePath
getSchedule();
}
const getSchedule = () => {
fs.readFile(scheduleFile.value, 'utf8', (err, data) => {
if (err) {
console.error("设备配置文件路径错误。"+err);
heatingdevicelist.value = [];
return;
}else{
heatingdevicelist.value = JSON.parse(data).devices;
}
});
}
// 定义一个定时任务函数
function myScheduleTask() {
for (let i = 0; i < heatingdevicelist.value.length; i++) {
const device = heatingdevicelist.value[i];
const client = getMQTTClient(device);
const msg = {
rs4853h: device.refresh_command
};
// console.log(JSON.stringify(msg))
client.publish(device.pubtopic, JSON.stringify(msg))
}
// process.exit(0); // 优雅地关闭应用
}
setInterval(myScheduleTask, 6000);
app.get('/reload', (req, res) => {
res.send('重新加载配置文件。');
initialize()
});
app.get('/', (req, res) => {
res.send('定时任务正在运行...');
});
initialize();
app.listen(port, () => {
console.log("程序运行中,请勿关闭窗口...")
});