local syslog=require("syslog") local math=require("math") local cjson=require("cjson") -------------------------[全局参数定义]------------------------- BATT_TEMP_COUNT = 4 BATT_VOL_COUNT = 14 EMU_CALCULATE_INTERVAL =5 FAST_ADJ_CURR_TIME = 30*60 FAST_SAMPLE_TIME_KEEP = 5*60 EMU_REPORT_INTERVAL = 60*60 SAPMLE_INTERVAL = 30 EMU_DAT_FILE = "/app/emu_bak.json" -------------------------[输入设备名称以及标识符]------------------------- -------------------------[事件参数]------------------------- -------------------------[系统变量]------------------------ emu_obj={} pcs_obj={} bms_obj={} syslog.openlog("EMU", syslog.LOG_PERROR + syslog.LOG_ODELAY, "LOG_USER") function write_cache_to_file(path,ojb) local file=io.open(path, 'w+') file:seek('set') file:write(cjson.encode(ojb)) file:flush() file:close() end function read_cache_from_file(path) local file=io.open(path, 'a+') local ojb={} file:seek('set') ojb = file:read() file:close() if(ojb == nil) then return nil end return cjson.decode(ojb) end function parser_input(obj) local obj = cjson.decode(obj) -- --获取输入变量-- local pcs,bms={},{} for i,v in pairs(obj["datas"]) do if v.tags and v.tags.dev_type and v.tags.dev_type == "PCS" then pcs = v.tags pcs.dev_type = nil elseif v.tags and v.tags.dev_type and v.tags.dev_type == "BMS" then bms = v.tags bms.dev_type = nil end end syslog.syslog("LOG_WARNING",cjson.encode(pcs)) syslog.syslog("LOG_WARNING",cjson.encode(bms)) return pcs,bms end -- | BMS/PCS | variable name | coefficient | emu variable name | local symbol_remap={ {"BMS", "Model_SN", 1, "BMS_ID"}, {"BMS", "Version", 1, "BMS_SOFT_VER"}, {"BMS", "SOC", 1, "SOC"}, {"BMS", "SOH", 1, "SOH"}, {"BMS", "FullCapacity", 1, "TCap"}, {"BMS", "ReMainCapacity", 1, "RemCap"}, {"BMS", "VoltageOfPack", 1, "Vbat"}, {"BMS", "Current", 1, "Ibat"}, {"PCS", "device_sn", 1, "PCS_ID"}, {"PCS", "firmware", 1, "PCS_Software_version"}, {"PCS", "VGrid", 1, "VGrid"}, {"PCS", "IGrid", 1, "IGrid"} } local function emu_calculate(emu_obj,pcs_obj,bms_obj) local cache = read_cache_from_file(EMU_DAT_FILE) if not cache then cache={} cache.emu={} cache.emu.DeviceID='' cache.emu.BMS_ID='' cache.emu.BMS_SOFT_VER='' cache.emu.PCS_ID='' cache.emu.PCS_Software_version='' cache.emu.TCap=0 cache.emu.RemCap=0 cache.emu.SOC=0 cache.emu.SOH=0 cache.emu.TADCh=0 cache.emu.TACh=0 cache.emu.Daily_Ch=0 cache.emu.daily_DCh=0 cache.emu.PPv1=0 cache.emu.PPv2=0 cache.emu.TPvA=0 cache.emu.Vbat=0 cache.emu.Ibat=0 cache.emu.BTemp=0 cache.emu.Pbat=0 cache.emu.VGrid=0 cache.emu.IGrid=0 cache.emu.TAPGr=0 cache.emu.TAP2Gr=0 cache.emu.Temp_Max_bat=0 cache.emu.Temp_Min_bat=0 cache.emu.Vol_Max_bat=0 cache.emu.Vol_Min_bat=0 cache.emu.Vol_Max_Bat_No=0 cache.emu.Vol_Min_Bat_No=0 cache.emu.Vol_Diff_bat=0 cache.time=os.time() cache.lastReMainCapacity = 0 cache.date = os.date("*t", os.time()) syslog.syslog("LOG_WARNING","table init") write_cache_to_file(EMU_DAT_FILE,cache) end if os.difftime(os.time(), cache.time) >= EMU_CALCULATE_INTERVAL then --数据平滑后上报 cache.time = os.time() local last_emu = cache.emu -- 可以直接映射的变量 for i,v in pairs(symbol_remap) do if v and v[1] == "BMS" then if bms_obj[v[2]] and bms_obj[v[3]] and type(bms_obj[v[2]]) == "number" and type(bms_obj[v[3]]) == "number" then last_emu[v[4]] = bms_obj[v[2]] * bms_obj[v[3]] end end end if pcs_obj.TAP2Gr then last_emu.TAP2Gr = last_emu.TAP2Gr + EMU_CALCULATE_INTERVAL / 3600 * pcs_obj.TAP2Gr end if pcs_obj.TAPGr then last_emu.TAPGr = last_emu.TAPGr + EMU_CALCULATE_INTERVAL / 3600 * pcs_obj.TAPGr end if pcs_obj.Vpv1 and pcs_obj.Ipv1 then last_emu.PPv1 = pcs_obj.Vpv1 * pcs_obj.Ipv1 end if pcs_obj.Vpv2 and pcs_obj.Ipv2 then last_emu.PPv2 = pcs_obj.Vpv2 * pcs_obj.Ipv2 end --累计两路公里 if pcs_obj.Vpv1 and pcs_obj.Ipv1 and pcs_obj.Vpv2 and pcs_obj.Ipv2 then local power_sum = pcs_obj.Vpv1 * pcs_obj.Ipv1 + pcs_obj.Vpv2 * pcs_obj.Ipv2 last_emu.TPvA = last_emu.TPvA + EMU_CALCULATE_INTERVAL / 3600 * power_sum end if bms_obj.ReMainCapacity then --如果第一次那么不计入统计 if cache.lastReMainCapacity == 0 then cache.lastReMainCapacity = bms_obj.ReMainCapacity end --每天定时清空daily统计 local date = os.date("*t", os.time()); if date["data"] ~= cache.date["data"] and date["hour"] == 8 then -- 8 地方时区 last_emu.Daily_Ch = 0 last_emu.daily_DCh = 0 end local diff = bms_obj.ReMainCapacity - cache.lastReMainCapacity if diff > 0 then last_emu.TACh = last_emu.TACh + diff last_emu.Daily_Ch = last_emu.Daily_Ch + diff elseif diff < 0 then last_emu.TADCh = last_emu.TACh - diff last_emu.daily_DCh = last_emu.daily_DCh - diff end cache.lastReMainCapacity = bms_obj.ReMainCapacity end --计算平均温度,最大最小电压 local temp_sum,temp_count,tab = 0,0,{} for i=1, BATT_TEMP_COUNT do local temp = bms_obj["Temperature_" .. i] if not temp then break end temp_sum = temp_sum + temp temp_count = i table.insert(tab,temp) end if temp_count > 0 then last_emu.BTemp = temp_sum/BATT_TEMP_COUNT else last_emu.BTemp = 0 end if #tab == BATT_TEMP_COUNT then table.sort(tab) last_emu.Temp_Max_bat = tab[#tab] last_emu.Temp_Min_bat = tab[1] end if bms_obj.VoltageOfPack and bms_obj.Current then last_emu.Pbat = bms_obj.VoltageOfPack * bms_obj.Current end if pcs_obj.Vpv2 then last_emu.PPv2 = pcs_obj.Vpv2 * pcs_obj.Ipv2 end if bms_obj.Vpv2 and pcs_obj.Ipv2 then last_emu.PPv2 = pcs_obj.Vpv2 * pcs_obj.Ipv2 end --计算电池温度,最高电压,最低电压,压差 local tab = {} for i=1, BATT_VOL_COUNT do local vol = bms_obj["Voltage_Unit_" .. i] if not vol then break end -- tab[string.format( "%d",i)] = vol table.insert(tab,vol) end if #tab == BATT_VOL_COUNT then table.sort(tab) last_emu.Vol_Max_bat = tab[#tab] last_emu.Vol_Min_bat = tab[1] if last_emu.Vol_Max_bat and last_emu.Vol_Min_bat then last_emu.Vol_Diff_bat = last_emu.Vol_Max_bat - last_emu.Vol_Min_bat end end -- 找出电池ID for i=1, BATT_VOL_COUNT do local vol = bms_obj["Voltage_Unit_" .. i] if vol and last_emu.Vol_Max_bat and last_emu.Vol_Max_bat == vol then last_emu.Vol_Max_Bat_No = i end if vol and last_emu.Vol_Min_bat and last_emu.Vol_Min_bat == vol then last_emu.Vol_Min_Bat_No = i end end syslog.syslog("LOG_WARNING",cjson.encode(cache)) write_cache_to_file(EMU_DAT_FILE,cache) end end local function mqtt_session_init() mqtt_client = MQTT.client.create(broker_addr, broker_port, function () end) mqtt_client:connect(string.format("emu_%d", os.time())) end local function mqtt_session_publish(topic,obj) json_str = cjson.encode(obj_send) mqtt_client:publish(topic, json_str) end local function emu_data_format(emu) local str = cjson.encode(emu) if str then return 0,str,#str else return -1 end end function protocol_decode(input_str, len) --出参格式化-- syslog.syslog("LOG_WARNING",input_str) pcs_obj, bms_obj = parser_input(input_str) emu_calculate(emu_obj,pcs_obj,bms_obj) -- if not last_calu then last_calu = os.time() end -- if os.difftime(os.time(),last_calu) > EMU_REPORT_INTERVAL then -- last_calu = os.time() -- --计算汇聚EMU数据 -- emu_obj = emu_data_report(emu_obj,pcs_obj,bms_obj) -- end -- if not last_fast_sample_keep then last_fast_sample_keep = 0 end -- --判断是否存在报警-- -- if pcs_has_alarm(pcs_obj) or bms_has_alarm(bms_obj) then -- -- 报警只采样一次 -- if not (os.difftime(os.time(),last_fast_sample_keep) <= FAST_SAMPLE_TIME_KEEP) then -- last_fast_sample_keep = os.time() -- end -- end -- if os.difftime(os.time(),last_fast_sample_keep) <= FAST_SAMPLE_TIME_KEEP then -- if not last_sample_interval then last_sample_interval = 0 end -- if os.difftime(os.time(),last_sample_interval) <= SAPMLE_INTERVAL then -- last_sample_interval = os.time() -- -- 触发高频上报-- -- pcs_fast_sample() -- bms_fast_sample() -- end -- end -- if not last_adj_curr then last_adj_curr = 0 end -- if os.difftime(os.time(),last_adj_curr) <= FAST_ADJ_CURR_TIME then -- last_adj_curr = os.time() -- -- 计算充放电电流,温度查表-- -- local mode,curr = bat_curr_calculate(bms_obj) -- pcs_ctrl_curr_set(mode,curr) -- end --用户自定义数据处理 -- status,err_code = pcall(udef_process, json_obj) -- if not status or not err_code then -- if not status then -- syslog.syslog("LOG_WARNING","err:FATAL") -- end -- return -3,nil,0 -- end err_code,out_str,out_len=emu_data_format(emu_obj) syslog.syslog("LOG_WARNING", string.format( "return code:%d",err_code)) return err_code,out_str,out_len end local json_str = '{"datas":[\ {"sn":"1","identifier":"post",\ "tags":{\ "dev_type":"PCS",\ "device_sn":"PCS11111",\ "firmware":"222333",\ "TAP2Gr":200,\ "TAPGr":100,\ "VGrid":200,\ "IGrid":-23,\ "PGrid":666,\ "workMode":0,\ "Vpv1":100,\ "Ipv1":100,\ "PV1Mode":0,\ "Vpv2":100,\ "Ipv2":100,\ "PV2Mode":0\ }\ },\ {"sn":"2","identifier":"post",\ "tags":{\ "dev_type":"BMS",\ "Model_SN":"BMS2222",\ "Current":10,\ "VoltageOfPack":10,\ "SOC":100,\ "SOH":100,\ "Warning":0,\ "Protection":0,\ "Fault_Status":0,\ "Temperature_1":22,\ "Temperature_2":22,\ "Temperature_3":25.6,\ "Temperature_4":22,\ "Voltage_Unit_1":3.6,\ "Voltage_Unit_2":3.12,\ "Voltage_Unit_3":3.12,\ "Voltage_Unit_4":3.12,\ "Voltage_Unit_5":3.9,\ "Voltage_Unit_6":3.9,\ "Voltage_Unit_7":3.9,\ "Voltage_Unit_8":4.9,\ "Voltage_Unit_9":3.9,\ "Voltage_Unit_10":3.9,\ "Voltage_Unit_11":3.9,\ "Voltage_Unit_12":3.8,\ "Voltage_Unit_13":3.12,\ "Voltage_Unit_14":3.12,\ "Version":"ZL2-2222"\ }\ }\ ]}' protocol_decode(json_str, 0) syslog.closelog()