--- testSocket -- @module testSocket -- @author AIRM2M -- @license MIT -- @copyright openLuat.com -- @release 2018.10.27 module(..., package.seeall) require "socket" require "nvm" require "net" -- 此处的IP和端口请填上你自己的socket服务器和端口 local heartbeatIp, heartbeatTcpPort, heartbeatUdpPort = nvm.get("heartbeatIp"), nvm.get("heartbeatTcpPort"), nvm.get("heartbeatUdpPort") local macAddr = "" local heartbeatInterval = nvm.get("heartbeatInterval") or 60 local heartbeatRetryInterval = nvm.get("heartbeatRetryInterval") or 1 local heartbeatRetryTimes = nvm.get("heartbeatRetryTimes") or 5 local heartbeatRetrySleep = nvm.get("heartbeatRetrySleep") or 20 local heartbeatWaitRecvMsgMaxTime = nvm.get("heartbeatWaitRecvMsgMaxTime") or 10 local timerSyncResult = false --运维消息类型配置项 --设备登录(client->server) local MESSAGE_TYPE_LOGIN = 1 --设备心跳(client->server) local MESSAGE_TYPE_HEARTBEAT = 3 --开机上报设备配置参数(client->server) local MESSAGE_TYPE_REPORT_CONFIG = 9 --上报设备配置参数命令响应(client->server) local MESSAGE_TYPE_REPORT_CONFIG_CMD_RESP = 10 --心跳响应(server->client) local MESSAGE_TYPE_HEARTBEAT_RESP = 4 --重启设备命令(server->client) local MESSAGE_TYPE_REBOOT_CMD = 1 --恢复出厂设置命令(server->client) local MESSAGE_TYPE_RESTORE_CMD = 6 --设置设备配置参数命令(server->client) local MESSAGE_TYPE_RESET_CMD = 7 --上报设备配置参数命令(server->client) local MESSAGE_TYPE_REPORT_CONFIG_CMD = 8 --ota升级命令(server->client) local MESSAGE_TYPE_OTA_UPDATE_CMD = 3 --开启rifd上报 local MESSAGE_TYPE_ENABLE_RFID_REPORT = 9 local function hex2bin( hexstr ) local str = "" for i = 1, string.len(hexstr) - 1, 2 do local doublebytestr = string.sub(hexstr, i, i+1); local n = tonumber(doublebytestr, 16); if 0 == n then str = str .. '\00' else str = str .. string.format("%c", n) end end return str end --将16进制串转换为字符串 local function hex2str(str) --判断输入类型 if (type(str)~="string") then return nil,"hex2str invalid input type" end --滤掉分隔符 str=str:gsub("[%s%p]",""):upper() --检查内容是否合法 if(str:find("[^0-9A-Fa-f]")~=nil) then return nil,"hex2str invalid input content" end --检查字符串长度 if(str:len()%2~=0) then return nil,"hex2str invalid input lenth" end --拼接字符串 local index=1 local ret="" for index=1,str:len(),2 do ret=ret..string.char(tonumber(str:sub(index,index+1),16)) end --log.info("socketHeartbeatTask.hex2str", ret) return ret end local function createSign(jsonPacket) if not jsonPacket then log.info("socketHeartbeatTask.createSign","jsonPacket not existed!") return false end local protoSecret = nvm.get("protoSecret") if not protoSecret then log.info("socketHeartbeatTask.createSign","protoSecret not existed!") return false end --local signStr = jsonPacket.type..jsonPacket.msgid..jsonPacket.model..jsonPacket.mac..jsonPacket.sn --..jsonPacket.version..jsonPacket.nmode..jsonPacket.rssi..jsonPacket.uptime..protoSecret local signStr = "" for k,v in pairs(jsonPacket) do --log.info(k,v) signStr = signStr .. v end signStr = signStr .. protoSecret log.info("socketHeartbeatTask.createSign", "signStr:", signStr) local sign = string.upper(crypto.md5(string.urlEncode(signStr),#signStr)) if not sign then log.info("socketHeartbeatTask.createSign","sign not existed!") return false end log.info("socketHeartbeatTask.createSign","sign = "..sign) return true,sign end local function createLoginSign(jsonPacket) if not jsonPacket then log.info("socketHeartbeatTask.createLoginSign","jsonPacket not existed!") return false end local protoSecret = nvm.get("protoSecret") if not protoSecret then log.info("socketHeartbeatTask.createLoginSign","protoSecret not existed!") return false end local signStr = jsonPacket.type..jsonPacket.msgid..jsonPacket.model..jsonPacket.mac..jsonPacket.sn ..jsonPacket.version..jsonPacket.wip..jsonPacket.nmode..jsonPacket.rssi..jsonPacket.serialnum..jsonPacket.uptime..protoSecret log.info("socketHeartbeatTask.createLoginSign", "signStr:", signStr) local sign = string.upper(crypto.md5(string.urlEncode(signStr),#signStr)) if not sign then log.info("socketHeartbeatTask.createLoginSign","sign not existed!") return false end log.info("socketHeartbeatTask.createLoginSign","sign = "..sign) return true,sign end local function createHeartbeatSign(jsonPacket) if not jsonPacket then log.info("socketHeartbeatTask.createHeartbeatSign","jsonPacket not existed!") return false end local protoSecret = nvm.get("protoSecret") if not protoSecret then log.info("socketHeartbeatTask.createHeartbeatSign","protoSecret not existed!") return false end local signStr = jsonPacket.type..jsonPacket.msgid..jsonPacket.mac..jsonPacket.realtime..protoSecret log.info("socketHeartbeatTask.createHeartbeatSign", "signStr:", signStr) local sign = string.upper(crypto.md5(string.urlEncode(signStr),#signStr)) if not sign then log.info("socketHeartbeatTask.createHeartbeatSign","sign not existed!") return false end log.info("socketHeartbeatTask.createHeartbeatSign","sign = "..sign) return true,sign end --组装待发送数据包 local function createPacket( msgType, msgId ) if not msgType then log.info("socketHeartbeatTask.createPacket","msgType not existed!") return false end local devSn = nvm.get("devSn") macAddr = devSn:sub(-12) if not macAddr then log.info("socketHeartbeatTask.createPacket","createPacket fail,macAddr empty!") return false end if #macAddr < 6 then log.info("socketHeartbeatTask.createPacket","createPacket fail,macAddr length < 6! macAddr = ",macAddr) return false end local jsonPacket = {} jsonPacket.type = msgType jsonPacket.msgid = msgId jsonPacket.mac = macAddr jsonPacket.state = net.getState() jsonPacket.nmode = net.getNetMode() jsonPacket.rssi = net.getRssi() jsonPacket.uptime = os.time() jsonPacket.wip = "" jsonPacket.serialnum = "" jsonPacket.sn = nvm.get("moduleSn") or "" jsonPacket.model = nvm.get("model") or "" jsonPacket.version = nvm.get("moduleSoftVersion") or "" local result, sign if msgType == MESSAGE_TYPE_REPORT_CONFIG then result, sign = createSign(jsonPacket) elseif msgType == MESSAGE_TYPE_LOGIN then result, sign = createLoginSign(jsonPacket) elseif msgType == MESSAGE_TYPE_HEARTBEAT then jsonPacket = {} jsonPacket.type = msgType jsonPacket.msgid = msgId jsonPacket.mac = macAddr jsonPacket.realtime = os.time() result, sign = createHeartbeatSign(jsonPacket) else log.info("socketHeartbeatTask.createPacket","invalid msgType! msgType:",msgType) return false end if not result then log.info("socketHeartbeatTask.createPacket","createSign failed!") return false end jsonPacket.sign = sign local jsonEncodePacket = json.encode(jsonPacket) if not jsonEncodePacket then log.info("socketHeartbeatTask.createPacket","jsonPacket encode failed!") return false end return jsonEncodePacket.. '\00' end --等待时间同步成功消息通知 sys.subscribe("TIMER_SYNC_SUCCESS", function ( ... ) log.info("socketHeartbeatTask.subscribe","TIMER_SYNC_SUCCESS") timerSyncResult = true end) local msgId = 0 sys.taskInit(function() local r, s, p local recv_cnt, send_cnt = 0, 0 while true do while not socket.isReady() do log.info("socketHeartbeatTask.main","socket not ready!") sys.wait(1000) end local enableHeartbeat = nvm.get("enableHeartbeat") or 0 while enableHeartbeat == 0 do log.info("socketHeartbeatTask.main","not enable heartbeat! enableHeartbeat:", enableHeartbeat) enableHeartbeat = nvm.get("enableHeartbeat") sys.wait(1000) end while not heartbeatIp do log.info("socketHeartbeatTask.main","heartbeatIp empty!") heartbeatIp = nvm.get("heartbeatIp") sys.wait(1000) end while not heartbeatTcpPort do log.info("socketHeartbeatTask.main","heartbeatTcpPort empty!") heartbeatTcpPort = nvm.get("heartbeatTcpPort") sys.wait(1000) end socketClient = socket.tcp() while not socketClient:connect(heartbeatIp, heartbeatTcpPort) do log.info("socketHeartbeatTask.main","heartbeat server connect failed! heartbeatIp:",heartbeatIp,",heartbeatTcpPort:",heartbeatTcpPort) sys.wait(2000) end --登陆服务端通知 sys.publish("PUB_DEVICE_LOGIN_MSG") while true do local heartbeatInterval = nvm.get("heartbeatInterval") or 120 r, s, p = socketClient:recv(heartbeatInterval*1000, "pub_msg") if r then recv_cnt = recv_cnt + #s log.info("socketHeartbeatTask.main","receive msg:", s:sub(1, 100)) sys.publish("ON_RECEIVE_SERVER_MESSAGE",s:toHex()) elseif s == "pub_msg" then send_cnt = send_cnt + #p log.info("socketHeartbeatTask.main","pub_msg(30):", p:sub(1, 100)) if not socketClient:send(p) then log.error("socketHeartbeatTask.main","send pub_msg packet failed!!") break end elseif s == "timeout" then msgId = msgId + 1 local packet_data = createPacket(MESSAGE_TYPE_HEARTBEAT, msgId) if not packet_data then log.error("socketHeartbeatTask.main","create heartbeat packet failed!!") else if not socketClient:send(packet_data) then log.error("socketHeartbeatTask.main","send heartbeat packet failed!!") break end log.info("socketHeartbeatTask.main","send heartbeat packet success") end else log.info("socketHeartbeatTask.main","socket连接错误!") break end end socketClient:close() end end) sys.subscribe("PUB_DEVICE_LOGIN_MSG", function() msgId = msgId + 1 local packet_data = createPacket(MESSAGE_TYPE_LOGIN, msgId) if not packet_data then log.error("socketHeartbeatTask.createLoginMsg","create login packet failed!!") else log.info("socketHeartbeatTask.createLoginMsg","publish login packet:",packet_data) sys.publish("pub_msg", packet_data) end end) --收到并解析服务端消息回调 local function onReceiveServerMessage(hex) log.info("socketHeartbeatTask.onReceiveServerMessage","hex: ", hex) if not string.find(hex,"00") then log.info("socketHeartbeatTask.onReceiveServerMessage", "format error, end char:0x00 not found! hex:",hex) return false end --解析json连包数据 local parseLen = 0 local tmp_hex = hex while true do log.info("socketHeartbeatTask.onReceiveServerMessage","tmp_hex1:",tmp_hex) local tail = string.find(tmp_hex,"00") if not tail then log.info("socketHeartbeatTask.onReceiveServerMessage","format error, end char:0x00 not found! tmp_hex:",tmp_hex) break end local hex_str = tmp_hex:sub(1,tail-1) log.info("socketHeartbeatTask.onReceiveServerMessage","hex_str:",hex_str) local json_str,errmsg = hex2str(hex_str) if not json_str then log.info("socketHeartbeatTask.onReceiveServerMessage", errmsg, " hex_str:", hex_str) break end log.info("socketHeartbeatTask.onReceiveServerMessage", "json_str:", json_str) local messageJson,result,errinfo = json.decode(json_str) if result and type(messageJson)=="table" then log.info("socketHeartbeatTask.onReceiveServerMessage","publish decode server message") sys.publish("ON_HANDLE_SERVER_MESSAGE",messageJson) else log.info("socketHeartbeatTask.onReceiveServerMessage","testJson.decode error",errinfo) break end parseLen = parseLen + (tail+1) if parseLen >= #hex then log.info("socketHeartbeatTask.onReceiveServerMessage","parse over") break end tmp_hex = tmp_hex:sub(tail+2,-1) log.info("socketHeartbeatTask.onReceiveServerMessage","tmp_hex2:",tmp_hex) end end sys.subscribe("ON_RECEIVE_SERVER_MESSAGE",onReceiveServerMessage) --重置设备配置参数 local function reset_device_config(config) return true end --处理已解析的服务端消息 local function onHandleServerMessage(message) if not message or type(message)~="table" then log.info("socketHeartbeatTask.onHandleMessage","message format error! message:",message) return false end if not message.type then log.info("socketHeartbeatTask.onHandleMessage","message.type not existed!") return false end --心跳服务端响应报文 if message.type ~= MESSAGE_TYPE_HEARTBEAT_RESP then log.info("socketHeartbeatTask.onHandleMessage","invalid message.type!!", os.time(), json.encode(message)) return end log.info("socketHeartbeatTask.onHandleMessage","recv heartbeat response", os.time(), json.encode(message)) if message.num == 0 then return end for i, cmd in ipairs(message.config) do --重启设备 if cmd.subtype == MESSAGE_TYPE_REBOOT_CMD then log.info("socketHeartbeatTask.onHandleMessage","recv reboot command", os.time(), json.encode(message)) --sys.timerStart(function() sys.restart("server_reboot_command") end, 2000) sys.restart("MESSAGE_TYPE_REBOOT_CMD") break end --恢复出厂设备 if cmd.subtype == MESSAGE_TYPE_RESTORE_CMD then log.info("socketHeartbeatTask.onHandleMessage","recv restore command", os.time(), json.encode(message)) nvm.restore() sys.restart("MESSAGE_TYPE_RESTORE_CMD") break end --下发设备配置参数 if cmd.subtype == MESSAGE_TYPE_RESET_CONFIG_CMD then log.info("socketHeartbeatTask.onHandleMessage","recv reset config command", os.time(), json.encode(message)) local res = reset_device_config(cmd) if not res then log.info("socketHeartbeatTask.onHandleMessage","reset device config failed!!") else sys.restart("MESSAGE_TYPE_RESET_CONFIG_CMD") break end end --查询设备配置参数 if cmd.subtype == MESSAGE_TYPE_REPORT_CONFIG_CMD then log.info("socketHeartbeatTask.onHandleMessage","recv report device config command", os.time(), json.encode(message)) sys.publish("MESSAGE_TYPE_REPORT_CONFIG_CMD") end --远程升级 if cmd.subtype == MESSAGE_TYPE_OTA_UPDATE_CMD then log.info("socketHeartbeatTask.onHandleMessage","recv ota update command", os.time(), json.encode(message)) sys.publish("MESSAGE_TYPE_OTA_UPDATE_CMD") end --开启rifd上报 if cmd.subtype == MESSAGE_TYPE_ENABLE_RFID_REPORT then log.info("socketHeartbeatTask.onHandleMessage","recv rfid report command", os.time(), json.encode(message)) if not cmd.maxtime or cmd.maxtime<1 then log.error("socketHeartbeatTask.onHandleMessage","cmd.maxtime invalid!! cmd.maxtime:", cmd.maxtime) else sys.publish("MESSAGE_TYPE_ENABLE_RFID_REPORT",cmd.maxtime) end end end end sys.subscribe("ON_HANDLE_SERVER_MESSAGE",onHandleServerMessage)