数据集成和定时任务

parent 0d91348d
......@@ -177,6 +177,37 @@ export async function getGatewayDeviceList(page: number = 1, limit: number = 10)
/**
* 内机列表分页查询
* @param params
* @returns
{
"code": "00000", //状态码 00000 为正常 其他为异常
"message": "success", //返回状态 success 为成功, 其他为失败
"data": { // 返回数据
"page": 1, //当前页码
"limit": 0, //每页条数
"total": 579, //总数
"rows": [{
"indoorUnitId": "98566729709518848", //内机 ID
"roomId": "98452624688414720", //房间 ID
"floorId": "98452624680026112", //楼层 ID
"buildingId": "34390184208629760", //楼栋 ID
"indoorUnitAddressFull": "11-1-1-1", //内机四段地址
"onOffLock": 1, //是否开关锁定 1 锁定 0 未锁定
"onOff": 0, //开关状态 1 开 0 关
"workModeLock": 0, //是否工作模式锁定 1 锁定 0 未锁定
"workMode": 2, //工作模式 1 制冷 2 制热 3 送风 4 除湿
"tempSetLock": 0, //是否温度锁定 1 锁定 0 未锁定
"tempSet": 16.0, // 设定温度
"tempSetLo": 16.0, // 锁定下限温度
"tempSetHi": 32.0, // 锁定下限温度
"fanSpeed": 4, // 风速 1 高风 2 中风 4 低风
"hasTimingTasks": 0, //是否有定时任务
"alarmCode": "LOST", //空调故障码
"roomTemp": 27 //室内温度(实际为空调回风温度,有一定的误差仅做参考)
"lockedSwitch": 0, // 锁定的开关:0 关 1 开
"lockedMode": 0, // 锁定模式 1 制冷 2 制热 3 送风 4 除湿 10 制热/送风 11 制冷/送风 12 制冷/除湿 13 制冷/除湿/送风 14 除湿/送风
}]
}
}
*/
export async function getIndoorUnitList(params: any): Promise<any> {
const path = '/openApi/indoorUnit/list';
......@@ -200,4 +231,151 @@ export async function controlIndoorUnit(params: any): Promise<any> {
console.log('控制内机响应:', result);
let success = result.code === '00000'? true : false;
return { success, data: result.message };
}
\ No newline at end of file
}
/**
* 建筑物树结构查询
* @param params
* @returns
{
"code": "00000", //状态码 00000 为正常,其他为异常
"message": "success", //状态信息 success 为成功,其他为异常
"data": [{
"buildingId": "97474765970866176", //建筑物 ID
"parentId": "0", //建筑物父 ID
"buildingName": "飞奕 1", // 建筑物名称
"buildingType": 1, //建筑物类型 1 楼栋 2 楼层 3 房间
"children": [ //子建筑物
{
"buildingId": "97474766339964928",
"parentId": "97474765970866176",
"buildingName": "1 层",
"buildingType": 2,
"children": [{
"buildingId": "97474766696480768",
"parentId": "97474766339964928",
"buildingName": "1-0",
"buildingType": 3,
"children": []
}]
}
]
}],
"timestamp": 1714290880301
}
*/
export async function getRegionTree(): Promise<any> {
const path = '/openApi/building/tree';
const body = { };
const result = await feiYiPost(path, body);
return result.data;
}
/**
* 电表分页查询
* @param params
* @returns
{
"code": "00000", //状态码 00000 为成功,其他为失败
"message": "success", //提示信息 success 为成功 其他为失败
"data": {
"page": 0, //当前页码
"limit": 0, //每页条数
"total": 6, //总条数
"rows": [{
"meterId": "110510431701041152", //电表 ID
"gatewayComId": , //电表网关设备通信 ID
"gatewayCode": , //电表网关设备编码
"protocolType": "DLT645-2007", //电表协议类型
"ammeterReadingAfterTransformationRatio": 6547.68, //电表变比后读数
"transformationRatio": 80.0, //电表变比
"meterComId": "210505015447" //电表地址
}, {
"gatewayComId": , //电表网关设备通信 ID
"gatewayCode": , //电表网关设备编码
"meterId": "110510346153885697",
"transformationRatio": 50.0,
"meterComId": "210505015560"
}]
},
"timestamp": 1713245734235
}
*/
export async function getElectricMaterList(params: any): Promise<any> {
const path = '/openApi/electricMeter/getAll';
const body = { ...params };
const result = await feiYiPost(path, body);
return result.data;
}
/**
* 抄表记录查询
* @param params
* @returns
{
"code": "00000", //状态码 00000 表示成功,其他为失败
"message": "success", //提示信息 success 为成功,其他为失败
"data": {
"page": 1, //当前页码
"limit": 0, //每页条数
"total": 6, //总条数
"rows": [{
"electricMeterStateId": "112111594590437376", //抄表记录 ID
"gatewayId": "97477557167063040", //主机设备 ID
"gatewayCode": "fa000001400001240231212000200026" //主机设备编码
"meterComId": "210505015595", //电表地址
"gatewayComId": 11, // 电表网关通信 ID
"transformationRatio": 100.0, //电表变比
"powerConsumptionAfterTransformationRatio": 0.08, //电表变比后用电量
"ammeterReadingAfterTransformationRatio": 19167.4, // 电表变比后读数
"ammeterReadingBeforeTransformationRatio": 191.67, //电表变比前读数
"energyLoss": 0.00, //损耗电量
"deviceTime": 1706371200000, //设备时间
}]
},
"timestamp": 1713145563759
}
*/
export async function getMaterStateList(params: any): Promise<any> {
const path = '/openApi/electricMeterState/list';
const body = { ...params };
const result = await feiYiPost(path, body);
return result.data;
}
/**
* 内机开关机记录查询
* @param params
* @returns
{
"code": "00000",
"message": "success",
"path": null,
"data": {
"page": 1,
"limit": 0,
"total": 278,
"rows": [{
"indoorUnitEventId": "140718238987321344", //内机事件 ID
"indoorUnitId": "97478680942739586", //内机 ID
"gatewayComId": 1, //主机通信 ID
"roomId": "97474774841819136", //内机所在房间 ID
"floorId": "97474774485303296", //内机所在楼层 ID
"buildingId": "97474765970866176", //内机所在楼栋 ID
"indoorUnitAddressFull": "1-8-128-16", //内机四段地址
"onOff": 0, //内机开关标志 0 关 1 开
"workMode": 4, //工作模式 1 制冷 2 制热 3 送风 4 除湿
"tempSet": 18.0, //内机温度设置
"fanSpeed": 2, //内机风速 风速 1 高风 2 中风 4 低风
"createTime": 1713173801018 //事件发生时间
}]
},
"timestamp": 1713173831195
}
*/
export async function getIndoorUnitStateList(params: any): Promise<any> {
const path = '/openApi/indoorUnit/event/switch';
const body = { ...params };
const result = await feiYiPost(path, body);
return result.data;
}
......@@ -5,6 +5,7 @@ import { selectOneDataByParam, selectDataListByParam } from "../data/findData";
import { BizError } from "../util/bizError";
import { controlIndoorUnit } from "./feiyiClient";
import { getRegionList } from "./region";
import { startSchedule, stopSchedule } from "../config/schedule";
/**
* 智能管控-运行分析
......@@ -200,6 +201,7 @@ export async function getRunAnalysis(regionGroup: string, regionType: string) {
{ count: 8, name: "安全事件", proportion: '18%' }];
// 5.2. 预警监控数据
resultAny.alertManagement = {
alertStatus: alertStatus,
alertWorkLevel: alertWorkLevel,
alertWorkType: alertWorkType,
alertWorkOrders: alertWorkOrders
......@@ -732,6 +734,21 @@ async function controlAcRunningApi(acDevices?: any, temperature?: number, worker
}
/**
* 数据集成 - 启动定时任务
*/
export async function startScheduleTask() {
await startSchedule();
return { success: true };
}
/**
* 数据集成 - 停止定时任务
*/
export async function stopScheduleTask() {
await stopSchedule();
return { success: true };
}
/**
* 空调中文到Key的映射
* 1 制冷 2 制热 3 送风 4 除湿
* 0 关-off 1 开-on
......
/**
* 定时任务调度器
* - 每分钟执行一次任务
* - 内置锁机制,防止任务重叠执行
* - 任务锁死时(超时未释放),会主动强制释放锁,确保后续任务能正常执行
*/
import { dataintegration } from "tencentcloud-sdk-nodejs";
import { region, device, deviceData } from "../biz/dataIntegration";
// 锁超时时间(毫秒),任务执行超过此时间视为锁死
const LOCK_TIMEOUT_MS = 55 * 1000; // 55秒,留5秒余量给下一次执行
// 定时器执行间隔(毫秒)
const TASK_INTERVAL_MS = 60 * 1000; // 1分钟
interface TaskLock {
locked: boolean;
lockTime: number; // 加锁时的时间戳
lockKey: string; // 锁标识,用于追踪
}
const taskLock: TaskLock = {
locked: false,
lockTime: 0,
lockKey: '',
};
/**
* 尝试获取任务锁
* @returns 是否成功获取锁
*/
function tryAcquireLock(): boolean {
if (taskLock.locked) {
const elapsed = Date.now() - taskLock.lockTime;
if (elapsed > LOCK_TIMEOUT_MS) {
// 锁已超时,强制释放
console.warn(`[定时任务] 检测到锁死,强制释放锁。已锁定 ${elapsed}ms,锁标识: ${taskLock.lockKey}`);
releaseLock();
return tryAcquireLock();
}
// 上一次任务还在执行中,跳过本次
console.log(`[定时任务] 上一次任务尚未完成,跳过本次执行。已锁定 ${elapsed}ms`);
return false;
}
taskLock.locked = true;
taskLock.lockTime = Date.now();
taskLock.lockKey = `${Date.now()}_${Math.random().toString(36).substring(2, 8)}`;
return true;
}
/**
* 释放任务锁
*/
function releaseLock(): void {
taskLock.locked = false;
taskLock.lockTime = 0;
taskLock.lockKey = '';
}
/**
* 获取当前锁状态(供外部查询)
*/
export function getLockStatus(): { locked: boolean; lockDuration: number; lockKey: string } {
return {
locked: taskLock.locked,
lockDuration: taskLock.locked ? Date.now() - taskLock.lockTime : 0,
lockKey: taskLock.lockKey,
};
}
/**
* 主动强制释放锁(供外部调用,用于紧急情况手动释放)
*/
export function forceReleaseLock(): void {
if (taskLock.locked) {
const elapsed = Date.now() - taskLock.lockTime;
console.warn(`[定时任务] 外部主动强制释放锁。已锁定 ${elapsed}ms,锁标识: ${taskLock.lockKey}`);
releaseLock();
}
}
/**
* 定时任务的具体业务逻辑
* 在这里编写需要定时执行的任务代码
*/
async function scheduledTask(): Promise<void> {
// 尝试获取锁,未获取到则跳过
if (!tryAcquireLock()) {
return;
}
try {
// ====== 在此处编写定时任务的具体逻辑 ======
console.log(`[定时任务] 开始执行 - ${new Date().toLocaleString()}`);
// TODO: 替换为实际的业务逻辑
// 例如:数据备份、缓存清理、定时同步等
await region();
await device();
await deviceData();
console.log(`[定时任务] 执行完成 - ${new Date().toLocaleString()}`);
// =========================================
} catch (err) {
console.error('[定时任务] 执行异常:', err);
} finally {
// 无论任务成功或失败,都要释放锁
releaseLock();
}
}
// 定时器句柄
let timerHandle: NodeJS.Timeout | null = null;
/**
* 启动定时任务
* 在项目启动时调用
*/
export function startSchedule(): void {
if (timerHandle) {
console.warn('[定时任务] 定时器已在运行中,无需重复启动');
return;
}
console.log(`[定时任务] 定时器已启动,间隔 ${TASK_INTERVAL_MS / 1000} 秒`);
// 使用 setInterval 实现每分钟执行一次
timerHandle = setInterval(() => {
scheduledTask();
}, TASK_INTERVAL_MS);
}
/**
* 停止定时任务
*/
export function stopSchedule(): void {
if (timerHandle) {
clearInterval(timerHandle);
timerHandle = null;
console.log('[定时任务] 定时器已停止');
}
}
......@@ -2,6 +2,7 @@ import { initConfig, systemConfig} from "./config/serverConfig";
import * as mysqlDB from "./db/mysqlInit";
import { initMysqlModel } from "./model/sqlModelBind";
import { httpServer } from "./net/http_server";
import { startSchedule } from "./config/schedule";
async function lanuch() {
......@@ -12,6 +13,8 @@ async function lanuch() {
await initMysqlModel();
/**创建http服务 */
httpServer.createServer(systemConfig.port);
/**启动定时任务 */
startSchedule();
console.log('This indicates that the server is started successfully.');
......
......@@ -33,6 +33,11 @@ export function setRouter(httpServer) {
/** 空调开关 */
httpServer.post('/api/qdm/run/monitor/acRun', asyncHandler(controlAcRunning));
/** 启动数据集成 */
httpServer.post('/api/qdm/run/start/schedule', asyncHandler(startSchedule));
/** 停止数据集成 */
httpServer.post('/api/qdm/run/stop/schedule', asyncHandler(stopSchedule));
}
/**
......@@ -137,6 +142,21 @@ async function controlAcRunning(req, res) {
res.success(result);
}
/**
* 启动定时任务
*/
async function startSchedule(req, res) {
const result = await runningBiz.startScheduleTask();
res.success(result);
}
/**
* 停止定时任务
*/
async function stopSchedule(req, res) {
const result = await runningBiz.stopScheduleTask();
res.success(result);
}
......
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