123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438 |
- --- 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)
|