update.lua 9.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. --- 模块功能:远程升级.
  2. -- @module update
  3. -- @author openLuat
  4. -- @license MIT
  5. -- @copyright openLuat
  6. -- @release 2018.03.29
  7. require "misc"
  8. require "http"
  9. require "log"
  10. require "common"
  11. module(..., package.seeall)
  12. local sUpdating,sCbFnc,sUrl,sPeriod,sRedir,sLocation,fotastart
  13. local sProcessedLen = 0
  14. --local sBraekTest = 0
  15. local httpRspCode
  16. local sGetImeiFnc,sDownloadProcessFnc
  17. local updateMsg
  18. local otaBegin
  19. local function httpDownloadCbFnc(result,statusCode,head)
  20. log.info("update.httpDownloadCbFnc",result,statusCode,head,sCbFnc,sPeriod)
  21. sys.publish("UPDATE_DOWNLOAD",result,statusCode,head)
  22. end
  23. local function processOta(stepData,totalLen,statusCode)
  24. if stepData and totalLen then
  25. if statusCode=="200" or statusCode=="206" then
  26. if not otaBegin then sys.publish("LIB_UPDATE_OTA_DOWNLOAD_BEGIN") otaBegin=true end
  27. local fotaProcessStatus=rtos.fota_process((sProcessedLen+stepData:len()>totalLen) and stepData:sub(1,totalLen-sProcessedLen) or stepData,totalLen)
  28. if fotaProcessStatus~=0 then
  29. log.error("update.processOta","fail",fotaProcessStatus,"failFotaProcessStatus")
  30. log.error("update.processOta","get_fs_free_size: ",rtos.get_fs_free_size()," Bytes")
  31. sys.publish("LIB_UPDATE_OTA_DOWNLOAD_END",false)
  32. return false
  33. else
  34. sProcessedLen = sProcessedLen + stepData:len()
  35. if sDownloadProcessFnc then sDownloadProcessFnc(sProcessedLen*100/totalLen) end
  36. log.info("update.processOta",totalLen,sProcessedLen,(sProcessedLen*100/totalLen).."%")
  37. --if sProcessedLen*100/totalLen==sBraekTest then return false end
  38. if sProcessedLen*100/totalLen>=100 then sys.publish("LIB_UPDATE_OTA_DOWNLOAD_END",true) return true end
  39. end
  40. elseif statusCode:sub(1,1)~="3" and stepData:len()==totalLen and totalLen>0 then
  41. if totalLen<=200 then
  42. local msg = stepData:match("\"msg\":%s*\"(.-)\"")
  43. if msg and msg:len()<=200 then
  44. updateMsg = common.ucs2beToUtf8((msg:gsub("\\u","")):fromHex())
  45. log.warn("update.error",updateMsg)
  46. end
  47. end
  48. httpRspCode = stepData:match("\"code\":%s*(%d+)")
  49. end
  50. end
  51. end
  52. function clientTask()
  53. sUpdating = true
  54. --不要省略此处代码,否则下文中的misc.getImei有可能获取不到
  55. while not socket.isReady() do sys.waitUntil("IP_READY_IND") end
  56. while true do
  57. local retryCnt = 0
  58. sProcessedLen = 0
  59. otaBegin = false
  60. updateMsg = nil
  61. while true do
  62. --sBraekTest = sBraekTest+30
  63. log.info("update.http.request",sLocation,sUrl,sProcessedLen,sBraekTest,fotastart)
  64. if not fotastart then break end
  65. local coreVer = rtos.get_version()
  66. local coreName1,coreName2 = coreVer:match("(.-)_V%d+(_.+)")
  67. local coreVersion = tonumber(coreVer:match(".-_V(%d+)"))
  68. httpRspCode = nil
  69. -- 合宙云平台升级地址
  70. local iotURL="iot.openluat.com/api/site/firmware_upgrade"
  71. -- 模块信息
  72. local moduleInfo="?project_key=".._G.PRODUCT_KEY
  73. .."&imei="..(sGetImeiFnc and sGetImeiFnc() or misc.getImei())
  74. .."&firmware_name=".._G.PROJECT.."_"..coreName1..coreName2
  75. .."&core_version="..coreVersion
  76. .."&dfota=1&version=".._G.VERSION..(sRedir and "&need_oss_url=1" or "")
  77. -- 如果自定义升级地址前三位为“###”,则不拼接模块信息
  78. if sUrl and string.sub(sUrl,1,3)=="###" then
  79. log.info("1-3",string.sub(sUrl,1,3))
  80. log.info("3-0",string.sub(sUrl,4))
  81. customizeUrl=string.sub(sUrl,4)
  82. elseif sUrl then
  83. customizeUrl=sUrl..moduleInfo
  84. else
  85. -- 默认向合宙云平台地址拼接模块信息
  86. iotURL=iotURL..moduleInfo
  87. end
  88. http.request("GET",
  89. sLocation or (customizeUrl or iotURL),
  90. nil,{["Range"]="bytes="..sProcessedLen.."-"},nil,60000,httpDownloadCbFnc,processOta)
  91. local _,result,statusCode,head = sys.waitUntil("UPDATE_DOWNLOAD")
  92. log.info("update.waitUntil UPDATE_DOWNLOAD",result,statusCode,httpRspCode)
  93. if result then
  94. local needBreak
  95. if statusCode=="200" or statusCode=="206" then
  96. needBreak = true
  97. local check = rtos.fota_end()
  98. log.info("update.rtos.fota_end", check)
  99. if sCbFnc then
  100. if check == 0 then
  101. sCbFnc(true)
  102. else
  103. sCbFnc(false)
  104. end
  105. else
  106. if check == 0 then
  107. sys.restart("UPDATE_DOWNLOAD_SUCCESS")
  108. end
  109. end
  110. elseif statusCode:sub(1,1)=="3" and head and head["Location"] then
  111. sLocation = head["Location"]
  112. sys.wait(2000)
  113. elseif httpRspCode=="43" then
  114. log.info("update.clientTask","wait server create fota")
  115. sys.wait(30000)
  116. else
  117. log.info("update.rtos.fota_end",rtos.fota_end())
  118. if sCbFnc then sCbFnc(false) end
  119. needBreak = true
  120. end
  121. if needBreak then
  122. break
  123. end
  124. else
  125. retryCnt = retryCnt+1
  126. if retryCnt==30 then
  127. rtos.fota_end()
  128. if sCbFnc then sCbFnc(false) end
  129. break
  130. end
  131. end
  132. end
  133. sProcessedLen = 0
  134. if sPeriod then
  135. sys.wait(sPeriod)
  136. if rtos.fota_start()~=0 then
  137. log.error("update.request","fota_start fail")
  138. fotastart = false
  139. else
  140. fotastart = true
  141. end
  142. else
  143. break
  144. end
  145. end
  146. sUpdating = false
  147. end
  148. --- 启动远程升级功能
  149. -- @function[opt=nil] cbFnc 每次执行远程升级功能后的回调函数,回调函数的调用形式为:
  150. -- cbFnc(result),result为true表示升级包下载成功,其余表示下载失败
  151. --如果没有设置此参数,则升级包下载成功后,会自动重启
  152. -- @string[opt=nil] url 使用http的get命令下载升级包的url,如果没有设置此参数,默认使用Luatiot平台的url
  153. -- 如果用户设置了url,注意:仅传入完整url的前半部分(如果有参数,即传入?前一部分),http.lua会自动添加?以及后面的参数,例如:
  154. -- 设置的url="www.userserver.com/api/site/firmware_upgrade",则http.lua会在此url后面补充下面的参数
  155. -- "?project_key=".._G.PRODUCT_KEY
  156. -- .."&imei="..misc.getimei()
  157. -- .."&device_key="..misc.getsn()
  158. -- .."&firmware_name=".._G.PROJECT.."_"..rtos.get_version().."&version=".._G.VERSION
  159. -- 如果用户设置了url,且url前面增加三个井号"###",http.lua会自动忽略"###"并以用户填入的url作为请求地址,不会自动添加模块信息,例如:
  160. -- 设置的url="###www.userserver.com"/api/site/firmware_upgrade?customparam=test",则http.lua会将此url开头的"###"忽略,并以此url为地址进行请求
  161. -- "www.userserver.com"/api/site/firmware_upgrade?customparam=test"
  162. -- 如果redir设置为true,还会补充.."&need_oss_url=1"
  163. -- @number[opt=nil] period 单位毫秒,定时启动远程升级功能的间隔,如果没有设置此参数,仅执行一次远程升级功能
  164. -- @bool[opt=nil] redir 是否访问重定向到阿里云的升级包,使用Luat提供的升级服务器时,此参数才有意义
  165. -- 为了缓解Luat的升级服务器压力,从2018年7月11日起,在iot.openluat.com新增或者修改升级包的升级配置时,升级文件会备份一份到阿里云服务器
  166. -- 如果此参数设置为true,会从阿里云服务器下载升级包;如果此参数设置为false或者nil,仍然从Luat的升级服务器下载升级包
  167. -- @return nil
  168. -- @usage
  169. -- update.request()
  170. -- update.request(cbFnc)
  171. -- update.request(cbFnc,"www.userserver.com/update")
  172. -- update.request(cbFnc,nil,4*3600*1000)
  173. -- update.request(cbFnc,nil,4*3600*1000,true)
  174. function request(cbFnc,url,period,redir)
  175. if rtos.fota_start()~=0 then
  176. log.error("update.request","fota_start fail")
  177. fotastart = false
  178. return
  179. else
  180. fotastart = true
  181. end
  182. sCbFnc,sUrl,sPeriod,sRedir = cbFnc or sCbFnc,url or sUrl,period or sPeriod,sRedir or redir
  183. log.info("update.request",sCbFnc,sUrl,sPeriod,sRedir)
  184. if not sUpdating then
  185. sys.taskInit(clientTask)
  186. end
  187. end
  188. function setGetImeiCbFnc(cbFnc)
  189. sGetImeiFnc = cbFnc
  190. end
  191. --- 设置升级包下载过程中的下载进度通知回调函数
  192. -- @function cbFnc 下载进度通知回调函数,回调函数的调用形式如下:
  193. -- cbFnc(step)
  194. -- step表示下载进度:取值范围是0到100,下载进度更新很快,建议在回调函数中,每隔5或者10执行一次实际动作
  195. -- @return nil
  196. -- @usage update.setDownloadProcessCbFnc(function(step) end)
  197. function setDownloadProcessCbFnc(cbFnc)
  198. sDownloadProcessFnc = cbFnc
  199. end
  200. --- 获取请求升级包时服务器返回的信息
  201. -- @return updateMsg, 若没有请求升级或服务器未返回相关信息,则返回值为nil,否则返回服务器返回的相关信息
  202. -- @usage local msg = getUpdateMsg()
  203. function getUpdateMsg()
  204. return updateMsg
  205. end