local syslog=require("syslog") local math=require("math") local cjson=require("cjson") -------------------------[全局参数定义]------------------------- BATT_TEMP_COUNT = 4 BATT_VOL_COUNT = 14 IFU_DAT_FILE = "/app/ifu_bak.json" DEVICE_OFFLINE_TIME = 20*60 ifu_obj={} pcs_obj={} bms_obj={} syslog.openlog("EMU", syslog.LOG_PERROR + syslog.LOG_ODELAY, "LOG_USER") local 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 local 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 local function parser_input(obj) if not obj or type(obj) ~= "string" then syslog.syslog("LOG_WARNING","Invalid message of virtual device") return nil,nil end local obj = cjson.decode(obj) -- --获取输入变量-- local pcs,bms={},{} if not obj["datas"] then syslog.syslog("LOG_WARNING","Invalid structure of virtual device,message need [datas] in object") return nil,nil end 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 pcs.SN = v.sn pcs.time = v.time elseif v.tags and v.tags.dev_type and v.tags.dev_type == "BMS" then bms = v.tags bms.dev_type = nil bms.sn = v.sn bms.time = v.time end end syslog.syslog("LOG_WARNING","PCS:" .. cjson.encode(pcs)) syslog.syslog("LOG_WARNING","BMS:" .. cjson.encode(bms)) return pcs,bms end -- | BMS/PCS | variable name | emu coefficient | emu variable name | emu coefficient | ifu variable name | local symbol_remap={ {"BMS", "Model_SN", 1, "BMS_ID", nil, nil}, {"BMS", "Version", 1, "BMS_SOFT_VER", nil, nil}, {"BMS", "SOC", 1, "SOC", 1, "StateOfCharge"}, {"BMS", "SOH", 1, "SOH", 1, "StateOfHealth"}, {"BMS", "FullCapacity", 1, "TCap", 1000, "TotalCapacity"}, {"BMS", "ReMainCapacity", 1, "RemCap", 1000, "RemainingCapacity"}, {"BMS", "VoltageOfPack", 1, "Vbat", 1, "BatteryVoltage"}, {"BMS", "Current", 1, "Ibat", 1, "BatteryCurrent"}, {"PCS", "BatteryPower", 1, nil, 1, "BatteryWattage"}, --先不自己计算 {"PCS", "BatteryPower", 1, nil, 1, "PowerAtCharge"}, --先不自己计算 {"PCS", "E_BatteryCharge", 1, nil, 1000, "AccumulatedLifetimeCharge"}, --先不自己计算 {"PCS", "E_BatteryDischarge", 1, nil, 1000, "AccumulatedLifetimeDischarge"}, --先不自己计算 {"PCS", "E_BatCharge_Today", 1, nil, 1, "DailyCharge"}, --先不自己计算 {"PCS", "E_BatDischarge_Today", 1, nil, 1, "DailyDischarge"}, --先不自己计算 {"PCS", "BMSPackTemp", 1, nil, 1, "BatteryTemp"}, {"PCS", "workMode", 1, nil, 1, "InverterMode"}, {"PCS", "Temperature", 1, nil, 1, "InverterTemp"}, {"PCS", "device_sn", 1, "PCS_ID", nil, nil}, {"PCS", "firmware", 1, "PCS_Software_version",nil, nil}, {"PCS", "VGrid", 1, "VGrid", 1, "GridVoltage"}, {"PCS", "IGrid", 1, "IGrid", 1, "GridCurrent"}, {"PCS", "PGrid", 1, nil, 1, "GridWattage"}, {"PCS", "FGrid", 1, nil, 1, "GridFrequency"}, {"PCS", "Ppv1", 1, "PPv1", 1, "Ppv1"}, {"PCS", "Ppv2", 1, "PPv2", 1, "Ppv2"}, {"PCS", "Vpv1", 1, nil, 1, "Ppv1Voltage"}, {"PCS", "Ipv1", 1, nil, 1, "Ppv1Current"}, {"PCS", "Ppv1", 1, nil, 1, "Ppv1Wattage"}, {"PCS", "Vpv2", 1, nil, 1, "Ppv2Voltage"}, {"PCS", "Ipv2", 1, nil, 1, "Ppv2Current"}, {"PCS", "Ppv2", 1, nil, 1, "Ppv2Wattage"}, {"PCS", "E_PV_Total", 1, "TPvA", 1000, "TotalAccumulatedSolar"}, {"PCS", "E_total_Sell", 1, "E_total_Sell", 1000, "TotalAccumulativePowerToGrId"}, {"PCS", "E_total_Buy", 1, "E_total_Buy", 1000, "TotalAccumulativePowerFromGrid"} } local function ifu_calculate(obj,pcs_obj,bms_obj) local cache = read_cache_from_file(IFU_DAT_FILE) if not cache then cache={} cache.ifu={ -- 逆变器 InverterMode=0,InterconnectionState=0,InverterTemp=0, -- 电池 BatteryVoltage=0,BatteryCurrent=0,BatteryTemp=0,BatteryWattage=0, RemainingCapacity=0,StateOfHealth=0,StateOfCharge=0,PowerAtCharge=0,TotalCapacity=0, AccumulatedLifetimeCharge=0,AccumulatedLifetimeDischarge=0,ChargeCapacity=0,DischargeCapacity=0, -- 电网 GridVoltage=0,GridCurrent=0,GridWattage=0,GridFrequency=0,TotalAccumulativePowerFromGrid=0,TotalAccumulativePowerToGrId=0, DailyCharge=0,DailyDischarge=0, -- 光伏 Ppv1=0,Ppv2=0,Ppv1Voltage=0,Ppv1Current=0,Ppv1Wattage=0, Ppv2Voltage=0,Ppv2Current=0,Ppv2Wattage=0, Ppv3Voltage=0,Ppv3Current=0,Ppv3Wattage=0,TotalAccumulatedSolar=0, -- 热水器 HWCurrent=0,HWWattage=0,HWVoltage=0,HWAccumulatedWattage=0,PowerFactor=0 } cache.lastReMainCapacity = 0 cache.date = os.date("*t", os.time()) syslog.syslog("LOG_WARNING","table init") write_cache_to_file(IFU_DAT_FILE,cache) end if not last_cal then last_cal = os.time() end local bms_valid = bms_obj and bms_obj.time and os.difftime(os.time(),bms_obj.time) < DEVICE_OFFLINE_TIME local pcs_valid = pcs_obj and pcs_obj.time and os.difftime(os.time(),pcs_obj.time) < DEVICE_OFFLINE_TIME if not bms_valid then syslog.syslog("LOG_WARNING","Invalid source data," .. string.format("bms sample time %d",bms_obj and bms_obj.time or 0)) end if not pcs_valid then syslog.syslog("LOG_WARNING","Invalid source data," .. string.format("pcs sample time %d",pcs_obj and pcs_obj.time or 0)) end -- ifu_obj = cache.ifu -- 可以直接映射的变量 for i,v in pairs(symbol_remap) do if v and v[1] == "BMS" then if bms_obj[v[2]] and v[5] and v[6] then print("bms",v[2],bms_obj[v[2]]) if type(bms_obj[v[2]]) == "number" then ifu_obj[v[6]] = bms_obj[v[2]] * v[5] else ifu_obj[v[6]] = v[6] end end elseif v and v[1] == "PCS" then if pcs_obj[v[2]] and v[5] and v[6] then print("pcs",v[2],pcs_obj[v[2]]) if type(pcs_obj[v[2]]) == "number" then ifu_obj[v[6]] = pcs_obj[v[2]] * v[5] else ifu_obj[v[6]] = v[6] end end end end cache.ifu = ifu_obj -- write_cache_to_file("/tmp/ifu_"..os.date("%X"),ifu_obj) -- write_cache_to_file("/tmp/pcs_"..os.date("%X"),pcs_obj) -- write_cache_to_file("/tmp/bms_"..os.date("%X"),bms_obj) syslog.syslog("LOG_WARNING","IFU:" .. cjson.encode(ifu_obj)) write_cache_to_file(IFU_DAT_FILE,cache) end function protocol_decode(input_str, len) --出参格式化-- local err_code = -1 local pcs_obj, bms_obj = parser_input(input_str) if pcs_obj and pcs_obj.time and os.difftime(os.time(),pcs_obj.time) < DEVICE_OFFLINE_TIME and bms_obj and bms_obj.time and os.difftime(os.time(),bms_obj.time) < DEVICE_OFFLINE_TIME then local ret,msg = pcall(ifu_calculate,ifu_obj,pcs_obj,bms_obj) if ret then local payload=cjson.encode(ifu_obj) return 0,payload,#payload else syslog.syslog("LOG_WARNING","IFU canlculate failed," ,msg) end else syslog.syslog("LOG_WARNING","Invalid source data," .. string.format("pcs sample time %d,bms sample time %d",pcs_obj and pcs_obj.time or 0,bms_obj and bms_obj.time or 0)) return -1,nil,0 end end datas='{"datas":[{"state":114,"identifier":"post","time":1596770567,"tags":{"Current":0,"BatteryCycle":3,"MOSFET_Temperature":29.5,"VoltageOfPack":47.33,"Fault":0,"Voltage_Unit_14":3383,"ReMainCapacity":11.72,"Voltage_Unit_5":3383,"Voltage_Unit_2":3383,"Voltage_Unit_9":3383,"SOH":100,"Temperature_3":27.9,"Protection":0,"DesignCapacity":120,"Temperature_1":28,"Voltage_Unit_3":3382,"Voltage_Unit_4":3382,"Status":12,"Voltage_Unit_15":-1,"dev_type":"BMS","FullCapacity":126,"Balance":0,"Environment_Temperature":32.1,"Voltage_Unit_10":3383,"Temperature_2":28.1,"Voltage_Unit_1":3383,"Temperature_4":27.9,"Voltage_Unit_13":3383,"Voltage_Unit_8":3383,"Voltage_Unit_12":3383,"Voltage_Unit_16":-1,"Voltage_Unit_11":3384,"Warning":0,"Voltage_Unit_6":3383,"Voltage_Unit_7":3383,"SOC":10},"sn":"2020080302","quality":99},{"state":88,"identifier":"post","time":1596770567,"tags":{"workMode":257,"Ipv2":0,"FLoad":49.97,"FGrid":49.97,"Iload":0.1,"Vpv2":0,"E_total_Buy":1173356544,"Ibattery1":0,"h_Total":13434880,"E_total_Sell":0,"PV3Mode":0,"BatteryPower":0,"Vbattery1":0,"dev_type":"PCS","BMSWarning":65536,"Ppv1":0,"Ppv3":0,"Temperature":0,"E_BatteryDischarge":0,"BMSPackTemp":0,"E_BatteryCharge":13.8,"Vpv1":0,"Ppv2":0,"Vpv3":0,"SOH":0,"E_Total_buy":1173356544,"E_Total_Shell":0,"PV2Mode":0,"DRMStatus":0,"DiagStatus":540744,"VGrid":222.9,"BackupLoad_Pow":0,"E_PV_Total":0,"E_day":0.1,"BMSErrorCode":256,"E_Total":229376,"gridMode":1,"E_Load_Day":0,"Total_Power":0,"BMSDischargeImax":0,"Ipv1":0,"InverterWarning":256,"BMSStatus":16,"BMSChargeImax":0,"ErrorMessage":0,"E_Total_Load":720888.5,"PGrid":-2,"Ipv3":0,"loadMode":65537,"OnGridLoadPow":2,"MeterPowerFactor":-26,"E_BatCharge_Today":0,"PV1Mode":0,"IGrid":0,"BattaryMode":0,"Vload":7.7,"meterStatus":1,"E_BatDischarge_Today":3353.5,"SOC":0},"sn":"2020080301","quality":86}]}' protocol_decode(datas, #datas) syslog.closelog()