ubuslog = require "ubuslog" require "log" require "sys" require "utils" require "patch" require "pack" require "bit" local siganl = require 'posix.signal' local syswait = require 'posix.sys.wait' local unistd = require 'posix.unistd' local lpack = require("lua_pack") local internal_api = require("internal_api") APP_DIR = "/app/config/ems/" GUARD_CFG_FILE = APP_DIR .. "guard_protect.json" local LOG_TAG = "guard_protect" --local LOG_LEVEL = log.LOGLEVEL_DEBUG local INDEX = 1 local active_sn -- 根据不同项目需求可做修改 ------------------------------------------------------------------修改区域开始------------------------------------------------------------------ local V3_PRO = 0 -- 是否是V3平台, 1 是 0:不是 local OFFLINE_TIME = 20 -- 离线判断时间, 单位秒 local AIRCOND_ENABLE = 1 -- 标准空调逻辑开关 1 开启功能 0 关闭功能 local COLLMACH_ENABLE = 1 -- 标准液冷机逻辑开关 1 开启功能 0 关闭功能 local DI_SOURCE = 0 -- DI数据源 0 内部mqtt broker 1 读gpio文件 local RUN_LIGHT = 0 -- 运行灯逻辑 0 标准逻辑,与故障灯互斥, 1 运行灯受充放电控制,充放电亮,静置灭 local POWER_LIMIT = 2 -- 漏电区间(自带正负 -2~2认为静置) 在漏电流影响下,根据有功功率判断系统运行状态 --静置 停止充放电 local COOL_CONTINUE = 0 -- 因液冷机性能参数不一 0 持续发送指令 1 变化发送指令 -- 指示灯和脱扣动作DO,可在此处修改 -- 1.是否启用 2.服务 3.TAG 4.描述 local light_map = { run_light = {true, "DO1", "DO_1", "运行灯"}, warn_light = {true, "DO2", "DO_2", "告警灯"}, fault_light = {true, "DO3", "DO_3", "故障灯"}, tuokou = {true, "DO6", "DO_6", "脱扣" }, } -- 订阅的设备,可在此处添加和修改,以单柜三组PCS为例,注意grp_idx -- 1.sn_suffix 设备SN后缀; 2.gw 设备SN后缀; 3.grp_idx 所属组;4.ident_list 过滤服务(关注的服务);5.offline_enable 是否开启检测设备离线; local g_sub_nodes = { -- 不属于PCS分组的设备可放置此区域 {sn_suffix = "_DI", gw = "_DI", grp_idx = 0, ident_list = {"DIRead"}, offline_enable = false}, {sn_suffix = "_gridmeter", gw = "_gridmeter", grp_idx = 0, ident_list = {"sanxianggongluxinxi"}, offline_enable = true}, -- 电网电表离线上报二级故障,运行灯灭,故障灯亮 {sn_suffix = "_coolmachine", gw = "_coolmachine", grp_idx = 0, ident_list = {"readmode", "readon_off"}, offline_enable = false}, -- PCS一组区域 PCS Cluster rack {sn_suffix = "_Rack1_1", gw = "_Rack1_1", grp_idx = INDEX, ident_list = {"gaojingxinxi", "rackxinxi"}, offline_enable = true}, {sn_suffix = "_Cluster_1", gw = "_Cluster_1", grp_idx = INDEX, ident_list = {"Read1029_102F", "Read0x1017_1028", "Read1001_100B","Read100C_1016"}, offline_enable = true}, {sn_suffix = "_PCS1", gw = "_PCS1", grp_idx = INDEX, ident_list = {"Read32_40Data", "Read101_125Data"}, offline_enable = true}, -- PCS二组区域 --{sn_suffix = "_Rack2_1", gw = "_Rack2_1", grp_idx = INDEX+1, ident_list = {"gaojingxinxi", "rackxinxi"}, offline_enable = true}, --{sn_suffix = "_Cluster_2", gw = "_Cluster_2", grp_idx = INDEX+1, ident_list = {"Read1029_102F", "Read0x1017_1028", "Read1001_100B","Read100C_1016"}, offline_enable = true}, --{sn_suffix = "_PCS2", gw = "_PCS2", grp_idx = INDEX+1, ident_list = {"Read32_40Data", "Read101_125Data"}, offline_enable = true}, -- PCS三组区域 --{sn_suffix = "_Rack3_1", gw = "_Rack3_1", grp_idx = INDEX+2, ident_list = {"gaojingxinxi", "rackxinxi"}, offline_enable = true}, --{sn_suffix = "_Cluster_3", gw = "_Cluster_3", grp_idx = INDEX+2, ident_list = {"Read1029_102F", "Read0x1017_1028", "Read1001_100B","Read100C_1016"}, offline_enable = true}, --{sn_suffix = "_PCS3", gw = "_PCS3", grp_idx = INDEX+2, ident_list = {"Read32_40Data", "Read101_125Data"}, offline_enable = true}, } -- 1.是否启用 2.level告警等级 3.TAG名称 4.告警描述 local common_warn_map = { {true, 3, "DI1", "急停"}, {true, 3, "DI2", "浪涌"}, {true, 3, "DI3", "水浸"}, {true, 3, "DI4", "消防"}, {true, 3, "DI5", "烟感"}, {true, 3, "DI6", "可燃气体"}, {true, 0, "DI7", "门禁"}, } -- 1.是否启用 2.TAG名称 3.告警描述 local group_rack_warn_map = { {true, "TAG_760A", "TAG_9C50", "总电压过压一级报警"}, -- 一级告警,亮告警灯 (根据bms返回的可充可放电流,由energy_assign实现) {true, "TAG_760B", "TAG_9C51", "总电压欠压一级报警"}, {true, "TAG_760C", "TAG_9C52", "单体过压一级报警"}, {true, "TAG_760D", "TAG_9C53", "单体欠压一级报警"}, {true, "TAG_7610", "TAG_9C56", "放电电池过温一级报警"}, {true, "TAG_7611", "TAG_9C57", "放电电池欠温一级报警"}, {true, "TAG_7612", "TAG_9C58", "充电电池过温一级报警"}, {true, "TAG_7613", "TAG_9C59", "充电电池欠温一级报警"}, {true, "TAG_7617", "TAG_9C5D", "总电压过压二级报警"}, -- 二级告警,亮告警灯 (功率写0,关机 由energy_assign实现) {true, "TAG_7618", "TAG_9C5E", "总电压欠压二级报警"}, {true, "TAG_7619", "TAG_9C5F", "单体过压二级报警"}, {true, "TAG_761A", "TAG_9C60", "单体欠压二级报警"}, {true, "TAG_761D", "TAG_9C63", "放电电池过温二级报警"}, {true, "TAG_761E", "TAG_9C64", "放电电池欠温二级报警"}, {true, "TAG_761F", "TAG_9C65", "充电电池过温二级报警"}, {true, "TAG_7620", "TAG_9C66", "充电电池欠温二级报警"}, } ---------------------------------------------------------------------- -- 1.是否启用 2.level告警等级 3.TAG名称 4.告警描述 local group_warn3_map = { {true, 3, "TAG_7624", "TAG_9C6A", "总电压过压三级报警"}, -- 组内三级告警 亮故障灯 (功率写0,关机 由energy_assign实现),脱扣(是否脱扣可由站控下发配置) {true, 3, "TAG_7625", "TAG_9C6B", "总电压过低三级报警"}, {true, 3, "TAG_7626", "TAG_9C6C", "单体过压三级报警"}, {true, 3, "TAG_7627", "TAG_9C6D", "单体欠压三级报警"}, {true, 3, "TAG_762A", "TAG_9C70", "放电电池过温三级报警"}, {true, 3, "TAG_762B", "TAG_9C71", "放电电池欠温三级报警"}, {true, 3, "TAG_762C", "TAG_9C72", "充电电池过温三级报警"}, {true, 3, "TAG_762D", "TAG_9C73", "充电电池欠温三级报警"}, } -- 组内三级告警 是否脱扣 0 不脱 1脱扣 local gurad_config = { warn_trip_enable = 0, -- 默认三级告警不脱扣,此功能站控可配置 } --------------------------------------------------------------------- -- 液冷机参数 local cooling_config = { -- 1.工作状态(充放电) start_cool:开始制冷温度(最高电芯温度) stop_cool:停止制冷温度(最高电芯温度) -- start_hot_max:开始制热温度(最高电芯温度)start_hot_min:开始制热温度(最低电芯温度) 两个都满足开始制热 -- stop_hot_max:停止制热温度(最高电芯温度) stop_hot_min :停止制热温度(最低电芯温度) 两个都满足停止制热 work = {start_cool = 27, stop_cool = 25, start_hot_max = 15, start_hot_min = 13, stop_hot_max = 18, stop_hot_min = 15}, -- 2.空闲状态 start_cool:开始制冷温度(最高电芯温度) stop_cool:停止制冷温度(最高电芯温度) standby = {start_cool = 29, stop_cool = 27}, } --------------------------------------------------------------------修改区域结束---------------------------------------------------------------- local nodes_info -- SN:object local g_nodes -- 全局node_cfg local total_nodes = {} local g_common = {data={},ctrl={},status={},protect={},fault_type={},fault={},warn={}} -- 存放 DI 等公共数据 local g_grp = {} -- 存放PCS Cluster rack 分组数据 local g_total = {data={},ctrl={},status={},protect={},fault_type={},fault={},warn={}} local aircond_action = 0 local g_changed = 0 local aircond_set_timeout_before = 60 --设置以分钟为单位,如1小时请设置60 表示提前60分钟开始 local aircond_set_timeout_after = 60 --设置以分钟为单位,如1小时请设置60 表示延后60分钟结束 local ENABLE_FLAG = 1 local ALARM_TRIGGER_FLAG = 2 local PRO_LEVEL = 3 local TAG_NAME = 4 local TAG_NAME_CLUSTER = 4 local TAG_NAME_RACK = 5 local ALARM_DES_ = 6 local ALARM_DES = 5 local FILE_DES = 6 local SERIAL = 7 local RACK_ENABLE_FLAG = 1 local CLUSTER_TAG_NAME = 2 local RACK_TAG_NAME = 3 local RACK_ALARM_DES = 4 local LIGNT_ENABLE_FLAG = 1 local LIGNT_SER_NAME = 2 local LIGNT_TAG_NAME = 3 local LIGNT_DES = 4 local function createDir() local file = io.open(APP_DIR, "rb") if file then file:close() else ubuslog.log(ubuslog.LOG_DEBUG, "create dir") os.execute("mkdir -p " .. APP_DIR) end end local function file_read(fileName) local data local file = io.open(fileName, "r") if file == nil then -- 若文件不存在则创建文件 os.execute("touch " .. fileName) return nil else --log_print.info("fuck_md:") file:seek("set", 0) data = file:read("*a") file:close() return data end end local function file_write(fileName, data) local file = io.open(fileName, "w") file:write(data) file:flush() -- 向文件写入缓冲中的所有数据 file:close() end function init_sub_nodes_info(warn_map, sub_nodes) assert(warn_map) assert(sub_nodes) for i, v in ipairs(warn_map) do if v then table.insert(v, ALARM_TRIGGER_FLAG, false) -- 插入告警是否触发flag if string.find(v[TAG_NAME], "DI1") then table.insert(v, SERIAL, 81) -- 插入GPIO序号 elseif string.find(v[TAG_NAME], "DI2") then table.insert(v, SERIAL, 79) elseif string.find(v[TAG_NAME], "DI3") then table.insert(v, SERIAL, 77) elseif string.find(v[TAG_NAME], "DI4") then table.insert(v, SERIAL, 75) elseif string.find(v[TAG_NAME], "DI5") then table.insert(v, SERIAL, 73) elseif string.find(v[TAG_NAME], "DI6") then table.insert(v, SERIAL, 71) elseif string.find(v[TAG_NAME], "DI7") then table.insert(v, SERIAL, 69) end end end for i, v in ipairs(sub_nodes) do if v.sn_suffix and v.gw then v.sn_suffix = string.format("%s%s", active_sn, v.sn_suffix) v.gw = string.format("%s%s", active_sn, v.gw) table.insert(total_nodes, v) end end end function update_nodes_info(total_node) assert(total_node) local tmp_nodes_info = {} for i, v in ipairs(total_node) do if v.gw then local dev_sn = v.gw tmp_nodes_info[dev_sn] = v tmp_nodes_info[dev_sn].recv_time = nil tmp_nodes_info[dev_sn].offline = false end end return tmp_nodes_info end local function init_grp_structure(grp_obj, sub_nodes) assert(grp_obj) assert(sub_nodes) local size = 0 for _, v in ipairs(sub_nodes) do if v.grp_idx then if v.grp_idx > size then size = v.grp_idx end end end if size == 0 then -- 单个网关最低支持1组PCS size = 1 end ubuslog.log(ubuslog.LOG_DEBUG, "pcs group cont::::", size) for grp_idx = 1, size do local data_space if not grp_obj[grp_idx] then -- 若不存在,创建分组table grp_obj[grp_idx] = {} end data_space = grp_obj[grp_idx] if not data_space.protect then data_space.protect = {} end if not data_space.data then data_space.data = {} end if not data_space.ctrl then data_space.ctrl = {} end if not data_space.status then data_space.status = {} end if not data_space.fault_type then data_space.fault_type = {} end if not data_space.fault then data_space.fault = {} end if not data_space.warn then data_space.warn = {} end -- 三级告警 if not data_space.group_warn3_map then data_space.group_warn3_map = {} end for i, v in ipairs(group_warn3_map) do if v then table.insert(v, ALARM_TRIGGER_FLAG, false) -- 插入告警是否触发flag table.insert(data_space.group_warn3_map, v) end end end end local function fault_report_station(warn_map, grp, index, sig) local obj = {} if sig == 0 then obj.info = "故障恢复: " .. warn_map[index][ALARM_DES] ubuslog.log(ubuslog.LOG_DEBUG, "report_info:Fault recovery") elseif sig == 1 then obj.info = "触发故障: " .. warn_map[index][ALARM_DES] ubuslog.log(ubuslog.LOG_DEBUG, "report_info:Fault trigger") elseif sig == 2 then obj.info = "PCS组" .. "[" .. grp .. "]" .. "故障恢复: " .. warn_map[index][ALARM_DES_] ubuslog.log(ubuslog.LOG_DEBUG, "report_info:Fault recovery") elseif sig == 3 then obj.info = "PCS组" .. "[" .. grp .. "]" .. "触发故障: " .. warn_map[index][ALARM_DES_] ubuslog.log(ubuslog.LOG_DEBUG, "report_info:Fault trigger") elseif sig == 4 then obj.info = "断路器脱扣: " ubuslog.log(ubuslog.LOG_DEBUG, "report_info:trip!!!") end obj.result = 0 internal_api.service_response(active_sn, active_sn .. "_EMSCTRL", "VINTF_TCP", "report_info", obj, 0) ubuslog.log(ubuslog.LOG_DEBUG, "report_info %s", cjson.encode(obj)) end local function offline_report_station(infostr) local obj = {} obj.info = infostr obj.result = 0 internal_api.service_response(active_sn, active_sn .. "_EMSCTRL", "VINTF_TCP", "report_info", obj, 0) ubuslog.log(ubuslog.LOG_DEBUG, "report_info", cjson.encode(obj)) end ----------------------------------------- local function set_fire_alarm(dev_sn, do_sn, ident, tag, value) internal_api.call_dev_service(dev_sn, do_sn, "NULL", ident, { [tag] = value }) sys.wait(500) internal_api.call_dev_service(dev_sn, do_sn, "NULL", ident, { [tag] = 0 }) end -- 脱扣 local function Trigger() local common_fault_level = 0 local group_fault_level = 0 local tuokou = light_map.tuokou local do_sn = string.format("%s%s", active_sn, "_DI") ubuslog.log(ubuslog.LOG_DEBUG, "start Trigger judgment... ") -- 取分组最大故障等级 for grp_idx, grp_obj in ipairs(g_grp) do if grp_obj and grp_obj.fault and grp_obj.fault.level then ubuslog.log(ubuslog.LOG_DEBUG, "group ", grp_idx, "fault_level: ", grp_obj.fault.level) group_fault_level = grp_obj.fault.level > group_fault_level and grp_obj.fault.level or group_fault_level end end ubuslog.log(ubuslog.LOG_DEBUG, "Max fault level of a group: ", group_fault_level) if g_common.fault.level then -- DI等公共数据故障等级 common_fault_level = g_common.fault.level end ubuslog.log(ubuslog.LOG_DEBUG, "Common fault level: ", common_fault_level) if common_fault_level == 3 or (gurad_config.warn_trip_enable == 1 and group_fault_level == 3) then -- 默认:三级告警脱扣开关关闭 if tuokou[LIGNT_ENABLE_FLAG] == true then ubuslog.log(ubuslog.LOG_NOTICE, "Real Trigger !!! ") set_fire_alarm(active_sn, do_sn, tuokou[LIGNT_SER_NAME], tuokou[LIGNT_TAG_NAME], 1) fault_report_station(nil, nil, 1, 4) end end end ----------------------------------------- local function DO_ctrl(dev_sn, do_sn, ident, tag, Onoff) internal_api.call_dev_service(dev_sn, do_sn, "NULL", ident, { [tag] = Onoff }) end -- 取保护等级和故障等级的最大值,若没及时收到保护等级可优先使用故障等级执行保护动作 1级保护对应1级故障 2级保护对应2级故障 3级保护对应3级故障 local function protect_level_get(total, grp) local protect_level = 0 local fault_level = 0 -- 取分组最大保护等级 for grp_idx, grp_obj in ipairs(grp) do if grp_obj and grp_obj.protect and grp_obj.protect.level then ubuslog.log(ubuslog.LOG_DEBUG, "group ", grp_idx, "protect_level: ", grp_obj.protect.level) protect_level = grp_obj.protect.level > protect_level and grp_obj.protect.level or protect_level end end ubuslog.log(ubuslog.LOG_DEBUG, "Max protection level of a group: ", protect_level) if total.protect.level then protect_level = total.protect.level > protect_level and total.protect.level or protect_level -- 此处可忽略,总保护等级始终是0,不使用 end ubuslog.log(ubuslog.LOG_DEBUG, "Final max protection level: ", protect_level) -- 取分组最大故障等级以及DI等公共数据故障等级的最大值 for grp_idx, grp_obj in ipairs(grp) do if grp_obj and grp_obj.fault and grp_obj.fault.level then ubuslog.log(ubuslog.LOG_DEBUG, "group ", grp_idx, "fault_level: ", grp_obj.fault.level) fault_level = grp_obj.fault.level > fault_level and grp_obj.fault.level or fault_level end end ubuslog.log(ubuslog.LOG_DEBUG, "Max fault level of a group: ", fault_level) if g_common.fault.level then fault_level = g_common.fault.level > fault_level and g_common.fault.level or fault_level end ubuslog.log(ubuslog.LOG_DEBUG, "Final max fault level: ", fault_level) local level = protect_level >= fault_level and protect_level or fault_level ubuslog.log(ubuslog.LOG_DEBUG, "level :::: level ", level) return level end local function grp_protect_level_get(protect_level, fault_level, max_min) local level = 0 if max_min == 1 then level = protect_level > fault_level and protect_level or fault_level else level = protect_level > fault_level and fault_level or protect_level end return level end local function aircond_set_report_ems(data_befor, data_after) --before传给after after传给before ,以当前时间为准,ems的after代表提前开启, ems的before代表提前结束 local obj = { aircond_set_timeout_before = data_befor, aircond_set_timeout_after = data_after } for i, v in ipairs(g_nodes) do internal_api.pp2north(active_sn, v.sn, "NULL", "aircond_set_timeout_by_min", obj, 0) end ubuslog.log(ubuslog.LOG_DEBUG, "aircond_set_timeout_by_min", cjson.encode(obj)) end local function linkage_aircond(Onoff) local aircond_sn = string.format("%s_aircond", active_sn) -- 空调 if Onoff == 0 then --关机 internal_api.call_dev_service(active_sn, aircond_sn, "NULL", "setoff", { }, 0) end if Onoff == 1 then --开机 internal_api.call_dev_service(active_sn, aircond_sn, "NULL", "seton", { }, 0) end end local function linkage_Pulse_aircond() while true do local ret, grp_idx = sys.waitUntil("AIRCOND_ACTION", 5000) ubuslog.log(ubuslog.LOG_NOTICE, "aircond_action: ", aircond_action, "change: ", g_changed) if g_changed == 1 and aircond_action == 1 then g_changed = 0 linkage_aircond(1) --开机 elseif g_changed == 1 and aircond_action == 0 then g_changed = 0 linkage_aircond(0) --关机 end end end local function linkage(order) local coolmachine_sn = string.format("%s_coolmachine", active_sn) -- 液冷机 local data_space = g_common if order == 2 then -- 液冷机制冷 1:制冷模式;2:制热模式;3:自循环模式 if COOL_CONTINUE == 0 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "seton", { TAG_EABC = 1 }, 0) sys.wait(1000) internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "modectrl", { TAG_EABD = 1 }, 0) --1:制冷 else if data_space.data.TAG_EABC and data_space.data.TAG_EABD then if data_space.data.TAG_EABC ~= 1 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "seton", { TAG_EABC = 1 }, 0) end if data_space.data.TAG_EABD ~= 1 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "modectrl", { TAG_EABD = 1 }, 0) end end end elseif order == 3 then -- 液冷机制热 if COOL_CONTINUE == 0 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "seton", { TAG_EABC = 1 }, 0) sys.wait(1000) internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "modectrl", { TAG_EABD = 2 }, 0) --2:制热模式 else if data_space.data.TAG_EABC and data_space.data.TAG_EABD then if data_space.data.TAG_EABC ~= 1 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "seton", { TAG_EABC = 1 }, 0) end if data_space.data.TAG_EABD ~= 2 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "modectrl", { TAG_EABD = 2 }, 0) end end end elseif order == 4 then -- 液冷机自循环模式 if COOL_CONTINUE == 0 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "seton", { TAG_EABC = 1 }, 0) sys.wait(1000) internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "modectrl", { TAG_EABD = 3 }, 0) --3:自循环模式 else if data_space.data.TAG_EABC and data_space.data.TAG_EABD then if data_space.data.TAG_EABC ~= 1 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "seton", { TAG_EABC = 1 }, 0) end if data_space.data.TAG_EABD ~= 3 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "modectrl", { TAG_EABD = 3 }, 0) end end end elseif order == 5 then -- 液冷机关机模式 if COOL_CONTINUE == 0 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "setoff", { TAG_EABC = 0 }, 0) else if data_space.data.TAG_EABC then if data_space.data.TAG_EABC ~= 0 then internal_api.call_dev_service(active_sn, coolmachine_sn, "NULL", "setoff", { TAG_EABC = 0 }, 0) end end end end end local function linkage_cooling_machine() local coolmachine_sn = string.format("%s_coolmachine", active_sn) local data_space = g_grp[1] -- 最高电芯温度、最低电芯温度 默认从第一组PCS获取 while true do local currTime = os.time() local ret, grp_idx = sys.waitUntil("REAL_DATA_UPDATE_WHAT", 10*1000) ubuslog.log(ubuslog.LOG_DEBUG, "maxtem TAG_75FC: ", data_space.data.TAG_75FC) -- 最高电芯温度 ubuslog.log(ubuslog.LOG_DEBUG, "mintem TAG_7600: ", data_space.data.TAG_7600) -- 最低电芯温度 ubuslog.log(ubuslog.LOG_DEBUG, "PCS run status TAG_4F2F: ", data_space.data.TAG_4F2F) -- PCS运行状态 ubuslog.log(ubuslog.LOG_DEBUG, "PCS run status TAG_4E88: ", data_space.data.TAG_4E88) -- PCS有功功率 if data_space.data.TAG_4E88 and data_space.data.TAG_75FC and data_space.data.TAG_7600 then if data_space.data.TAG_4E88 < (0 - POWER_LIMIT) or data_space.data.TAG_4E88 > POWER_LIMIT then -- 根据有功功率判断系统运行状态 --静置 停止充放电 if data_space.data.TAG_75FC >= cooling_config.work.start_cool then linkage(2) --液冷机制冷 ubuslog.log(ubuslog.LOG_NOTICE, " pcs run zhileng") elseif data_space.data.TAG_75FC > cooling_config.work.stop_cool then -- what to do ? keep elseif data_space.data.TAG_75FC > cooling_config.work.stop_hot_max and data_space.data.TAG_75FC <= cooling_config.work.stop_cool then linkage(5) --关机 ubuslog.log(ubuslog.LOG_NOTICE, "pcs run guanjiyeleng") elseif data_space.data.TAG_75FC <= cooling_config.work.start_hot_max and data_space.data.TAG_7600 <= cooling_config.work.start_hot_min then linkage(3) --液冷机加热 ubuslog.log(ubuslog.LOG_NOTICE, "pcs run zhire") end else if data_space.data.TAG_75FC >= cooling_config.standby.start_cool then linkage(2) --液冷机制冷 ubuslog.log(ubuslog.LOG_NOTICE, "pcs stop zhileng") elseif data_space.data.TAG_75FC >= cooling_config.standby.stop_cool then -- what to do ? keep elseif data_space.data.TAG_75FC < cooling_config.standby.stop_cool then linkage(5) --关机 ubuslog.log(ubuslog.LOG_NOTICE, "pcs stop guanjiyeleng") end end end end end ------------------------------------------------------------------------------------------------- local function common_fault_calculate() while true do local ret, grp_idx = sys.waitUntil("REAL_DATA_UPDATE", 2000) if grp_idx and grp_idx == 0 then local level = 0 local now = os.time() local data_space = g_common if data_space then if data_space.fault.level == nil then -- 初始化故障等级 data_space.fault.level = 0 end if data_space.protect.level == nil then -- 初始化保护等级 data_space.protect.level = 0 end -- 公共区域设备离线 2级故障(影响全部) for sn, v in pairs(nodes_info) do if not v.recv_time then v.recv_time = os.time() end if v.grp_idx == 0 then if os.difftime(now, v.recv_time) >= OFFLINE_TIME then if v.offline_enable and v.offline_enable == true and v.offline == false then offline_report_station("离线设备: total lixian:" .. v.sn_suffix) v.offline = true end ubuslog.log(ubuslog.LOG_NOTICE, "设备离线: ", v.sn_suffix) else if v.offline_enable and v.offline_enable == true and v.offline == true then offline_report_station("恢复设备: total huifu:" .. v.sn_suffix) v.offline = false end end end end for sn, v in pairs(nodes_info) do if v.offline_enable and v.offline and v.offline_enable == true and v.offline == true and v.grp_idx == 0 then level = 2 break end end local tmp = data_space.data for i = 1, #common_warn_map do if common_warn_map[i][ENABLE_FLAG] == true then local val = tmp[common_warn_map[i][TAG_NAME]] if val then if val == 1 then level = common_warn_map[i][PRO_LEVEL] > level and common_warn_map[i][PRO_LEVEL] or level if common_warn_map[i][ALARM_TRIGGER_FLAG] == false then fault_report_station(common_warn_map, 0, i, 1) common_warn_map[i][ALARM_TRIGGER_FLAG] = true --alarm is triggered end else if common_warn_map[i][ALARM_TRIGGER_FLAG] == true then fault_report_station(common_warn_map, 0, i, 0) common_warn_map[i][ALARM_TRIGGER_FLAG] = false end end end end end if data_space.fault.level ~= level then data_space.fault.level = level sys.publish("FAULT_LEVEL_CHANGED", 0) end end end end end local function total_warn_exec() local do_sn = string.format("%s%s", active_sn, "_DI") local warn_light = light_map.warn_light while true do local warn_flag = 0 local ret, grp_idx = sys.waitUntil("WARN_FLAG_CHANGED", 2000) for i, v in ipairs(g_grp) do assert(v.warn) if v.warn.flag and v.warn.flag == 1 then warn_flag = 1 break end end -- 告警灯 if warn_flag == 1 then if warn_light[LIGNT_ENABLE_FLAG] == true then DO_ctrl(active_sn, do_sn, warn_light[LIGNT_SER_NAME], warn_light[LIGNT_TAG_NAME], 1) ubuslog.log(ubuslog.LOG_DEBUG, "Alarm light on ") end elseif warn_flag == 0 then if warn_light[LIGNT_ENABLE_FLAG] == true then DO_ctrl(active_sn, do_sn, warn_light[LIGNT_SER_NAME], warn_light[LIGNT_TAG_NAME], 0) ubuslog.log(ubuslog.LOG_DEBUG, "Alarm light off") end end end end local function total_protect_process(idx) local last_protect_level = -1 local run_indicator local fault_indicator local last_fire_trip local do_sn = string.format("%s%s", active_sn, "_DI") local run_light = light_map.run_light local fault_light = light_map.fault_light local data_space = g_grp[1] -- 默认从第一组PCS获取 while true do local ret, grp_idx = sys.waitUntil("PROTECT_LEVEL_CHANGED", 5000) local protect_level = protect_level_get(g_total, g_grp) if last_protect_level ~= protect_level then last_protect_level = protect_level last_fire_trip = 1 else last_fire_trip = 0 end if protect_level > 0 then -- 保护等级 ubuslog.log(ubuslog.LOG_NOTICE, "total System stop, level: ", protect_level) fault_indicator = 1 run_indicator = 0 else -- 没有保护,意味着没触发故障 ubuslog.log(ubuslog.LOG_NOTICE, "total System running") fault_indicator = 0 run_indicator = 1 end -- 运行灯受充放电控制,充放电亮,静置灭 if RUN_LIGHT == 1 then if data_space.data.TAG_4E88 then if data_space.data.TAG_4E88 < (0 - POWER_LIMIT) or data_space.data.TAG_4E88 > POWER_LIMIT then if run_light[LIGNT_ENABLE_FLAG] == true then DO_ctrl(active_sn, do_sn, run_light[LIGNT_SER_NAME], run_light[LIGNT_TAG_NAME], 1) ubuslog.log(ubuslog.LOG_DEBUG, "Run light on ") end else if run_light[LIGNT_ENABLE_FLAG] == true then DO_ctrl(active_sn, do_sn, run_light[LIGNT_SER_NAME], run_light[LIGNT_TAG_NAME], 0) ubuslog.log(ubuslog.LOG_DEBUG, "Run light off ") end end end elseif RUN_LIGHT == 0 then -- 标准逻辑,与故障灯互斥 -- 运行灯 if run_indicator == 1 then if run_light[LIGNT_ENABLE_FLAG] == true then DO_ctrl(active_sn, do_sn, run_light[LIGNT_SER_NAME], run_light[LIGNT_TAG_NAME], 1) ubuslog.log(ubuslog.LOG_DEBUG, "Run light on ") end else if run_light[LIGNT_ENABLE_FLAG] == true then DO_ctrl(active_sn, do_sn, run_light[LIGNT_SER_NAME], run_light[LIGNT_TAG_NAME], 0) ubuslog.log(ubuslog.LOG_DEBUG, "Run light off ") end end end -- 故障灯 if fault_indicator == 1 then if fault_light[LIGNT_ENABLE_FLAG] == true then DO_ctrl(active_sn, do_sn, fault_light[LIGNT_SER_NAME], fault_light[LIGNT_TAG_NAME], 1) ubuslog.log(ubuslog.LOG_DEBUG, "Fault light on ") end else if fault_light[LIGNT_ENABLE_FLAG] == true then DO_ctrl(active_sn, do_sn, fault_light[LIGNT_SER_NAME], fault_light[LIGNT_TAG_NAME], 0) ubuslog.log(ubuslog.LOG_DEBUG, "Fault light off ") end end if last_fire_trip == 1 then if protect_level == 3 then -- 脱扣 Trigger() end end end end local function total_fault_level_report() local tmp_level = 0 local group_level = 0 while true do sys.waitUntil("FAULT_LEVEL_CHANGED", 3000) local obj = { fault_level = g_total.fault.level and g_total.fault.level or 0, -- 此参数始终为0,暂不使用 grps_fault_level = {} } ubuslog.log(ubuslog.LOG_DEBUG, "fault_level_report", "g_common fault_level: ", g_common.fault.level) for grp_idx, grp_obj in ipairs(g_grp) do if (grp_obj and grp_obj.fault and grp_obj.fault.level) and g_common.fault.level then table.insert(obj.grps_fault_level, { level = g_common.fault.level >= grp_obj.fault.level and g_common.fault.level or grp_obj.fault.level }) end end for i, v in ipairs(g_nodes) do internal_api.pp2north(active_sn, v.sn, "NULL", "fault_level_report", obj, 0) end ubuslog.log(ubuslog.LOG_DEBUG, "fault_level_report:: ", cjson.encode(obj)) end end ------------------------------------------------------------------------------------------------- local function grp_warn_calculate(idx) local do_sn = string.format("%s_DI", active_sn) while true do local ret, grp_idx = sys.waitUntil("REAL_DATA_UPDATE", 2000) if grp_idx and grp_idx == idx then local data_space = g_grp[idx] if data_space then if data_space.warn.flag == nil then data_space.warn.flag = 0 end local flag = 0 local tmp = data_space.data for i = 1, #group_rack_warn_map do if group_rack_warn_map[i][RACK_ENABLE_FLAG] == true then local cluster_val = tmp[group_rack_warn_map[i][CLUSTER_TAG_NAME]] local rack_val = tmp[group_rack_warn_map[i][RACK_TAG_NAME]] if (cluster_val and cluster_val > 0) or (rack_val and rack_val > 0) then flag = 1 ubuslog.log(ubuslog.LOG_DEBUG, "group:", idx, "warn:", group_rack_warn_map[i][CLUSTER_TAG_NAME], ":", group_rack_warn_map[i][RACK_TAG_NAME], ":", group_rack_warn_map[i][RACK_ALARM_DES]) end end end if data_space.warn.flag ~= flag then data_space.warn.flag = flag sys.publish("WARN_FLAG_CHANGED", idx) end end end end end local function grp_fault_calculate(idx) while true do local ret, grp_idx = sys.waitUntil("REAL_DATA_UPDATE", 2000) if grp_idx and grp_idx == idx then local level = 0 local now = os.time() local data_space = g_grp[grp_idx] if data_space then if data_space.fault.level == nil then -- 初始化故障等级 data_space.fault.level = 0 end if data_space.protect.level == nil then -- 初始化保护等级 data_space.protect.level = 0 end -- 组内设备离线 2级故障(只影响本组)PCS Cluster rack for sn, v in pairs(nodes_info) do if not v.recv_time then v.recv_time = os.time() end if v.grp_idx == idx then if os.difftime(now, v.recv_time) >= OFFLINE_TIME then if v.offline_enable and v.offline_enable == true and v.offline == false then offline_report_station("离线设备: total lixian:" .. v.sn_suffix) v.offline = true end ubuslog.log(ubuslog.LOG_NOTICE, "设备离线: ", v.sn_suffix) else if v.offline_enable and v.offline_enable == true and v.offline == true then offline_report_station("恢复设备: total huifu:" .. v.sn_suffix) v.offline = false end end end end for sn, v in pairs(nodes_info) do if v.offline_enable and v.offline and v.offline_enable == true and v.offline == true and v.grp_idx == idx then level = 2 break end end local tmp = data_space.data local group_warn_map = g_grp[idx].group_warn3_map for i = 1, #group_warn_map do if group_warn_map[i][ENABLE_FLAG] == true then local cluster_val = tmp[group_warn_map[i][TAG_NAME_CLUSTER]] local rack_val = tmp[group_warn_map[i][TAG_NAME_RACK]] if (cluster_val and cluster_val > 0) or (rack_val and rack_val > 0) then level = group_warn_map[i][PRO_LEVEL] > level and group_warn_map[i][PRO_LEVEL] or level if group_warn_map[i][ALARM_TRIGGER_FLAG] == false then fault_report_station(group_warn_map, idx, i, 3) group_warn_map[i][ALARM_TRIGGER_FLAG] = true --alarm is triggered end else if group_warn_map[i][ALARM_TRIGGER_FLAG] == true then fault_report_station(group_warn_map, idx, i, 2) group_warn_map[i][ALARM_TRIGGER_FLAG] = false end end end end -- 状态改变通知其他模块上报 if data_space.fault.level ~= level then data_space.fault.level = level sys.publish("FAULT_LEVEL_CHANGED", idx) end end end end end local function grp_protect_process(idx) local last_protect_level = -1 local protect_level = 0 local last_fire_trip local do_sn = string.format("%s_DI", active_sn) while true do local ret, grp_idx = sys.waitUntil("PROTECT_LEVEL_CHANGED", 5000) if g_grp[idx].protect.level and g_grp[idx].fault.level then protect_level = grp_protect_level_get(g_grp[idx].protect.level, g_grp[idx].fault.level, 1) end if last_protect_level ~= protect_level then last_protect_level = protect_level last_fire_trip = 1 else last_fire_trip = 0 end -- 组内保护动作 if last_fire_trip == 1 then if protect_level >= 2 then local pcs_sn = string.format("%s%s%d", active_sn, "_PCS", idx) -- 功率写0,关机 internal_api.call_dev_service(active_sn, pcs_sn, "NULL", "WritePExpect", { TAG_4E92 = 0 }) internal_api.call_dev_service(active_sn, pcs_sn, "NULL", "guanji", { TAG_4EAF = 1 }) end end end end local function di_capture() local data_space = g_common -- open for i, v in ipairs(common_warn_map) do if v then -- 构建文件路径 local filePath = "/sys/class/gpio/gpio" .. v[SERIAL] .. "/value" local fd = io.open(filePath, "r") table.insert(v, FILE_DES, fd) -- 插入GPIO文件描述符 ubuslog.log(ubuslog.LOG_NOTICE, "DI ", v[TAG_NAME], "SERIAL ", v[SERIAL], "FILE_DES ", v[FILE_DES]) end end while true do -- read for i, v in ipairs(common_warn_map) do if v then v[FILE_DES]:seek("set", 0) local value = v[FILE_DES]:read("*all") if value then data_space.data[v[TAG_NAME]] = value ubuslog.log(ubuslog.LOG_DEBUG, "TAG ", v[TAG_NAME], "value ", value) end end end sys.wait(500) end -- what to do ? no close end ------------------------------------------------------------------------------------------------- local function pp_msg(topic, payload) local currTime = os.time() local obj = cjson.decode(payload) local tags = obj.tag_node and cjson.decode(obj.tag_node) or nil if not obj.sn then ubuslog.log(ubuslog.LOG_NOTICE, "Invalid device sn") return end if not tags then ubuslog.log(ubuslog.LOG_NOTICE, "Invalid device tags") return end -- 1.过滤设备SN local node_info = nodes_info[obj.sn] if not node_info then --ubuslog.log(ubuslog.LOG_NOTICE, "Filtering decive SN") return end -- 2.过滤服务 local found for _, ident in ipairs(node_info.ident_list) do if obj.identifier == ident then found = true break end end if not found then --ubuslog.log(ubuslog.LOG_NOTICE, "Filtering service") return end local grp_idx = node_info.grp_idx local data_space if grp_idx == 0 then data_space = g_common -- 公共数据 else data_space = g_grp[grp_idx] -- 分组数据 end if data_space then -- 更新数据 for msg_field, msg_value in pairs(tags) do -- 遍历上来的变量 local data = data_space.data data[msg_field] = msg_value end -- 更新状态 node_info.recv_time = os.time() sys.publish("REAL_DATA_UPDATE", grp_idx) end end local function iot_msg(topic, payload) local currTime = os.time() local obj = cjson.decode(payload) if obj.identifier == "protect_level_set" then local changed = false -- 总保护等级,此参数暂不使用 if obj.protect_level then if g_total.protect.level ~= obj.protect_level then g_total.protect.level = obj.protect_level changed = true end end -- 组保护等级 for grp_idx = 1, #g_grp do local data_space = g_grp[grp_idx] if not data_space then break end local data = data_space.protect if obj.grps_protect_level and obj.grps_protect_level[grp_idx] then local grp_protect = obj.grps_protect_level[grp_idx] local last_level = data.level if grp_protect.level then data.level = grp_protect.level end if last_level ~= data.level then changed = true end end end if changed then sys.publish("PROTECT_LEVEL_CHANGED") end elseif obj.identifier == "emsguard_aircond" then local last_aircond_status = aircond_action if obj.aircond_start then aircond_action = obj.aircond_start end if last_aircond_status ~= aircond_action then g_changed = 1 sys.publish("AIRCOND_ACTION") end ubuslog.log(ubuslog.LOG_NOTICE, "iot_msg aircond_action: ", aircond_action, "change: ", g_changed) elseif obj.identifier == "warn_trip_set" then local last_warn_trip = gurad_config.warn_trip_enable if obj.warn_trip then gurad_config.warn_trip_enable = obj.warn_trip end if last_warn_trip ~= gurad_config.warn_trip_enable then file_write(GUARD_CFG_FILE, cjson.encode(gurad_config)) end ubuslog.log(ubuslog.LOG_NOTICE, "iot_msg warn_trip_set: ", gurad_config.warn_trip_enable) else return end -- 应答 internal_api.pp2north(active_sn, obj.sn, "NULL", obj.identifier, {}, obj.mi) end ------------------------------------------------------------------------------------------------- function main(nodes_cfg, sn) ubuslog.reinit(LOG_TAG) ubuslog.loglevel_set(ubuslog.LOG_NOTICE) ubuslog.log(ubuslog.LOG_NOTICE, "main_loop", "=============== Guard System of EMS 1.0.0============") local gw_sn = sn if not gw_sn then gw_sn = io.getGatewayID() end local GW_6UL_SN = string.gsub(gw_sn, "21881DFF", "21881EFF") if V3_PRO == 1 then active_sn = GW_6UL_SN else active_sn = gw_sn end ubuslog.log(ubuslog.LOG_DEBUG, "active_sn::::", active_sn) --[[ createDir() local guard_Config = file_read(GUARD_CFG_FILE) if guard_Config == nil then file_write(GUARD_CFG_FILE, cjson.encode(gurad_config)) else gurad_config = cjson.decode(guard_Config) end ]] g_nodes = cjson.decode(nodes_cfg) for i, v in ipairs(g_nodes) do ubuslog.log(ubuslog.LOG_DEBUG, "nodes_cfg,", v) end init_sub_nodes_info(common_warn_map, g_sub_nodes) nodes_info = update_nodes_info(total_nodes) init_grp_structure(g_grp, total_nodes) siganl.signal(siganl.SIGKILL, handler) siganl.signal(siganl.SIGHUP, handler) --get devs local devs = {} for i,v in ipairs(total_nodes) do assert(v.sn_suffix) local dev_sn = v.sn_suffix --[[ Lua 5.3 if DI_SOURCE == 1 and string.find(dev_sn, "_DI") then goto continue end table.insert(devs, dev_sn) ubuslog.log(ubuslog.LOG_DEBUG, "sub dev sn ::::", dev_sn) ::continue:: ]] -- Lua 5.1 if DI_SOURCE == 1 then if string.find(dev_sn, "_DI") then -- what to do? no insert else table.insert(devs, dev_sn) ubuslog.log(ubuslog.LOG_DEBUG, "sub dev sn ::::", dev_sn) end else table.insert(devs, dev_sn) ubuslog.log(ubuslog.LOG_DEBUG, "sub dev sn ::::", dev_sn) end end local local_dev_sn = string.format("%s_GUARD", active_sn) table.insert(devs, local_dev_sn) mqtt_client = internal_api.local_mqtt_session(devs, "APP", function(topic, payload) iot_msg(topic,payload) end, function(topic, payload) pp_msg(topic,payload) end) sys.taskInit(common_fault_calculate) sys.taskInit(total_warn_exec) sys.taskInit(total_protect_process) sys.taskInit(total_fault_level_report) if DI_SOURCE == 1 then sys.taskInit(di_capture) end if AIRCOND_ENABLE == 1 then sys.taskInit(linkage_Pulse_aircond) end if COLLMACH_ENABLE == 1 then sys.taskInit(linkage_cooling_machine) end --aircond_set_report_ems(aircond_set_timeout_before,aircond_set_timeout_after) for grp_idx = 1, #g_grp do sys.taskInit(grp_warn_calculate, grp_idx) sys.taskInit(grp_fault_calculate, grp_idx) sys.taskInit(grp_protect_process, grp_idx) end -- 启动系统框架 sys.init(0, 0) sys.run() end main(arg[1], arg[2])