空调控制逻辑变更-1

parent 3c2bef4f
...@@ -67,18 +67,22 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) { ...@@ -67,18 +67,22 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
let deviceEnergyMap = new Map(); let deviceEnergyMap = new Map();
for (let rec of records.data) { for (let rec of records.data) {
let data = rec.data; let data = rec.data;
let energy = data.energy ?? data.total_energy; // let energy = data.energy ?? data.total_energy;
let energy = data.current;
if (energy === undefined) continue; if (energy === undefined) continue;
if (!deviceEnergyMap.has(rec.device_id)) { if (!deviceEnergyMap.has(rec.device_id)) {
deviceEnergyMap.set(rec.device_id, { min: energy, max: energy }); // deviceEnergyMap.set(rec.device_id, { min: energy, max: energy });
deviceEnergyMap.set(rec.device_id, energy);
} else { } else {
let cur = deviceEnergyMap.get(rec.device_id); let cur = deviceEnergyMap.get(rec.device_id);
if (energy < cur.min) cur.min = energy; // if (energy < cur.min) cur.min = energy;
if (energy > cur.max) cur.max = energy; // if (energy > cur.max) cur.max = energy;
energy += cur;
deviceEnergyMap.set(rec.device_id, energy);
} }
} }
for (let { min, max } of deviceEnergyMap.values()) { for (let energy of deviceEnergyMap.values()) {
total += (max - min); total += energy;
} }
return total; return total;
} }
...@@ -764,13 +768,13 @@ export async function controlAcRunning(params: {}) { ...@@ -764,13 +768,13 @@ export async function controlAcRunning(params: {}) {
"indoorUnitAddressFull": [deviceId], "indoorUnitAddressFull": [deviceId],
"workMode": acDeviceKeyMap[mode], "workMode": acDeviceKeyMap[mode],
"onOff": acDeviceKeyMap[power], "onOff": acDeviceKeyMap[power],
"tempSet": setTemp, "tempSet": Number(setTemp),
"fanSpeed": acDeviceKeyMap[fanSpeed], "fanSpeed": acDeviceKeyMap[fanSpeed],
"onOffLock": acDeviceKeyMap[autoControl], "onOffLock": acDeviceKeyMap[autoControl],
"workModeLock": acDeviceKeyMap[autoControl], "workModeLock": acDeviceKeyMap[autoControl],
"tempSetLock": acDeviceKeyMap[autoControl], "tempSetLock": acDeviceKeyMap[autoControl],
"tempSetLo": minTemp, "tempSetLo": Number(minTemp),
"tempSetHi": maxTemp, "tempSetHi": Number(maxTemp),
"openApiAction": autoControl === "解除" ? "control" : "lock" "openApiAction": autoControl === "解除" ? "control" : "lock"
}; };
return await controlIndoorUnit(acPrarms); return await controlIndoorUnit(acPrarms);
...@@ -788,7 +792,8 @@ async function getEnergyTrend(deviceIds: string[], startTime: Date, endTime: Dat ...@@ -788,7 +792,8 @@ async function getEnergyTrend(deviceIds: string[], startTime: Date, endTime: Dat
let intervalMap = new Map(); // key: 时间字符串, value: { deviceMin, deviceMax } let intervalMap = new Map(); // key: 时间字符串, value: { deviceMin, deviceMax }
for (let rec of records.data) { for (let rec of records.data) {
let data = rec.data; let data = rec.data;
let energy = data.energy ?? data.total_energy; // let energy = data.energy ?? data.total_energy;
let energy = data.current;
if (energy === undefined) continue; if (energy === undefined) continue;
let intervalKey: string; let intervalKey: string;
let d = new Date(rec.device_time); let d = new Date(rec.device_time);
...@@ -801,142 +806,215 @@ async function getEnergyTrend(deviceIds: string[], startTime: Date, endTime: Dat ...@@ -801,142 +806,215 @@ async function getEnergyTrend(deviceIds: string[], startTime: Date, endTime: Dat
intervalKey = `${d.getFullYear()}-${pad(d.getMonth()+1)}`; intervalKey = `${d.getFullYear()}-${pad(d.getMonth()+1)}`;
} }
if (!intervalMap.has(intervalKey)) { if (!intervalMap.has(intervalKey)) {
intervalMap.set(intervalKey, { deviceMin: new Map(), deviceMax: new Map() }); intervalMap.set(intervalKey, energy);
}
let entry = intervalMap.get(intervalKey);
if (!entry.deviceMin.has(rec.device_id)) {
entry.deviceMin.set(rec.device_id, energy);
entry.deviceMax.set(rec.device_id, energy);
} else { } else {
let curMin = entry.deviceMin.get(rec.device_id); energy = intervalMap.get(intervalKey) + energy;
let curMax = entry.deviceMax.get(rec.device_id); intervalMap.set(intervalKey, energy);
if (energy < curMin) entry.deviceMin.set(rec.device_id, energy);
if (energy > curMax) entry.deviceMax.set(rec.device_id, energy);
} }
} }
let result = []; let result = [];
for (let [key, { deviceMin, deviceMax }] of intervalMap.entries()) { for (let [key, energy] of intervalMap.entries()) {
let total = 0; result.push({ key, value: energy.toFixed(0) });
for (let [deviceId, minVal] of deviceMin.entries()) {
let maxVal = deviceMax.get(deviceId);
total += (maxVal - minVal);
}
result.push({ key, value: total.toFixed(0) });
} }
result.sort((a, b) => a.key.localeCompare(b.key)); result.sort((a, b) => a.key.localeCompare(b.key));
return result; return result;
} }
// 基于馆内环境温度、湿度变化等,联动空调启停 // 判断当前季节:5-9月为夏季(制冷),其余为冬季(制热)
function getSeason(): 'summer' | 'winter' {
const month = new Date().getMonth() + 1;
return (month >= 5 && month <= 9) ? 'summer' : 'winter';
}
// 根据IAQ温度计算空调设定温度
function calcAcTempSet(temperature: number, season: 'summer' | 'winter'): number {
if (season === 'summer') {
// 夏季制冷:温度越高,设定越低
if (temperature > 26) return 22;
if (temperature >= 22) return 24;
return 26;
} else {
// 冬季制热:温度越低,设定越高
if (temperature > 21) return 18;
if (temperature >= 18) return 20;
return 21;
}
}
// 根据IAQ CO2浓度计算新风控制参数
function calcFanParams(co2: number): { action: 'high' | 'low' | 'standby' } | null {
if (co2 > 1000) return { action: 'high' }; // 新风开启,风量调高
if (co2 < 800) return { action: 'low' }; // 风量调低,新风待机
return null; // 800-1000 区间不做调整
}
// 基于馆内环境温度、CO2浓度等,联动空调启停及新风控制
export async function controlAcByEnvironment(deviceId: string, data: any) { export async function controlAcByEnvironment(deviceId: string, data: any) {
// 获取区域内环境监测设备数据 // 获取区域内环境监测设备数据
let envDevices = await selectDataListByParam(TABLENAME.设备表, { let envDevices = await selectDataListByParam(TABLENAME.设备表, {
device_id: deviceId, device_id: deviceId,
device_type: "环境监测" device_type: "环境监测"
}, ["id", "device_name", "region_key"]); }, ["id", "device_name", "region_key"]);
let controlRes:any = {};
// 若是环境设备,则解析环境设备数据,判断是否需要联动空调设备
if (envDevices.data.length) {
// 通过设备所属区域查询当前区域中的空调设备,获取空调设备标准参数中预设的温度、湿度阈值
let regionKey = envDevices.data[0].region_key;
let acDevices = await selectDataListByParam(TABLENAME.设备表, {
region_key: regionKey,
device_type: "空调"
}, ["id", "device_name", "device_id", "device_ad", "control_params"]);
controlRes = await controlAcRunningApi(acDevices, data.temperature, "");
}
// 加入日志
const now = new Date(); const now = new Date();
const operationTime = now.toISOString().replace('T', ' ').slice(0, 19); const operationTime = now.toISOString().replace('T', ' ').slice(0, 19);
if (controlRes && controlRes.success) { const season = getSeason();
console.log(`调用空调控制成功: 设备 ${deviceId}`); const temperature = data.temperature;
if (controlRes.devices) { const co2 = data.co2;
const logEntries = controlRes.devices.map((acDeviceId: string) => ({
device_id: acDeviceId, // 若是环境设备,则解析环境设备数据,判断是否需要联动
device_type: '空调', if (envDevices.data.length) {
operation_content: { let regionKey = envDevices.data[0].region_key;
option: '自动联动控制',
env_device_id: deviceId, // ===== 空调联动 =====
time: operationTime, if (temperature != null) {
success: true, let acDevices = await selectDataListByParam(TABLENAME.设备表, {
message: controlRes.message || '控制成功', region_key: regionKey,
}, device_type: "空调"
status: 1, }, ["id", "device_name", "device_id", "device_ad", "control_params"]);
created_at: now,
updated_at: now, if (acDevices.data.length > 0) {
})); const tempSet = calcAcTempSet(temperature, season);
await addData(TABLENAME.设备日志表, logEntries); const workMode = season === 'summer' ? 1 : 2; // 1制冷 2制热
const modeName = season === 'summer' ? '制冷' : '制热';
let controlRes = await controlAcRunningApi(acDevices, workMode, tempSet);
// 空调日志
const acLogs = acDevices.data.map((ac: any) => ({
device_id: ac.device_id,
device_type: '空调',
operation_content: {
option: '自动联动控制',
device_id: deviceId,
time: operationTime,
season,
mode: modeName,
roomTemp: temperature,
setTemp: tempSet,
success: controlRes.success,
message: controlRes.message || (controlRes.success ? '控制成功' : '控制失败'),
},
status: controlRes.success ? 1 : 0,
created_at: now,
updated_at: now,
}));
await addData(TABLENAME.设备日志表, acLogs);
if (controlRes.success) {
console.log(`空调联动(${modeName})成功: IAQ温度${temperature}℃ → 设定${tempSet}℃, 设备 ${deviceId}`);
} else {
console.error(`空调联动(${modeName})失败: ${controlRes.message}`);
}
}
} }
} else if (controlRes && !controlRes.success) {
console.log(`调用空调控制失败: 设备 ${deviceId} 模式 ${controlRes.message}`); // ===== 新风联动 =====
if (controlRes.devices) { if (co2 != null) {
const logEntries = controlRes.devices.map((acDeviceId: string) => ({ const fanParams = calcFanParams(co2);
device_id: acDeviceId, if (fanParams) {
device_type: '空调', let fanDevices = await selectDataListByParam(TABLENAME.设备表, {
operation_content: { region_key: regionKey,
option: '自动联动控制', device_type: "新风"
env_device_id: deviceId, }, ["id", "device_name", "device_id", "device_ad"]);
time: operationTime,
success: false, if (fanDevices.data.length > 0) {
message: controlRes.message || '控制失败', let fanControlRes = await controlFanRunningApi(fanDevices, fanParams);
},
status: 0, const fanLogs = fanDevices.data.map((fan: any) => ({
created_at: now, device_id: fan.device_id,
updated_at: now, device_type: '新风',
})); operation_content: {
await addData(TABLENAME.设备日志表, logEntries); option: '自动联动控制',
device_id: deviceId,
time: operationTime,
roomCo2: co2,
action: fanParams.action === 'high' ? '风量调高' : '风量调低待机',
success: fanControlRes.success,
message: fanControlRes.message || (fanControlRes.success ? '控制成功' : '控制失败'),
},
status: fanControlRes.success ? 1 : 0,
created_at: now,
updated_at: now,
}));
await addData(TABLENAME.设备日志表, fanLogs);
if (fanControlRes.success) {
console.log(`新风联动成功: IAQ CO2 ${co2}ppm → ${fanParams.action === 'high' ? '风量调高' : '风量调低待机'}, 设备 ${deviceId}`);
} else {
console.error(`新风联动失败: ${fanControlRes.message}`);
}
}
}
} }
} else {
console.log(`未调用空调控制: 设备 ${deviceId}`);
} }
} }
// 辅助:接入空调控制API,根据温度阈值启停空调设备 // 辅助:接入空调控制API,根据温度设定值启停空调设备
async function controlAcRunningApi(acDevices?: any, temperature?: number, workerMode?: string) { async function controlAcRunningApi(acDevices?: any, workMode?: number, tempSet?: number) {
let workModeMap = {}; let deviceList: any = [];
let deviceMaxList: any = [];
let deviceMinList: any = [];
let openApiAction = "control"; // control: 控制空调模式,lock: 锁定空调模式
acDevices.data.forEach((ac: any) => { acDevices.data.forEach((ac: any) => {
let controlParams = ac.control_params; deviceList.push(ac.device_id);
let maxTemp = controlParams.maxTemp;
let minTemp = controlParams.minTemp;
if (temperature && temperature > maxTemp) {
// 调用空调控制接口启停空调设备
console.log(`联动空调 ${ac.device_name}${ac.id})启停,当前温度:${temperature},阈值范围:${minTemp}-${maxTemp}`);
// 单个接入空调控制API,传入设备ID和控制指令(如开/关、温度设定等)
deviceMaxList.push(ac.device_id);
workModeMap[1] = deviceMaxList;
openApiAction = "control";
} else if (temperature && temperature < minTemp) {
console.log(`联动空调 ${ac.device_name}${ac.id})启停,当前温度:${temperature},阈值范围:${minTemp}-${maxTemp}`);
deviceMinList.push(ac.device_id);
workModeMap[2] = deviceMinList;
openApiAction = "control";
}
}); });
// 多个设备: 接入空调控制API,传入设备ID和控制指令(如开/关、温度设定等)
let controlResults:any = { "success": false, "message": "失败" }; let controlResults: any = { "success": false, "message": "失败" };
if (workModeMap[1]) { if (deviceList.length === 0) return controlResults;
// 处理制冷模式
let coldRes = await controlIndoorUnit({ "indoorUnitAddressFull": workModeMap[1], "workMode": 1, "openApiAction": openApiAction }) let params: any = {
if (!coldRes.success) { "indoorUnitAddressFull": deviceList,
console.error("控制空调设备制冷失败", coldRes); "workMode": workMode,
controlResults.success = false; "onOff": 1, // 联动时自动开机
controlResults.devices = workModeMap[1]; "fanSpeed": 2, // 默认中风
controlResults.message = coldRes.data || "控制空调设备制冷失败"; "openApiAction": "control",
} };
// 如果传入了设定温度,一并下发
if (tempSet != null) {
params.tempSet = tempSet;
} }
if (workModeMap[2]) {
// 处理制热模式 let res = await controlIndoorUnit(params);
let hotRes = await controlIndoorUnit({ "indoorUnitAddressFull": workModeMap[2], "workMode": 2, "openApiAction": openApiAction }) if (res.success) {
if (!hotRes.success) { controlResults.success = true;
console.error("控制空调设备制热失败", hotRes); controlResults.devices = deviceList;
controlResults.success = false; controlResults.message = '控制成功';
controlResults.devices = workModeMap[2]; } else {
controlResults.message = hotRes.data || "控制空调设备制热失败"; controlResults.success = false;
} controlResults.devices = deviceList;
controlResults.message = res.data || '控制空调设备失败';
}
return controlResults;
}
// 辅助:接入新风控制API,根据CO2浓度控制新风风量
async function controlFanRunningApi(fanDevices?: any, fanParams?: { action: 'high' | 'low' | 'standby' }) {
let deviceList: any = [];
fanDevices.data.forEach((fan: any) => {
deviceList.push(fan.device_id);
});
let controlResults: any = { "success": false, "message": "失败" };
if (deviceList.length === 0) return controlResults;
// fanSpeed: 1高风 2中风 4低风;standby模式关停
const fanSpeed = fanParams?.action === 'high' ? 1 : 4;
const onOff = fanParams?.action === 'standby' ? 0 : 1;
let params: any = {
"indoorUnitAddressFull": deviceList,
"onOff": onOff,
"fanSpeed": fanSpeed,
"openApiAction": "control",
};
let res = await controlIndoorUnit(params);
if (res.success) {
controlResults.success = true;
controlResults.devices = deviceList;
controlResults.message = '控制成功';
} else {
controlResults.success = false;
controlResults.devices = deviceList;
controlResults.message = res.data || '控制新风设备失败';
} }
return controlResults; return controlResults;
} }
......
...@@ -136,8 +136,8 @@ async function getRegionList(req, res) { ...@@ -136,8 +136,8 @@ async function getRegionList(req, res) {
* 控制空调开关 * 控制空调开关
*/ */
async function controlAcRunning(req, res) { async function controlAcRunning(req, res) {
let reqConf = {deviceId:'String', mode:'String', power:'String', setTemp:'Number', maxTemp:'Number', minTemp:'Number', autoControl:'String', fanSpeed:'String'}; let reqConf = {deviceId:'String', mode:'String', power:'String', setTemp:'String', maxTemp:'String', minTemp:'String', autoControl:'String', fanSpeed:'String'};
const NotMustHaveKeys = []; const NotMustHaveKeys = [ 'maxTemp', 'minTemp', 'autoControl', 'fanSpeed' ];
let { deviceId, mode, power, setTemp, maxTemp, minTemp, autoControl, fanSpeed } = eccReqParamater(reqConf, req.body, NotMustHaveKeys); let { deviceId, mode, power, setTemp, maxTemp, minTemp, autoControl, fanSpeed } = eccReqParamater(reqConf, req.body, NotMustHaveKeys);
let params = { deviceId, mode, power, setTemp, maxTemp, minTemp, autoControl, fanSpeed }; let params = { deviceId, mode, power, setTemp, maxTemp, minTemp, autoControl, fanSpeed };
const result = await runningBiz.controlAcRunning(params); const result = await runningBiz.controlAcRunning(params);
......
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