空调联动管理

parent a716b29d
...@@ -11,11 +11,11 @@ ...@@ -11,11 +11,11 @@
* // 热湿环境 * // 热湿环境
* rshj: { pmv: "+0.28", ppd: "5.6%", wd: "22.5℃", sd: "50%", pmvTrend: [...] } * rshj: { pmv: "+0.28", ppd: "5.6%", wd: "22.5℃", sd: "50%", pmvTrend: [...] }
* // 空气品质 * // 空气品质
* kqpz: { co2: "0.28", pm25: "5.6", tvoc: "22.5", pm10: "50", kqpzTrend: [...] } * kqpz: { co2: "0.28ppm", pm25: "5.6μg/m³", tvoc: "22.5μg/m³", pm10: "50μg/m³", kqpzTrend: [...] }
* // 光环境 * // 光环境
* ghj: { lux: "+0.28", ugr: "5.6%", ghjTrend: [...] } * ghj: { lux: "+0.28lux", ugr: "5.6%", ghjTrend: [...] }
* // 声环境 * // 声环境
* shj: { dB: "28", nr: "NR-222", maxdB: "56", shjTrend: [...] } * shj: { dB: "28dB", nr: "NR-222", maxdB: "56dB", shjTrend: [...] }
* // 区域综合舒适度 * // 区域综合舒适度
* qyzhssd: [{ regionName: "办公室", pmv: "0.28", co2: "0.28", lux: "0.28", dB: "0.28", zhssd: "28", zb: "28%" }, ...] * qyzhssd: [{ regionName: "办公室", pmv: "0.28", co2: "0.28", lux: "0.28", dB: "0.28", zhssd: "28", zb: "28%" }, ...]
* // 实时异常监控 * // 实时异常监控
...@@ -319,7 +319,7 @@ async function getRegionData(): Promise<Array<{ ...@@ -319,7 +319,7 @@ async function getRegionData(): Promise<Array<{
for (const row of latestData) { for (const row of latestData) {
const rk = deviceRegionMap[row.device_id]; const rk = deviceRegionMap[row.device_id];
if (!rk || !row.device_data) continue; if (!rk || !row.device_data) continue;
if (!regionAgg[rk]) regionAgg[rk] = { temp: [], hum: [], co2: [], lux: [], a14263: [] }; if (!regionAgg[rk]) regionAgg[rk] = { temp: [], hum: [], co2: [], lux: [], a14263: [] };
const d = row.device_data; const d = row.device_data;
if (d.temperature !== undefined) regionAgg[rk].temp.push(d.temperature); if (d.temperature !== undefined) regionAgg[rk].temp.push(d.temperature);
if (d.humidity !== undefined) regionAgg[rk].hum.push(d.humidity); if (d.humidity !== undefined) regionAgg[rk].hum.push(d.humidity);
...@@ -529,10 +529,10 @@ export async function getCustomsAnalysis() { ...@@ -529,10 +529,10 @@ export async function getCustomsAnalysis() {
pmvTrend: pmvTrendSliced, pmvTrend: pmvTrendSliced,
}, },
kqpz: { kqpz: {
co2: sensorData.co2.toFixed(2), co2: sensorData.co2.toFixed(2) + 'ppm',
pm25: sensorData.pm25.toFixed(2), pm25: sensorData.pm25.toFixed(2) + 'μg/m³',
tvoc: sensorData.tvoc.toFixed(2), tvoc: sensorData.tvoc.toFixed(2) + 'μg/m³',
pm10: (sensorData.pm10 || 0).toFixed(2), pm10: (sensorData.pm10 || 0).toFixed(2) + 'μg/m³',
kqpzTrend: airTrendSliced, kqpzTrend: airTrendSliced,
}, },
ghj: { ghj: {
...@@ -541,9 +541,9 @@ export async function getCustomsAnalysis() { ...@@ -541,9 +541,9 @@ export async function getCustomsAnalysis() {
ghjTrend: lightTrendSliced, ghjTrend: lightTrendSliced,
}, },
shj: { shj: {
dB: sensorData.a14263.toFixed(2), dB: sensorData.a14263.toFixed(2) + 'dB',
nr: 'NR-' + Math.round(nr), nr: 'NR-' + Math.round(nr),
maxdB: maxNoise.toFixed(2), maxdB: maxNoise.toFixed(2) + 'dB',
shjTrend: noiseTrendSliced, shjTrend: noiseTrendSliced,
}, },
qyzhssd: regionData, qyzhssd: regionData,
......
...@@ -20,17 +20,17 @@ export const STANDARDS = { ...@@ -20,17 +20,17 @@ export const STANDARDS = {
}; };
/** PMV 舒适区间 [-0.5, +0.5] */ /** PMV 舒适区间 [-0.5, +0.5] */
const PMV_COMFORT_MIN = -0.5; export const PMV_COMFORT_MIN = -0.5;
const PMV_COMFORT_MAX = 0.5; export const PMV_COMFORT_MAX = 0.5;
/** PPD 限值 ≤ 20% */ /** PPD 限值 ≤ 20% */
const PPD_LIMIT = 20; export const PPD_LIMIT = 20;
/** UGR 展厅限值 ≤ 22 */ /** UGR 展厅限值 ≤ 22 */
const UGR_LIMIT = 22; export const UGR_LIMIT = 22;
/** NR 办公场所限值 ≤ 40 */ /** NR 办公场所限值 ≤ 40 */
const NR_LIMIT = 40; export const NR_LIMIT = 40;
/** 噪音 24h 峰值告警阈值 > 65 dB(A) */ /** 噪音 24h 峰值告警阈值 > 65 dB(A) */
export const NOISE_ALERT_THRESHOLD = 65; export const NOISE_ALERT_THRESHOLD = 65;
......
...@@ -16,6 +16,7 @@ import { ...@@ -16,6 +16,7 @@ import {
getDataSourceDetail, getDataSourceDetail,
} from "./diqinClient"; } from "./diqinClient";
import { mysqlModelMap } from "../model/sqlModelBind"; import { mysqlModelMap } from "../model/sqlModelBind";
import { acLinkageControl } from "./acLinkage";
import { systemConfig } from "../config/serverConfig"; import { systemConfig } from "../config/serverConfig";
import Sequelize from "sequelize"; import Sequelize from "sequelize";
import { DEVICE_STATE, WORK_MODE_TEXT_MAP, FAN_SPEED_TEXT_MAP } from "../config/businessEnum"; import { DEVICE_STATE, WORK_MODE_TEXT_MAP, FAN_SPEED_TEXT_MAP } from "../config/businessEnum";
...@@ -1645,6 +1646,8 @@ export async function diqinSyncAll() { ...@@ -1645,6 +1646,8 @@ export async function diqinSyncAll() {
await diqinRegionDeviceRel(); await diqinRegionDeviceRel();
await diqinDeviceRegionKey(); await diqinDeviceRegionKey();
await diqinDeviceData(); await diqinDeviceData();
// 环境数据同步后触发空调自动联动控制
await acLinkageControl();
console.log('[迪勤全量同步] 完成'); console.log('[迪勤全量同步] 完成');
} }
......
...@@ -283,7 +283,8 @@ export async function editAcDeviceControl(params: { ...@@ -283,7 +283,8 @@ export async function editAcDeviceControl(params: {
if (deviceMode) acParams.workMode = workModeMap[deviceMode]; if (deviceMode) acParams.workMode = workModeMap[deviceMode];
// 3. 调用飞奕控制接口 // 3. 调用飞奕控制接口
const result = await controlIndoorUnit(acParams); const result = { success:false,data:{} };
// result = await controlIndoorUnit(acParams);
// 4. 记录操作日志 // 4. 记录操作日志
const now = new Date(); const now = new Date();
...@@ -296,9 +297,9 @@ export async function editAcDeviceControl(params: { ...@@ -296,9 +297,9 @@ export async function editAcDeviceControl(params: {
device_id: deviceId, device_id: deviceId,
time: formatLocalTime(now), time: formatLocalTime(now),
power: power, power: power,
setTemp: setTemp, set_temp: setTemp ?? '',
fanSpeed: fanSpeed, fan_speed: fanSpeed ?? '',
deviceMode: deviceMode, device_mode: deviceMode ?? '',
success: result.success, success: result.success,
message: result.data || (result.success ? '控制成功' : '控制失败'), message: result.data || (result.success ? '控制成功' : '控制失败'),
}, },
...@@ -622,7 +623,7 @@ export async function batchEditLocalDevices(params: { ...@@ -622,7 +623,7 @@ export async function batchEditLocalDevices(params: {
deviceName?: string; deviceName?: string;
regionKey?: number; regionKey?: number;
deviceType?: string; deviceType?: string;
controlParams?: string; linkageStart?: string;
deviceState?: string; deviceState?: string;
}; };
}) { }) {
...@@ -645,7 +646,7 @@ export async function batchEditLocalDevices(params: { ...@@ -645,7 +646,7 @@ export async function batchEditLocalDevices(params: {
if (edits.deviceName !== undefined) dbEdits.device_name = edits.deviceName; if (edits.deviceName !== undefined) dbEdits.device_name = edits.deviceName;
if (edits.regionKey !== undefined) dbEdits.region_key = edits.regionKey; if (edits.regionKey !== undefined) dbEdits.region_key = edits.regionKey;
if (edits.deviceType !== undefined) dbEdits.device_type = edits.deviceType; if (edits.deviceType !== undefined) dbEdits.device_type = edits.deviceType;
if (edits.controlParams !== undefined) dbEdits.device_param = edits.controlParams; if (edits.linkageStart !== undefined) dbEdits.linkage_start = edits.linkageStart;
if (edits.deviceState !== undefined) dbEdits.device_state = edits.deviceState; if (edits.deviceState !== undefined) dbEdits.device_state = edits.deviceState;
if (Object.keys(dbEdits).length === 0) { if (Object.keys(dbEdits).length === 0) {
......
...@@ -13,6 +13,7 @@ export enum TABLENAME { ...@@ -13,6 +13,7 @@ export enum TABLENAME {
日程设备关联表 = 'schedule_device', 日程设备关联表 = 'schedule_device',
设备故障表 = 'device_fault', 设备故障表 = 'device_fault',
设备联动调节表 = 'device_linkage', 设备联动调节表 = 'device_linkage',
设备联动状态表 = 'device_linkage_state',
设备扩展表 = 'device_expansion', 设备扩展表 = 'device_expansion',
区域电费表 = 'region_expenses', 区域电费表 = 'region_expenses',
}; };
......
...@@ -484,7 +484,7 @@ export const TablesConfig = [ ...@@ -484,7 +484,7 @@ export const TablesConfig = [
comment: '日志标题' comment: '日志标题'
}, },
operation_content: { operation_content: {
type: Sequelize.TEXT, type: Sequelize.JSON,
allowNull: true, allowNull: true,
comment: '操作内容' comment: '操作内容'
}, },
...@@ -659,6 +659,27 @@ export const TablesConfig = [ ...@@ -659,6 +659,27 @@ export const TablesConfig = [
allowNull: true, allowNull: true,
comment: '中间设置:处于阈值区间内的设定值' comment: '中间设置:处于阈值区间内的设定值'
}, },
fan_speed_max: {
type: DataTypes.STRING(50),
allowNull: true,
comment: '上限风速:高风/中风/低风'
},
fan_speed_mid: {
type: DataTypes.STRING(50),
allowNull: true,
comment: '中间风速:高风/中风/低风'
},
fan_speed_min: {
type: DataTypes.STRING(50),
allowNull: true,
comment: '下限风速:高风/中风/低风'
},
is_use: {
type: DataTypes.STRING(10),
allowNull: true,
defaultValue: 'on',
comment: '是否启用:on=启用, off=停用'
},
divide_method: { divide_method: {
type: DataTypes.STRING(50), type: DataTypes.STRING(50),
allowNull: true, allowNull: true,
...@@ -694,6 +715,67 @@ export const TablesConfig = [ ...@@ -694,6 +715,67 @@ export const TablesConfig = [
{ fields: ['device_id', 'linkage_type'] }, { fields: ['device_id', 'linkage_type'] },
] ]
}, },
// 设备联动状态表(记录每台空调上次联动下发的目标状态,用于下发去重与人为修改检测)
{
tableNameCn: '设备联动状态表',
tableName: 'device_linkage_state',
schema: {
id: {
type: DataTypes.BIGINT,
allowNull: false,
primaryKey: true,
autoIncrement: true,
comment: '自增主键'
},
device_id: {
type: DataTypes.STRING(50),
allowNull: false,
unique: true,
comment: '设备编号,关联device.device_id'
},
target_power: {
type: DataTypes.STRING(10),
allowNull: true,
comment: '目标开关机:开/关'
},
target_set_temp: {
type: DataTypes.STRING(20),
allowNull: true,
comment: '目标设定温度(新风联动为空)'
},
target_fan_speed: {
type: DataTypes.STRING(20),
allowNull: true,
comment: '目标风速:高风/中风/低风'
},
target_work_mode: {
type: DataTypes.STRING(20),
allowNull: true,
comment: '目标运行模式:制冷/制热/送风'
},
update_time: {
type: DataTypes.DATE,
allowNull: true,
comment: '最近一次下发时间'
},
created_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '创建时间'
},
updated_at: {
type: DataTypes.DATE,
allowNull: false,
defaultValue: DataTypes.NOW,
comment: '修改时间'
}
},
association: [],
indexes: [
{ fields: ['device_id'] },
]
},
// 区域电费表(按区域存储电费数据,不再关联设备) // 区域电费表(按区域存储电费数据,不再关联设备)
{ {
tableNameCn: '区域电费表', tableNameCn: '区域电费表',
......
...@@ -333,7 +333,7 @@ async function getDevicesByRegion(req, res) { ...@@ -333,7 +333,7 @@ async function getDevicesByRegion(req, res) {
*/ */
async function editDevice(req, res) { async function editDevice(req, res) {
let reqConf = { deviceId: 'String', power: 'String', setTemp: 'Number', fanSpeed: 'String', deviceMode: 'String' }; let reqConf = { deviceId: 'String', power: 'String', setTemp: 'Number', fanSpeed: 'String', deviceMode: 'String' };
const NotMustHaveKeys = ["fanSpeed", "deviceMode"]; const NotMustHaveKeys = ["setTemp", "fanSpeed", "deviceMode"];
let { deviceId, power, setTemp, fanSpeed, deviceMode } = eccReqParamater(reqConf, req.body, NotMustHaveKeys); let { deviceId, power, setTemp, fanSpeed, deviceMode } = eccReqParamater(reqConf, req.body, NotMustHaveKeys);
if (!deviceId || !power) { if (!deviceId || !power) {
res.success({success: false, msg: "缺少必填参数:deviceId, power"}); res.success({success: false, msg: "缺少必填参数:deviceId, power"});
......
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