require "log" require "sys" require "utils" require "patch" require "fs" siganl = require 'posix.signal' syswait = require 'posix.sys.wait' unistd = require 'posix.unistd' mqtt=require "mosquitto" lpack=require("lua_pack") base64=require("base64") dyutils=require("dyutils") math=require("math") cjson=require("cjson") require"lsqlite3" LOG_LEVEL = log.LOGLEVEL_TRACE -------------------------[全局参数定义]------------------------- nodes={} status={} gw_sn=nil fetch_iostr={ {"DI0","cat /sys/class/gpio/gpio0/value"} } for _,v in pairs(fetch_iostr) do status[v[1]] = 1 end local function system_reply(cmd) local f = assert(io.popen(cmd)) local s = nil if f then s = assert(f:read('*a')) end f:close() return s end local function mqtt_send(topic,payload) if not client then return end local mid,errid,errmsg = client:publish(topic, payload) if not mid then log.error("mqtt.send","error:", errid,errmsg) end end local function DevCtrlTopic(gw_sn,dev_sn,port) return string.format("ipc/%s/%s/device/%s/data/Set_Rglt",gw_sn,port,dev_sn) end local function DevRawTopic(gw_sn,dev_sn,port) return string.format("ipc/%s/%s/device/%s/data/raw_data",gw_sn,port,dev_sn) end -- 拆分MQTT消息,转为内部变量和obj local function MessageSpilt(topic,payload) local gw_sn,dev_sn,port,identifier,param,mi,time local s = string.split(topic, '/') if s[1] == 'ipc' then gw_sn = s[2] port = s[3] if s[4] == "device" then dev_sn = s[5] identifier = s[8] local obj = cjson.decode(payload) if obj then mi = obj.mi time = bj.time if s[6] == "data_filtered" then param = obj["tags"] elseif s[6] == "data" and obj["tag_node"]then param =cjson.decode(obj["tag_node"]) else return nil end else return true,gw_sn,dev_sn,port,identifier end else return nil end end return true,gw_sn,dev_sn,port,identifier,param,mi,time end -- 服务上报,或者服务请求的应答 local function ServiceResponse(gw_sn,dev_sn,port,identifier,param,mi,time) local topic = string.format( "ipc/%s/%s/device/%s/data_filtered/service/%s",gw_sn,port,dev_sn,identifier) local obj_send={} local json_str obj_send['mi'] = mi or 0 -- obj_send['len'] = #data obj_send['identifier'] = identifier obj_send['sn'] = dev_sn obj_send['time'] = time or os.time() obj_send["data_type"] = 2 obj_send["tags"] = param and type(param) == "table" and param or cjson.decode(param) json_str = cjson.encode(obj_send) log.info("ServiceResponse",topic,json_str) mqtt_send(topic, json_str) end -- 事件上报 local function Event(gw_sn,dev_sn,port,identifier,param,mi,time) local topic = string.format( "ipc/%s/%s/device/%s/data/event/%s",gw_sn,port,dev_sn,identifier) local obj_send={} local json_str obj_send['mi'] = mi or 0 -- obj_send['len'] = #data obj_send['identifier'] = identifier obj_send['sn'] = dev_sn obj_send['time'] = time or os.time() obj_send["data_type"] = 1 obj_send["tag_node"] = type(param) == "string" and param or cjson.encode(param) json_str = cjson.encode(obj_send) log.info("Event",topic,json_str) mqtt_send(topic, json_str) end -- 调动内部服务 local function ServiceCall(gw_sn,dev_sn,port,identifier,param,mi) local topic = string.format( "ipc/%s/%s/device/%s/data/Set_Rglt",gw_sn,port,dev_sn) local obj_send={} local json_str obj_send['mi'] = mi or 0 -- obj_send['len'] = #data obj_send['identifier'] = identifier obj_send['sn'] = dev_sn obj_send['time'] = os.time() if param then for k,v in pairs(param)do obj_send[k] = v end end json_str = cjson.encode(obj_send) log.info("ServiceCall",topic,json_str) mqtt_send(topic, json_str) end local function on_mqtt_msg(topic, payload) if topic == subscribe[1] then local obj = cjson.decode(payload) if obj and obj.sn == nodes[1].sn then if "FetchStatus" == obj.identifier then sys.publish("FETCH_STATUS",obj.identifier,obj.mi) end end end end local function FetchPortBySN(sn) for _,v in pairs(nodes) do if v.sn == sn then return v.connect_port end end end ---------------------------------------------------------- 外部消息---------------------------------------------------------- local function mqtt_session(id, addr, port, usr, pwd, subscribe, qos,func) cid, keepAlive, timeout = tonumber(cid) or 1, tonumber(keepAlive) or 300, tonumber(timeout) or 1800 cleansession, qos, retain = tonumber(cleansession) or 0, tonumber(qos) or 0, tonumber(retain) or 0 sys.taskInit(function() mqtt.init() client = mqtt.new() client.ON_CONNECT = function() log.warn("mqtt","client connected") for _,v in pairs(subscribe) do if type(v) == "string" then client:subscribe(v) end end end client.ON_MESSAGE = function(mid, topic, payload) log.info("mqtt recv",topic, payload) if func then func(topic, payload) end end client.ON_DISCONNECT = function() log.warn("mqtt","client disconnected") end client:connect(addr,port) sys.poll_socket=function() client:loop(3000,1) end while(true) do while client:socket() do sys.wait(2000) end sys.wait(1000) client:reconnect() end end) end local function handler() local pid, status, code = syswait.wait(-1, syswait.WNOHANG) log.error('system exit', pid, status, code) --打印不出来 os.exit(0) end function main(nodes_cfg,sn) -- local last_used_TOU log.info("calculate", "=============== Digit Input Read ============") if not nodes_cfg then return -1,"Input param error" end gw_sn = sn log.info("main_loop", string.format("Try Run At Shell\nsn='%s'\nnodes='%s'\nmain(nodes,sn)",gw_sn,nodes_cfg)) local obj = cjson.decode(nodes_cfg) if obj and #obj then if #obj > 1 then unistd.sleep(10) return -2,"these device the only be one" else nodes = obj end else return -3,"Input param miss word" end FetchPortBySN(sn) subscribe={} table.insert(subscribe,DevCtrlTopic(gw_sn,nodes[1].sn,"DI_1")) -- 只可能有一个设备 mqtt_session(nil,"localhost", 1883 , nil, nil, subscribe, 0,on_mqtt_msg) for _,v in pairs(subscribe) do log.info("subscribe topic list",v) end siganl.signal(siganl.SIGKILL,handler) siganl.signal(siganl.SIGHUP,handler) sys.taskInit(function() while true do local ret,service,mi = sys.waitUntil("FETCH_STATUS",300) local change = nil for _,v in pairs(fetch_iostr) do local str = system_reply(v[2]) if str then local DIn = tonumber(str) if DIn then local obj={} obj[v[1]]=true if DIn > status[v[1]] then --rise change = true Event(gw_sn,nodes[1].sn,nodes[1].connect_port,"TriggleRise",obj) elseif DIn < status[v[1]] then --falling change = true Event(gw_sn,nodes[1].sn,nodes[1].connect_port,"TriggleFalling",obj) else -- 保持 end status[v[1]] = DIn end end end if ret and service and mi then ServiceResponse(gw_sn,nodes[1].sn,nodes[1].connect_port,service,status,mi) elseif change then sys.wait(2000) ServiceResponse(gw_sn,nodes[1].sn,nodes[1].connect_port,"Status",status) end end end) --启动系统框架 sys.init(0, 0) sys.run() end main(arg[1],arg[2])