socketHeartbeatTask.lua 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. --- testSocket
  2. -- @module testSocket
  3. -- @author AIRM2M
  4. -- @license MIT
  5. -- @copyright openLuat.com
  6. -- @release 2018.10.27
  7. module(..., package.seeall)
  8. require "socket"
  9. require "nvm"
  10. require "net"
  11. -- 此处的IP和端口请填上你自己的socket服务器和端口
  12. local heartbeatIp, heartbeatTcpPort, heartbeatUdpPort = nvm.get("heartbeatIp"), nvm.get("heartbeatTcpPort"), nvm.get("heartbeatUdpPort")
  13. local macAddr = ""
  14. local heartbeatInterval = nvm.get("heartbeatInterval") or 60
  15. local heartbeatRetryInterval = nvm.get("heartbeatRetryInterval") or 1
  16. local heartbeatRetryTimes = nvm.get("heartbeatRetryTimes") or 5
  17. local heartbeatRetrySleep = nvm.get("heartbeatRetrySleep") or 20
  18. local heartbeatWaitRecvMsgMaxTime = nvm.get("heartbeatWaitRecvMsgMaxTime") or 10
  19. local timerSyncResult = false
  20. --运维消息类型配置项
  21. --设备登录(client->server)
  22. local MESSAGE_TYPE_LOGIN = 1
  23. --设备心跳(client->server)
  24. local MESSAGE_TYPE_HEARTBEAT = 3
  25. --开机上报设备配置参数(client->server)
  26. local MESSAGE_TYPE_REPORT_CONFIG = 9
  27. --上报设备配置参数命令响应(client->server)
  28. local MESSAGE_TYPE_REPORT_CONFIG_CMD_RESP = 10
  29. --心跳响应(server->client)
  30. local MESSAGE_TYPE_HEARTBEAT_RESP = 4
  31. --重启设备命令(server->client)
  32. local MESSAGE_TYPE_REBOOT_CMD = 1
  33. --恢复出厂设置命令(server->client)
  34. local MESSAGE_TYPE_RESTORE_CMD = 6
  35. --设置设备配置参数命令(server->client)
  36. local MESSAGE_TYPE_RESET_CMD = 7
  37. --上报设备配置参数命令(server->client)
  38. local MESSAGE_TYPE_REPORT_CONFIG_CMD = 8
  39. --ota升级命令(server->client)
  40. local MESSAGE_TYPE_OTA_UPDATE_CMD = 3
  41. --开启rifd上报
  42. local MESSAGE_TYPE_ENABLE_RFID_REPORT = 9
  43. local function hex2bin( hexstr )
  44. local str = ""
  45. for i = 1, string.len(hexstr) - 1, 2 do
  46. local doublebytestr = string.sub(hexstr, i, i+1);
  47. local n = tonumber(doublebytestr, 16);
  48. if 0 == n then
  49. str = str .. '\00'
  50. else
  51. str = str .. string.format("%c", n)
  52. end
  53. end
  54. return str
  55. end
  56. --将16进制串转换为字符串
  57. local function hex2str(str)
  58. --判断输入类型
  59. if (type(str)~="string") then
  60. return nil,"hex2str invalid input type"
  61. end
  62. --滤掉分隔符
  63. str=str:gsub("[%s%p]",""):upper()
  64. --检查内容是否合法
  65. if(str:find("[^0-9A-Fa-f]")~=nil) then
  66. return nil,"hex2str invalid input content"
  67. end
  68. --检查字符串长度
  69. if(str:len()%2~=0) then
  70. return nil,"hex2str invalid input lenth"
  71. end
  72. --拼接字符串
  73. local index=1
  74. local ret=""
  75. for index=1,str:len(),2 do
  76. ret=ret..string.char(tonumber(str:sub(index,index+1),16))
  77. end
  78. --log.info("socketHeartbeatTask.hex2str", ret)
  79. return ret
  80. end
  81. local function createSign(jsonPacket)
  82. if not jsonPacket then
  83. log.info("socketHeartbeatTask.createSign","jsonPacket not existed!")
  84. return false
  85. end
  86. local protoSecret = nvm.get("protoSecret")
  87. if not protoSecret then
  88. log.info("socketHeartbeatTask.createSign","protoSecret not existed!")
  89. return false
  90. end
  91. --local signStr = jsonPacket.type..jsonPacket.msgid..jsonPacket.model..jsonPacket.mac..jsonPacket.sn
  92. --..jsonPacket.version..jsonPacket.nmode..jsonPacket.rssi..jsonPacket.uptime..protoSecret
  93. local signStr = ""
  94. for k,v in pairs(jsonPacket) do
  95. --log.info(k,v)
  96. signStr = signStr .. v
  97. end
  98. signStr = signStr .. protoSecret
  99. log.info("socketHeartbeatTask.createSign", "signStr:", signStr)
  100. local sign = string.upper(crypto.md5(string.urlEncode(signStr),#signStr))
  101. if not sign then
  102. log.info("socketHeartbeatTask.createSign","sign not existed!")
  103. return false
  104. end
  105. log.info("socketHeartbeatTask.createSign","sign = "..sign)
  106. return true,sign
  107. end
  108. local function createLoginSign(jsonPacket)
  109. if not jsonPacket then
  110. log.info("socketHeartbeatTask.createLoginSign","jsonPacket not existed!")
  111. return false
  112. end
  113. local protoSecret = nvm.get("protoSecret")
  114. if not protoSecret then
  115. log.info("socketHeartbeatTask.createLoginSign","protoSecret not existed!")
  116. return false
  117. end
  118. local signStr = jsonPacket.type..jsonPacket.msgid..jsonPacket.model..jsonPacket.mac..jsonPacket.sn
  119. ..jsonPacket.version..jsonPacket.wip..jsonPacket.nmode..jsonPacket.rssi..jsonPacket.serialnum..jsonPacket.uptime..protoSecret
  120. log.info("socketHeartbeatTask.createLoginSign", "signStr:", signStr)
  121. local sign = string.upper(crypto.md5(string.urlEncode(signStr),#signStr))
  122. if not sign then
  123. log.info("socketHeartbeatTask.createLoginSign","sign not existed!")
  124. return false
  125. end
  126. log.info("socketHeartbeatTask.createLoginSign","sign = "..sign)
  127. return true,sign
  128. end
  129. local function createHeartbeatSign(jsonPacket)
  130. if not jsonPacket then
  131. log.info("socketHeartbeatTask.createHeartbeatSign","jsonPacket not existed!")
  132. return false
  133. end
  134. local protoSecret = nvm.get("protoSecret")
  135. if not protoSecret then
  136. log.info("socketHeartbeatTask.createHeartbeatSign","protoSecret not existed!")
  137. return false
  138. end
  139. local signStr = jsonPacket.type..jsonPacket.msgid..jsonPacket.mac..jsonPacket.realtime..protoSecret
  140. log.info("socketHeartbeatTask.createHeartbeatSign", "signStr:", signStr)
  141. local sign = string.upper(crypto.md5(string.urlEncode(signStr),#signStr))
  142. if not sign then
  143. log.info("socketHeartbeatTask.createHeartbeatSign","sign not existed!")
  144. return false
  145. end
  146. log.info("socketHeartbeatTask.createHeartbeatSign","sign = "..sign)
  147. return true,sign
  148. end
  149. --组装待发送数据包
  150. local function createPacket( msgType, msgId )
  151. if not msgType then
  152. log.info("socketHeartbeatTask.createPacket","msgType not existed!")
  153. return false
  154. end
  155. local devSn = nvm.get("devSn")
  156. macAddr = devSn:sub(-12)
  157. if not macAddr then
  158. log.info("socketHeartbeatTask.createPacket","createPacket fail,macAddr empty!")
  159. return false
  160. end
  161. if #macAddr < 6 then
  162. log.info("socketHeartbeatTask.createPacket","createPacket fail,macAddr length < 6! macAddr = ",macAddr)
  163. return false
  164. end
  165. local jsonPacket = {}
  166. jsonPacket.type = msgType
  167. jsonPacket.msgid = msgId
  168. jsonPacket.mac = macAddr
  169. jsonPacket.state = net.getState()
  170. jsonPacket.nmode = net.getNetMode()
  171. jsonPacket.rssi = net.getRssi()
  172. jsonPacket.uptime = os.time()
  173. jsonPacket.wip = ""
  174. jsonPacket.serialnum = ""
  175. jsonPacket.sn = nvm.get("moduleSn") or ""
  176. jsonPacket.model = nvm.get("model") or ""
  177. jsonPacket.version = nvm.get("moduleSoftVersion") or ""
  178. local result, sign
  179. if msgType == MESSAGE_TYPE_REPORT_CONFIG then
  180. result, sign = createSign(jsonPacket)
  181. elseif msgType == MESSAGE_TYPE_LOGIN then
  182. result, sign = createLoginSign(jsonPacket)
  183. elseif msgType == MESSAGE_TYPE_HEARTBEAT then
  184. jsonPacket = {}
  185. jsonPacket.type = msgType
  186. jsonPacket.msgid = msgId
  187. jsonPacket.mac = macAddr
  188. jsonPacket.realtime = os.time()
  189. result, sign = createHeartbeatSign(jsonPacket)
  190. else
  191. log.info("socketHeartbeatTask.createPacket","invalid msgType! msgType:",msgType)
  192. return false
  193. end
  194. if not result then
  195. log.info("socketHeartbeatTask.createPacket","createSign failed!")
  196. return false
  197. end
  198. jsonPacket.sign = sign
  199. local jsonEncodePacket = json.encode(jsonPacket)
  200. if not jsonEncodePacket then
  201. log.info("socketHeartbeatTask.createPacket","jsonPacket encode failed!")
  202. return false
  203. end
  204. return jsonEncodePacket.. '\00'
  205. end
  206. --等待时间同步成功消息通知
  207. sys.subscribe("TIMER_SYNC_SUCCESS", function ( ... )
  208. log.info("socketHeartbeatTask.subscribe","TIMER_SYNC_SUCCESS")
  209. timerSyncResult = true
  210. end)
  211. local msgId = 0
  212. sys.taskInit(function()
  213. local r, s, p
  214. local recv_cnt, send_cnt = 0, 0
  215. while true do
  216. while not socket.isReady() do
  217. log.info("socketHeartbeatTask.main","socket not ready!")
  218. sys.wait(1000)
  219. end
  220. local enableHeartbeat = nvm.get("enableHeartbeat") or 0
  221. while enableHeartbeat == 0 do
  222. log.info("socketHeartbeatTask.main","not enable heartbeat! enableHeartbeat:", enableHeartbeat)
  223. enableHeartbeat = nvm.get("enableHeartbeat")
  224. sys.wait(1000)
  225. end
  226. while not heartbeatIp do
  227. log.info("socketHeartbeatTask.main","heartbeatIp empty!")
  228. heartbeatIp = nvm.get("heartbeatIp")
  229. sys.wait(1000)
  230. end
  231. while not heartbeatTcpPort do
  232. log.info("socketHeartbeatTask.main","heartbeatTcpPort empty!")
  233. heartbeatTcpPort = nvm.get("heartbeatTcpPort")
  234. sys.wait(1000)
  235. end
  236. socketClient = socket.tcp()
  237. while not socketClient:connect(heartbeatIp, heartbeatTcpPort) do
  238. log.info("socketHeartbeatTask.main","heartbeat server connect failed! heartbeatIp:",heartbeatIp,",heartbeatTcpPort:",heartbeatTcpPort)
  239. sys.wait(2000)
  240. end
  241. --登陆服务端通知
  242. sys.publish("PUB_DEVICE_LOGIN_MSG")
  243. while true do
  244. local heartbeatInterval = nvm.get("heartbeatInterval") or 120
  245. r, s, p = socketClient:recv(heartbeatInterval*1000, "pub_msg")
  246. if r then
  247. recv_cnt = recv_cnt + #s
  248. log.info("socketHeartbeatTask.main","receive msg:", s:sub(1, 100))
  249. sys.publish("ON_RECEIVE_SERVER_MESSAGE",s:toHex())
  250. elseif s == "pub_msg" then
  251. send_cnt = send_cnt + #p
  252. log.info("socketHeartbeatTask.main","pub_msg(30):", p:sub(1, 100))
  253. if not socketClient:send(p) then
  254. log.error("socketHeartbeatTask.main","send pub_msg packet failed!!")
  255. break
  256. end
  257. elseif s == "timeout" then
  258. msgId = msgId + 1
  259. local packet_data = createPacket(MESSAGE_TYPE_HEARTBEAT, msgId)
  260. if not packet_data then
  261. log.error("socketHeartbeatTask.main","create heartbeat packet failed!!")
  262. else
  263. if not socketClient:send(packet_data) then
  264. log.error("socketHeartbeatTask.main","send heartbeat packet failed!!")
  265. break
  266. end
  267. log.info("socketHeartbeatTask.main","send heartbeat packet success")
  268. end
  269. else
  270. log.info("socketHeartbeatTask.main","socket连接错误!")
  271. break
  272. end
  273. end
  274. socketClient:close()
  275. end
  276. end)
  277. sys.subscribe("PUB_DEVICE_LOGIN_MSG", function()
  278. msgId = msgId + 1
  279. local packet_data = createPacket(MESSAGE_TYPE_LOGIN, msgId)
  280. if not packet_data then
  281. log.error("socketHeartbeatTask.createLoginMsg","create login packet failed!!")
  282. else
  283. log.info("socketHeartbeatTask.createLoginMsg","publish login packet:",packet_data)
  284. sys.publish("pub_msg", packet_data)
  285. end
  286. end)
  287. --收到并解析服务端消息回调
  288. local function onReceiveServerMessage(hex)
  289. log.info("socketHeartbeatTask.onReceiveServerMessage","hex: ", hex)
  290. if not string.find(hex,"00") then
  291. log.info("socketHeartbeatTask.onReceiveServerMessage", "format error, end char:0x00 not found! hex:",hex)
  292. return false
  293. end
  294. --解析json连包数据
  295. local parseLen = 0
  296. local tmp_hex = hex
  297. while true do
  298. log.info("socketHeartbeatTask.onReceiveServerMessage","tmp_hex1:",tmp_hex)
  299. local tail = string.find(tmp_hex,"00")
  300. if not tail then
  301. log.info("socketHeartbeatTask.onReceiveServerMessage","format error, end char:0x00 not found! tmp_hex:",tmp_hex)
  302. break
  303. end
  304. local hex_str = tmp_hex:sub(1,tail-1)
  305. log.info("socketHeartbeatTask.onReceiveServerMessage","hex_str:",hex_str)
  306. local json_str,errmsg = hex2str(hex_str)
  307. if not json_str then
  308. log.info("socketHeartbeatTask.onReceiveServerMessage", errmsg, " hex_str:", hex_str)
  309. break
  310. end
  311. log.info("socketHeartbeatTask.onReceiveServerMessage", "json_str:", json_str)
  312. local messageJson,result,errinfo = json.decode(json_str)
  313. if result and type(messageJson)=="table" then
  314. log.info("socketHeartbeatTask.onReceiveServerMessage","publish decode server message")
  315. sys.publish("ON_HANDLE_SERVER_MESSAGE",messageJson)
  316. else
  317. log.info("socketHeartbeatTask.onReceiveServerMessage","testJson.decode error",errinfo)
  318. break
  319. end
  320. parseLen = parseLen + (tail+1)
  321. if parseLen >= #hex then
  322. log.info("socketHeartbeatTask.onReceiveServerMessage","parse over")
  323. break
  324. end
  325. tmp_hex = tmp_hex:sub(tail+2,-1)
  326. log.info("socketHeartbeatTask.onReceiveServerMessage","tmp_hex2:",tmp_hex)
  327. end
  328. end
  329. sys.subscribe("ON_RECEIVE_SERVER_MESSAGE",onReceiveServerMessage)
  330. --重置设备配置参数
  331. local function reset_device_config(config)
  332. return true
  333. end
  334. --处理已解析的服务端消息
  335. local function onHandleServerMessage(message)
  336. if not message or type(message)~="table" then
  337. log.info("socketHeartbeatTask.onHandleMessage","message format error! message:",message)
  338. return false
  339. end
  340. if not message.type then
  341. log.info("socketHeartbeatTask.onHandleMessage","message.type not existed!")
  342. return false
  343. end
  344. --心跳服务端响应报文
  345. if message.type ~= MESSAGE_TYPE_HEARTBEAT_RESP then
  346. log.info("socketHeartbeatTask.onHandleMessage","invalid message.type!!", os.time(), json.encode(message))
  347. return
  348. end
  349. log.info("socketHeartbeatTask.onHandleMessage","recv heartbeat response", os.time(), json.encode(message))
  350. if message.num == 0 then
  351. return
  352. end
  353. for i, cmd in ipairs(message.config) do
  354. --重启设备
  355. if cmd.subtype == MESSAGE_TYPE_REBOOT_CMD then
  356. log.info("socketHeartbeatTask.onHandleMessage","recv reboot command", os.time(), json.encode(message))
  357. --sys.timerStart(function() sys.restart("server_reboot_command") end, 2000)
  358. sys.restart("MESSAGE_TYPE_REBOOT_CMD")
  359. break
  360. end
  361. --恢复出厂设备
  362. if cmd.subtype == MESSAGE_TYPE_RESTORE_CMD then
  363. log.info("socketHeartbeatTask.onHandleMessage","recv restore command", os.time(), json.encode(message))
  364. nvm.restore()
  365. sys.restart("MESSAGE_TYPE_RESTORE_CMD")
  366. break
  367. end
  368. --下发设备配置参数
  369. if cmd.subtype == MESSAGE_TYPE_RESET_CONFIG_CMD then
  370. log.info("socketHeartbeatTask.onHandleMessage","recv reset config command", os.time(), json.encode(message))
  371. local res = reset_device_config(cmd)
  372. if not res then
  373. log.info("socketHeartbeatTask.onHandleMessage","reset device config failed!!")
  374. else
  375. sys.restart("MESSAGE_TYPE_RESET_CONFIG_CMD")
  376. break
  377. end
  378. end
  379. --查询设备配置参数
  380. if cmd.subtype == MESSAGE_TYPE_REPORT_CONFIG_CMD then
  381. log.info("socketHeartbeatTask.onHandleMessage","recv report device config command", os.time(), json.encode(message))
  382. sys.publish("MESSAGE_TYPE_REPORT_CONFIG_CMD")
  383. end
  384. --远程升级
  385. if cmd.subtype == MESSAGE_TYPE_OTA_UPDATE_CMD then
  386. log.info("socketHeartbeatTask.onHandleMessage","recv ota update command", os.time(), json.encode(message))
  387. sys.publish("MESSAGE_TYPE_OTA_UPDATE_CMD")
  388. end
  389. --开启rifd上报
  390. if cmd.subtype == MESSAGE_TYPE_ENABLE_RFID_REPORT then
  391. log.info("socketHeartbeatTask.onHandleMessage","recv rfid report command", os.time(), json.encode(message))
  392. if not cmd.maxtime or cmd.maxtime<1 then
  393. log.error("socketHeartbeatTask.onHandleMessage","cmd.maxtime invalid!! cmd.maxtime:", cmd.maxtime)
  394. else
  395. sys.publish("MESSAGE_TYPE_ENABLE_RFID_REPORT",cmd.maxtime)
  396. end
  397. end
  398. end
  399. end
  400. sys.subscribe("ON_HANDLE_SERVER_MESSAGE",onHandleServerMessage)