local syslog=require("syslog") local math=require("math") local cjson=require("cjson") -- local http=require("http") -------------------------[全局参数定义]------------------------- 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 IFU_REPORT_INTERVAL = 30 -- 60*60 SAPMLE_INTERVAL = 30 EMU_DAT_FILE = "/app/emu_bak.json" IFU_DAT_FILE = "/app/ifu_bak.json" HIGH_FREQ_REPORT_LAST_TIME = 300 --发生故障时,高频上报持续时间 -------------------------[输入设备名称以及标识符]------------------------- -------------------------[事件参数]------------------------- -------------------------[系统变量]------------------------ emu_obj={} ifu_obj={} pcs_obj={} bms_obj={} bms_last_fault_time = nil -- BMS上次故障发生时间 pcs_last_fault_time = nil -- PCS上次故障发生时间 mqtt_client = nil 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) 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 pcs.SN = v.sn 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 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", 1000, "BatteryVoltage"}, {"BMS", "Current", 1, "Ibat", 1000, "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 Max_CH_DCH_table = { ZL={ CH={ {min=-9999, max=0, val=0}, {min=0, max=5, val=17}, {min=5, max=10, val=26}, {min=10, max=45, val=65}, {min=45, max=9999, val=0}, }, DCH={ {min=-9999, max=-20, val=0}, {min=-20, max=-10, val=12}, {min=-10, max=0, val=36}, {min=0, max=50, val=74.4}, {min=50, max=55, val=36}, {min=55, max=9999, val=0} } }, other={ CH={ {min=-9999, max=0, val=0}, {min=0, max=10, val=12}, {min=10, max=25, val=36}, {min=25, max=40, val=60}, {min=40, max=47, val=36}, {min=47, max=9999, 0} }, DCH={ {min=-9999, max=-20, val=0}, {min=-20, max=-10, val=12}, {min=-10, max=0, val=36}, {min=0, max=50, val=74.4}, {min=50, max=55, val=36}, {min=55, max=9999, val=0} } }, lost={ CH={ {min=-9999, max=0, val=0}, {min=0, max=5, val=12}, {min=5, max=10, val=12}, {min=10, max=45, val=36}, {min=45, max=9999, 0} }, DCH={ {min=-9999, max=-20, val=0}, {min=-20, max=-10, val=12}, {min=-10, max=0, val=36}, {min=0, max=50, val=74.4}, {min=50, max=55, val=36}, {min=55, max=9999, val=0} } } } local function set_MAX_CH_DCH_to_pcs(pcs, temp, version) local max_CH = nil local max_DCH = nil local max_ch_dch = nil if bms.Version == nil or string.len(bms.Version) then max_ch_dch = Max_CH_DCH_table['lost'] elseif string.sub(bms.Version, 1,2) == "ZL" then max_ch_dch = Max_CH_DCH_table['ZL'] else max_ch_dch = Max_CH_DCH_table['other'] end for i,v in pairs(max_ch_dch['CH']) do if temp > v.min and temp <= v.max then max_CH = v.val break end end for i,v in pairs(max_ch_dch['DCH']) do if temp > v.min and temp <= v.max then max_DCH = v.val break end end local now = os.time() local gw_sn = get_gateway_sn() local topic = "ipc/gw_sn/port/device/"..bms.sn.."/data/Set_Rglt" local payload = {} payload["identifier"] = "DischargeCtrl" payload["sn"] = pcs.sn payload["mi"] = now payload['DiscargeCurr']=max_DCH payload["timestamp"] = now mqtt_session_publish(topic, json.encode(payload)) payload["identifier"] = "ChargeCtrl" payload['DiscargeCurr']=nil payload['ChargeCurr']=max_CH mqtt_session_publish(topic, json.encode(payload)) return max_CH,max_DCH end local function emu_calculate(emu_obj,pcs_obj,bms_obj) local cache = read_cache_from_file(EMU_DAT_FILE) local now = os.time() if not cache then cache={} cache.emu={ DeviceID='',BMS_ID='',BMS_SOFT_VER='',PCS_ID='',PCS_Software_version='', TCap=0,RemCap=0,SOC=0,SOH=0,TADCh=0,TACh=0, Daily_Ch=0,Daily_DCh=0,PPv1=0,PPv2=0,TPvA=0, Vbat=0,Ibat=0,BTemp=0,Pbat=0, VGrid=0,IGrid=0,TAPGr=0,TAP2Gr=0, Temp_Max_bat=0,Temp_Min_bat=0,Vol_Higher_bat=0,Vol_Lower_bat=0,Vol_Higher_Bat_No=0,Vol_Lower_Bat_No=0,Vol_Diff_bat=0, AlarmVolDiffOver=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 elseif v and v[1] == "PCS"then if bms_obj[v[5]] and bms_obj[v[6]] 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 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 if bms_obj.Model_SN and last_emu.BMS_ID and bms_obj.Model_SN ~= last_emu.BMS_ID then -- 查看BMS ID是否变更过 last_emu.TACh = 0 last_emu.TADCh = 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.TADCh - 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 --计算电池温度,最高电压,最低电压,压差 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_Higher_bat = tab[#tab] last_emu.Vol_Lower_bat = tab[1] if last_emu.Vol_Higher_bat and last_emu.Vol_Lower_bat then last_emu.Vol_Diff_bat = last_emu.Vol_Higher_bat - last_emu.Vol_Lower_bat if last_emu.Vol_Diff_bat and type(last_emu.Vol_Diff_bat) == "number" then last_emu.AlarmVolDiffOver = 0 if last_emu.Vol_Diff_bat > 100 then last_emu.AlarmVolDiffOver = 1 elseif last_emu.Vol_Diff_bat > 200 then last_emu.AlarmVolDiffOver = 2 elseif last_emu.Vol_Diff_bat > 200 then last_emu.AlarmVolDiffOver = 3 end end end end -- 找出电池ID for i=1, BATT_VOL_COUNT do local vol = bms_obj["Voltage_Unit_" .. i] if vol and last_emu.Vol_Higher_bat and last_emu.Vol_Higher_bat == vol then last_emu.Vol_Higher_Bat_No = i end if vol and last_emu.Vol_Lower_bat and last_emu.Vol_Lower_bat == vol then last_emu.Vol_Lower_Bat_No = i end end syslog.syslog("LOG_WARNING",cjson.encode(cache)) write_cache_to_file(EMU_DAT_FILE,cache) end end 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 -- 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 local function pcs_has_alarm(pcs) if pcs and pcs.inverterWarC_BOOSThardwareovercurrent ~= 0 or pcs.inverterWarC_BOOSTsoftwareovercurrent ~= 0 or pcs.inverterWarC_BatterycurrentRMS ~= 0 or pcs.inverterWarC_Offgridbatterycurrent ~= 0 or pcs.inverterWarningCode then return true end end local function bms_has_alarm(bms) if bms and bms.Warning ~= 0 or bms.Protection ~= 0 or bms.Fault ~= 0 then return true end end local function pcs_ctrl_curr_set(emu,pcs,bms) bms_temp = temp_sum/temp_count set_MAX_CH_DCH_to_pcs(pcs, emu.BTemp, bms.Version) end local function bms_sample(bms) local now = os.time() local gw_sn = get_gateway_sn() local topic = "ipc/gw_sn/port/device/"..bms.sn.."/data/Set_Rglt" local payload = {} payload["identifier"] = "SystemInformationRequest" payload["sn"] = bms.sn payload["mi"] = now payload["timestamp"] = now mqtt_session_publish(topic, json.encode(payload)) end local function pcs_sample(pcs) local now = os.time() local gw_sn = get_gateway_sn() local topic = "ipc/gw_sn/port/device/"..bms.sn.."/data/Set_Rglt" local payload = {} payload["sn"] = bms.sn payload["mi"] = now payload["timestamp"] = now payload["identifier"] = "PVInfo" mqtt_session_publish(topic, json.encode(payload)) payload["identifier"] = "gridInfo" mqtt_session_publish(topic, json.encode(payload)) payload["identifier"] = "MeterInfo" mqtt_session_publish(topic, json.encode(payload)) end local function mqtt_session_init() if not mqtt_client then mqtt_client = MQTT.client.create(broker_addr, broker_port, function () end) mqtt_client:connect(string.format("emu_%d", os.time())) end 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 local function ifu_data_format(ifu) ifu.BatteryId="04d0d5be-51e1-480c-9a0a-229cb6449399" ifu.Date=os.date("%Y-%m-%dT%X.113") --"2020-06-29T09:38:19.943Z" -- ifu.Date="2020-06-29T09:38:19.943Z" local str = cjson.encode(ifu) return str end function protocol_decode(input_str, len) --出参格式化-- local err_code = -1 pcs_obj, bms_obj = parser_input(input_str) ifu_calculate(ifu_obj,pcs_obj,bms_obj) -- if not last_calu then last_calu = os.time() end -- if os.difftime(os.time(),last_calu) > IFU_REPORT_INTERVAL then -- last_calu = os.time() --计算汇聚EMU数据 local payload=ifu_data_format(ifu_obj) if payload then syslog.syslog("LOG_WARNING","==== ifu report ====" .. string.gsub( payload,"\"","\\\"",99999)) os.execute("curl -v -X \"POST\" \"http://staging.aries.panabattery.com/ARIES/api/IfuAutoPolling\" -u \"Admin@admin.com:Password1\" -H \"accept: */*\" -H \"Content-Type: application/json-patch+json\" \"-d " .. string.gsub( payload,"\"","\\\"",99999) .. "\"") end -- end -- 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数据 -- err_code,out_str,out_len=emu_data_format(emu_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_sample() -- bms_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() -- -- 计算充放电电流,温度查表-- -- pcs_ctrl_curr_set(emu_obj,pcs_obj,bms_obj) -- end -- syslog.syslog("LOG_WARNING", string.format( "return code:%d",err_code)) return 0,payload,#payload end local json_str = '{\ "datas":[\ {\ "sn":"2",\ "time":1593581386,\ "state":211,\ "quality":240,\ "identifier":"post",\ "tags":{\ "Current":0,\ "VoltageOfPack":50.36,\ "SOC":40,\ "SOH":100,\ "ReMainCapacity":48.37,\ "DesignCapacity":120,\ "FullCapacity":120,\ "BatteryCycle":3,\ "Warning":0,\ "Protection":0,\ "Fault":0,\ "Status":12,\ "Balance":0,\ "Voltage_Unit_1":3598,\ "Voltage_Unit_2":3599,\ "Voltage_Unit_3":3599,\ "Voltage_Unit_4":3598,\ "Voltage_Unit_5":3599,\ "Voltage_Unit_6":3599,\ "Voltage_Unit_7":3599,\ "Voltage_Unit_8":3599,\ "Voltage_Unit_9":3599,\ "Voltage_Unit_10":3599,\ "Voltage_Unit_11":3599,\ "Voltage_Unit_12":3599,\ "Voltage_Unit_13":3599,\ "Voltage_Unit_14":3598,\ "Voltage_Unit_15":-1,\ "Voltage_Unit_16":-1,\ "Temperature_1":27.4,\ "Temperature_2":27.5,\ "Temperature_3":27.2,\ "Temperature_4":27.3,\ "MOSFET_Temperature":29.4,\ "Environment_Temperature":32.2,\ "Remote_Ctrl":65535,\ "Pack_OV_alarm":65535,\ "Pack_OV_protection":65535,\ "Pack_OV_release_protection":65535,\ "Pack_OV_protection_delay_time":6553.5,\ "Cell_OV_alarm":65535,\ "Cell_OV_protection":65535,\ "Cell_OV_release_protection":65535,\ "Cell_OV_protection_delay_time":6553.5,\ "Pack_UV_alarm":65535,\ "Pack_UV_protection":65535,\ "Pack_UV_release_protection":65535,\ "Pack_UV_protection_delay_time":6553.5,\ "Cell_UV_alarm":65535,\ "Cell_UV_protection":65535,\ "Cell_UV_release_protection":65535,\ "Cell_UV_protection_delay_time":6553.5,\ "Charging_OC_alarm":65535,\ "Charging_OC_protection":65535,\ "CH_OC_protection_delay_time":6553.5,\ "Discharging_OC_alarm":65535,\ "Discharging_OC_protection":58600,\ "DCH_OC_prot_delay_time":5885,\ "DCH_OC2_protection":57700,\ "DCH_OC2_prot_delay_time":0.25,\ "Charging_OT_alarm":419,\ "Charging_OT_protection":420,\ "Charging_OT_release_protection":410,\ "Discharging_OT_alarm":1,\ "Discharging_OT_protection":-2153.6,\ "DCH_OT_release_protection":-2453.6,\ "Charging_UT_alarm":-1803.6,\ "Charging_UT_protection":1,\ "CH_UT_release_protection":310,\ "Discharging_UT_alarm":290,\ "Discharging_UT_protection":330,\ "DCH_UT_release_protection":1,\ "MOSFET_OT_alarm":7.6,\ "MOSFET_OT_protection":8,\ "MOSFET_OT_release_protection":1,\ "Environment_OT_alarm":7.6,\ "Environment_OT_protection":8,\ "Env_OT_release_protection":1,\ "Environment_UT_alarm":8.5,\ "Environment_UT_protection":0.4,\ "Env_UT_release_protection":46,\ "Balance_start_cell_voltage":470,\ "Balance_start_delta_voltage":350,\ "Pack_full_charge_voltage":540,\ "Pack_full_charge_current":550,\ "Cell_sleep_voltage":450,\ "Cell_sleep_delay_time":50,\ "SC_protect_delay_time":7.5e-07,\ "SOC_alarm_threshold":60,\ "Charging_OC2_protect":65436,\ "CH_OC_2_protect_delay_time":1634.65,\ "Cell_OD2_protect":65486,\ "Cell_OD2_protect_delay":90,\ "Pack_OD2_protect":1100,\ "Pack_OD2_protect_delay":85,\ "Cell_Full_CH_Vol":650,\ "Cell_Charging_Cur":700,\ "dev_type":"BMS"\ }\ },\ {\ "sn":"1",\ "time":1593581262,\ "state":0,\ "quality":0,\ "identifier":"post",\ "tags":{\ "DSPVer":"04004-15-S02",\ "ARMVer":"02034-09-S02",\ "device_sn":"73648ESU19600037",\ "dev_type":"PCS",\ "Vpv1":0,\ "Ipv1":0,\ "PV1Mode":0,\ "Vpv2":0,\ "Ipv2":0,\ "PV2Mode":0,\ "Vbattery1":50.3,\ "TBD":10,\ "BMSStatus":80,\ "BMSPackTemp":27.3,\ "Ibattery1":0,\ "BMSChargeImax":75,\ "BMSDischargeImax":6,\ "BMSErrorCode":0,\ "SOC":40,\ "InverterWarning":256,\ "TBD2":216,\ "SOH":100,\ "BattaryMode":2,\ "BMSWarning":0,\ "meterStatus":1,\ "VGrid":221.4,\ "IGrid":0.2,\ "PGrid":65531,\ "FGrid":49.97,\ "gridMode":1,\ "Vload":221.4,\ "Iload":0.3,\ "OnGridLoadPow":61,\ "FLoad":49.96,\ "loadMode":65538,\ "workMode":309,\ "Temperature":0,\ "ErrorMessage":0,\ "E_Total":78643.2,\ "h_Total":3145728,\ "E_day":1.1,\ "E_Load_Day":0,\ "E_Total_Load":209718.6,\ "Total_Power":0,\ "E_PV_Total":0,\ "BackupLoad_Pow":0,\ "MeterPowerFactor":-13,\ "DiagStatus":133184,\ "DRMStatus":0,\ "E_Total_Shell":0,\ "E_Total_buy":1155596288,\ "Vpv3":0,\ "Ipv3":0,\ "PV3Mode":0,\ "E_BatteryCharge":4.8,\ "E_BatteryDischarge":0,\ "Ppv1":0,\ "Ppv2":0,\ "Ppv3":0,\ "BatteryPower":0,\ "E_total_Sell":0,\ "E_total_Buy":1155596288,\ "E_BatCharge_Today":0.3,\ "E_BatDischarge_Today":680.9,\ "BMS_E_VoltageDiff":1,\ "BMS_E_OverTemp":1,\ "BMS_E_UnderTemp":1,\ "inverterWarC_hardwareoOC":0,\ "inverterWarC_BOOSThardwareovercurrent":0,\ "inverterWarC_BOOSTsoftwareovercurrent":0,\ "inverterWarC_BatterycurrentRMS":0,\ "inverterWarC_Offgridbatterycurrent":1,\ "BMS_A_OverTemp":0,\ "BMS_A_UnderTemp":0,\ "BMS_A_VoltageDiff":0\ }\ }\ ]\ }' -- protocol_decode(json_str, 0) syslog.closelog()