update_device.py 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import getopt
  4. import time
  5. import uuid
  6. import requests
  7. import sys
  8. import os
  9. PROJECT_ROOT = os.path.join(os.path.abspath(os.path.split(os.path.realpath(__file__))[0] + "/.."), '..')
  10. sys.path.insert(0, PROJECT_ROOT)
  11. def translate_driver_code(driver_code):
  12. if driver_code == '100205':
  13. return '100210'
  14. return driver_code
  15. def map_code(driver_code):
  16. if driver_code == '100205' or driver_code == '100210':
  17. return ['100205', '100210']
  18. else:
  19. return [driver_code]
  20. def valid_code(driver_code, registerd_code):
  21. code_map = map_code(driver_code)
  22. return registerd_code in code_map
  23. try:
  24. options, args = getopt.getopt(sys.argv[1:], 'd:v:s:e:m:r:p:b:d:a:f:',
  25. ['driver=', 'version=', 'server=', 'env=', 'max-count=', 'platform-version=',
  26. 'platform=', 'parallel=', 'dealer=', 'agent=', 'postfix='])
  27. except getopt.GetoptError as e:
  28. print(str(e))
  29. sys.exit()
  30. upgrade_version = ''
  31. system_env = 'testing'
  32. max_count = 10
  33. platform_version = ''
  34. platform = ''
  35. parallel = 5
  36. server = ''
  37. dealer = None
  38. agent = None
  39. postfix = ''
  40. driver_code = ''
  41. def get_fw_url_tmpl(server, platform, platform_version):
  42. if platform == '8955':
  43. fw_url_tmpl = 'http://{server}/uploaded/version/2g/SmartBox_{version}_Luat_V{platform_version}_{platform}_SSL'.format(
  44. server = server,
  45. version = upgrade_version,
  46. platform_version = '{0:0>4}'.format(platform_version),
  47. platform = platform)
  48. elif platform == 'ASR1802':
  49. fw_url_tmpl = 'http://{server}/uploaded/version/4g/SmartBox4G_{version}_Luat_V{platform_version}_{platform}_720D'.format(
  50. server = server,
  51. version = upgrade_version,
  52. platform_version = '{0:0>4}'.format(platform_version),
  53. platform = platform)
  54. else:
  55. assert False, 'incorrect platform type.'
  56. fw_url_tmpl = fw_url_tmpl + '_{driver_code}'
  57. if postfix:
  58. fw_url_tmpl = fw_url_tmpl + '_' + postfix
  59. if platform == 'ASR1802':
  60. fw_url_tmpl = fw_url_tmpl + '_{full}'
  61. fw_url_tmpl = fw_url_tmpl + '.bin'
  62. return fw_url_tmpl
  63. for name, value in options:
  64. if name in ('-v', '--version'):
  65. upgrade_version = value
  66. if name in ('-e', '--env'):
  67. system_env = value
  68. if name in ('-m', '--max-count'):
  69. max_count = int(value)
  70. if name in ('-r', '--platform-version'):
  71. platform_version = value
  72. if name in ('-p', '--platform'):
  73. platform = value
  74. if name in ('-b', '--parallel'):
  75. parallel = int(value)
  76. if name in ('-s', '--server'):
  77. server = value
  78. if name in ('-d', '--dealer'):
  79. dealer = value
  80. if name in ('-a', '--agent'):
  81. agent = value
  82. if name in ('-f', '--postfix'):
  83. postfix = value
  84. if name in ('-d', '--driver'):
  85. driver_code = translate_driver_code(value)
  86. print 'to do driver code is {}, translate driver code is {}'.format(value, driver_code)
  87. if not server:
  88. print 'server is null.'
  89. sys.exit(2)
  90. if not platform_version or not platform:
  91. print 'not assign platform info.'
  92. sys.exit(2)
  93. if platform not in ('8955', 'ASR1802'):
  94. print 'incorrect platform type.'
  95. sys.exit(2)
  96. if not upgrade_version:
  97. print 'error version = {version}'.format(version = upgrade_version)
  98. sys.exit(2)
  99. if not driver_code:
  100. print 'not assign driver code parameter.'
  101. sys.exit(2)
  102. master, major, minor = upgrade_version.split('.')
  103. if not master or not major or not minor:
  104. print 'error version = {version}'.format(version = upgrade_version)
  105. sys.exit(2)
  106. if not system_env:
  107. print 'error system env = {env}'.format(env = system_env)
  108. sys.exit(2)
  109. import os
  110. os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'configs.{env}'.format(env = system_env))
  111. from django.conf import settings
  112. from script.base import init_env
  113. import simplejson as json
  114. from script.device_upgrade import DeviceUpgradeLog
  115. init_env(interactive = False)
  116. from apps.web.core.networking import MessageSender
  117. from apps.web.dealer.models import Dealer
  118. from apps.web.device.models import Device, DeviceDict
  119. from apps.web.constant import Const, DeviceCmdCode, DeviceOnlineStatus
  120. from apps.web.core.mqtt_client import MqttClient
  121. version_regex = 'v{master}\.{major}\.'.format(master = master, major = major)
  122. version_check = 'v{master}.{major}.'.format(master = master, major = major)
  123. upgrade_soft_ver = 'v{version}'.format(version = upgrade_version)
  124. if platform == 'ASR1802':
  125. upgrade_core_ver = 'Luat_V{platform_version}_{platform}_720D'.format(
  126. platform_version = '{0:0>4}'.format(platform_version),
  127. platform = platform)
  128. else:
  129. upgrade_core_ver = 'Luat_V{platform_version}_{platform}_SSL'.format(
  130. platform_version = '{0:0>4}'.format(platform_version),
  131. platform = platform)
  132. fw_url_tmpl = get_fw_url_tmpl(server, platform, platform_version)
  133. driver_code_list = map_code(driver_code)
  134. update_key = DeviceUpgradeLog.make_update_key(upgrade_core_ver, upgrade_soft_ver)
  135. print 'version regex is: {}'.format(version_regex)
  136. print 'version check is: {}'.format(version_check)
  137. print 'upgrade soft version is: {}'.format(upgrade_soft_ver)
  138. print 'fw url tmpl is: {}'.format(fw_url_tmpl)
  139. print 'driver code is: {}'.format(driver_code)
  140. print 'driver code list is: {}'.format(driver_code_list)
  141. print 'update key is: {}'.format(update_key)
  142. mqttc1883 = None
  143. mqttc1884 = None
  144. doing_dict = {}
  145. exists_code = set()
  146. no_exists_code = set()
  147. try:
  148. def on_connect(client, userdata, flags, rc):
  149. pass
  150. def on_message(mqttc, obj, msg):
  151. # type: (MqttClient, obj, json)->None
  152. msgDict = json.loads(bytes.decode(msg.payload))
  153. imei = msgDict['IMEI']
  154. print 'msg dict is: {}'.format(msgDict)
  155. log = DeviceUpgradeLog.objects(
  156. updateKey = update_key,
  157. devNo = imei
  158. ).first() # type: DeviceUpgradeLog
  159. if not log:
  160. print 'not has log record'
  161. if msgDict['cmd'] == 209:
  162. print('209 has received. msg = %s' % str(msgDict))
  163. if msgDict['result']:
  164. if log:
  165. log.set_stauts(DeviceUpgradeLog.Status.UPGRADED)
  166. else:
  167. if log:
  168. log.set_stauts(DeviceUpgradeLog.Status.FAILURE)
  169. mqttc.unsubscribe('server/%s/209' % imei)
  170. doing_dict.pop(imei, None)
  171. elif msgDict['cmd'] == 200:
  172. if msgDict['soft_ver'] == upgrade_soft_ver:
  173. log.set_stauts(DeviceUpgradeLog.Status.SUCCESS)
  174. else:
  175. log.set_stauts(DeviceUpgradeLog.Status.FAILURE)
  176. mqttc.unsubscribe('server/%s/200' % imei)
  177. def on_disconnect(client, userdata, self):
  178. print('exit. client = %s' % str(client))
  179. mqttc1883 = MqttClient(client_id = 'webapp_' + str(uuid.uuid1()))
  180. try:
  181. mqttc1883.on_message = on_message
  182. mqttc1883.on_connect = on_connect
  183. mqttc1883.on_disconnect = on_disconnect
  184. mqttc1883.username_pw_set(settings.MQTT_USER, settings.MQTT_PSWD)
  185. mqttc1883.connect(settings.MQTT_HOSTNAME, 1883, 60)
  186. mqttc1883.loop_start()
  187. except Exception as e:
  188. print(e)
  189. mqttc1884 = MqttClient(client_id = 'webapp_' + str(uuid.uuid1()))
  190. try:
  191. mqttc1884.on_message = on_message
  192. mqttc1884.on_connect = on_connect
  193. mqttc1884.on_disconnect = on_disconnect
  194. mqttc1884.username_pw_set(settings.MQTT_USER, settings.MQTT_PSWD)
  195. mqttc1884.connect(settings.MQTT_HOSTNAME, 1884, 60)
  196. mqttc1884.loop_start()
  197. except Exception as e:
  198. print(e)
  199. if dealer:
  200. dealers = [dealer]
  201. elif agent:
  202. dealers = [dealer['_id'] for dealer in Dealer.get_collection().find({'agentId': agent})]
  203. else:
  204. dealers = None
  205. if driver_code != '000000':
  206. common_filter = {
  207. 'driverCode': {'$in': driver_code_list}
  208. }
  209. else:
  210. common_filter = {}
  211. if version_check == 'v1.8.':
  212. filter = {
  213. '$and': [
  214. {
  215. '$or': [
  216. {'softVer': 'v1.5'},
  217. {'softVer': 'v1.7'},
  218. {'softVer': {'$regex': 'v1\.5\.'}},
  219. {'softVer': {'$regex': 'v1\.7.'}},
  220. {'softVer': {'$regex': version_regex}}]
  221. },
  222. {
  223. 'softVer': {'$ne': upgrade_soft_ver}
  224. }
  225. ]
  226. }
  227. filter.update(common_filter)
  228. if dealers:
  229. filter.update({
  230. 'ownerId': {'$in': dealers}
  231. })
  232. elif version_check == 'v5.0.':
  233. filter = {
  234. '$and': [
  235. {
  236. '$or': [{'softVer': {'$regex': 'v4\.0\.'}},
  237. {'softVer': {'$regex': 'v3\.0\.'}},
  238. {'softVer': {'$regex': version_regex}}]
  239. },
  240. {
  241. 'softVer': {'$ne': upgrade_soft_ver}
  242. }
  243. ]
  244. }
  245. filter.update(common_filter)
  246. if dealers:
  247. filter.update({
  248. 'ownerId': {'$in': dealers}
  249. })
  250. elif version_check == 'v5.13.':
  251. filter = {
  252. '$and': [
  253. {
  254. '$or': [{'softVer': {'$regex': 'v3\.1\.'}},
  255. {'softVer': {'$regex': 'v4\.1\.'}},
  256. {'softVer': {'$regex': version_regex}}]
  257. },
  258. {
  259. 'softVer': {'$ne': upgrade_soft_ver}
  260. }
  261. ]
  262. }
  263. filter.update(common_filter)
  264. if dealers:
  265. filter.update({
  266. 'ownerId': {'$in': dealers}
  267. })
  268. elif version_check == 'v5.1.':
  269. filter = {
  270. '$and': [
  271. {
  272. '$or': [{'softVer': {'$regex': 'v40\.1\.'}}, {'softVer': {'$regex': version_regex}}]
  273. },
  274. {
  275. 'softVer': {'$ne': upgrade_soft_ver}
  276. }
  277. ]
  278. }
  279. filter.update(common_filter)
  280. if dealers:
  281. filter.update({
  282. 'ownerId': {'$in': dealers}
  283. })
  284. elif version_check == 'v5.12.':
  285. filter = {
  286. '$and': [
  287. {
  288. '$or': [{'softVer': {'$regex': 'v4\.12\.'}}, {'softVer': {'$regex': version_regex}}]
  289. },
  290. {
  291. 'softVer': {'$ne': upgrade_soft_ver}
  292. }
  293. ]
  294. }
  295. filter.update(common_filter)
  296. if dealers:
  297. filter.update({
  298. 'ownerId': {'$in': dealers}
  299. })
  300. else:
  301. filter = {
  302. '$and': [{'softVer': {'$regex': version_regex}}, {'softVer': {'$ne': upgrade_soft_ver}}]
  303. }
  304. filter.update(common_filter)
  305. if dealers:
  306. filter.update({
  307. 'ownerId': {'$in': dealers}
  308. })
  309. objs = Device.get_collection().find(filter).limit(10000)
  310. count = 0
  311. # 做一下保护, 避免查询语句错误
  312. devNoList = []
  313. for obj in objs:
  314. now_soft_ver = str(obj['softVer'])
  315. dev_no = str(obj['devNo'])
  316. exist_log = DeviceUpgradeLog.objects(updateKey = update_key, devNo = dev_no).first() # type: DeviceUpgradeLog
  317. if exist_log:
  318. print 'ignore this round for dev<{}>'.format(dev_no)
  319. if now_soft_ver == upgrade_soft_ver:
  320. exist_log.set_stauts(DeviceUpgradeLog.Status.SUCCESS)
  321. continue
  322. need_upgrade = True
  323. try:
  324. common_flag = (now_soft_ver.startswith(version_check) and now_soft_ver != upgrade_soft_ver)
  325. if version_check == 'v1.8.':
  326. if now_soft_ver.startswith('v1.7.') or now_soft_ver.startswith(
  327. 'v1.5.') or now_soft_ver == 'v1.7' or now_soft_ver == 'v1.5' or common_flag:
  328. devNoList.append(dev_no)
  329. continue
  330. elif version_check == 'v5.0.':
  331. if now_soft_ver.startswith('v4.0.') or now_soft_ver.startswith('v3.0.') or common_flag:
  332. devNoList.append(dev_no)
  333. continue
  334. elif version_check == 'v5.1.':
  335. if now_soft_ver.startswith('v40.1.') or common_flag:
  336. devNoList.append(dev_no)
  337. continue
  338. elif version_check == 'v5.12.':
  339. if now_soft_ver.startswith('v4.12.') or common_flag:
  340. devNoList.append(dev_no)
  341. continue
  342. elif version_check == 'v5.13.':
  343. if now_soft_ver.startswith('v3.1.') or now_soft_ver.startswith('v4.1.') or common_flag:
  344. devNoList.append(dev_no)
  345. continue
  346. else:
  347. if common_flag:
  348. devNoList.append(dev_no)
  349. continue
  350. need_upgrade = False
  351. finally:
  352. if not need_upgrade:
  353. print 'dev<devNo={},rCode={},code={}> version is: {}. no need to upgrade'.format(dev_no,
  354. obj.get('devType',
  355. {}).get(
  356. 'code', ''),
  357. obj.get('driverCode',
  358. ''),
  359. now_soft_ver)
  360. else:
  361. print 'dev<devNo={},rCode={},code={}> version is: {}. need to upgrade.'.format(dev_no,
  362. obj.get('devType',
  363. {}).get(
  364. 'code', None),
  365. obj.get('driverCode',
  366. ''),
  367. now_soft_ver)
  368. for devNo in devNoList:
  369. try:
  370. if max_count != -1 and count >= max_count:
  371. print 'max count reach.'
  372. break
  373. dev = Device.get_dev(devNo) # type: DeviceDict
  374. if dev.online != DeviceOnlineStatus.DEV_STATUS_ONLINE:
  375. print '{} is offline.'.format(devNo)
  376. continue
  377. if driver_code != '000000':
  378. if 'driverCode' not in dev or not dev['driverCode']:
  379. print '{} has no driver code.'.format(devNo)
  380. if dev['driverCode'] not in driver_code_list:
  381. print '{} of {} is not my driver code.'.format(dev['driverCode'], devNo)
  382. continue
  383. if driver_code in no_exists_code:
  384. print '{} not have version.'.format(driver_code)
  385. continue
  386. if ':1884' in dev['server']:
  387. mqttc1884.subscribe('server/%s/209' % devNo, Const.MQTT_QOS)
  388. mqttc1884.subscribe('server/%s/200' % devNo, Const.MQTT_QOS)
  389. elif ':1883' in dev['server']:
  390. mqttc1883.subscribe('server/%s/209' % devNo, Const.MQTT_QOS)
  391. mqttc1883.subscribe('server/%s/200' % devNo, Const.MQTT_QOS)
  392. else:
  393. print('%s %s %s\n' % (str(dev['devNo']), str(dev['logicalCode']), str(dev['softVer'])))
  394. continue
  395. if platform == 'ASR1802':
  396. if upgrade_core_ver == dev['coreVer']:
  397. version_path = fw_url_tmpl.format(driver_code = driver_code, full = 'inc')
  398. else:
  399. version_path = fw_url_tmpl.format(driver_code = driver_code, full = 'full')
  400. else:
  401. version_path = fw_url_tmpl.format(driver_code = driver_code)
  402. print 'version path is: {}'.format(version_path)
  403. if driver_code not in exists_code:
  404. r = requests.get(version_path, timeout = 15)
  405. if r.status_code == 404:
  406. print '{} version is not exist'.format(driver_code)
  407. no_exists_code.add(driver_code)
  408. continue
  409. else:
  410. exists_code.add(version_path)
  411. cmdPara = {'cmd': DeviceCmdCode.SET_DEVINFO, 'IMEI': devNo, 'ota_set': {'fw_url': version_path}}
  412. print cmdPara
  413. try:
  414. log = DeviceUpgradeLog.new_log(dev = dev,
  415. coreVer = upgrade_core_ver,
  416. softVer = upgrade_soft_ver,
  417. driverCode = driver_code,
  418. updatePara = cmdPara)
  419. except Exception, e:
  420. print str(e)
  421. continue
  422. result = MessageSender.send(device = dev, cmd = DeviceCmdCode.SET_DEVINFO, payload = cmdPara, timeout = 15)
  423. if result['rst'] != 0:
  424. log.set_stauts(DeviceUpgradeLog.Status.FAILURE)
  425. continue
  426. else:
  427. count = count + 1
  428. log.set_stauts(DeviceUpgradeLog.Status.RUNNING)
  429. doing_dict[devNo] = int(time.time())
  430. while True:
  431. if len(doing_dict) > parallel:
  432. print('queue is full.')
  433. for imei in list(doing_dict.keys()):
  434. start_time = doing_dict[imei]
  435. if (int(time.time()) - start_time) > 5 * 60:
  436. doing_dict.pop(imei, None)
  437. time.sleep(5)
  438. else:
  439. print('queue is not full')
  440. break
  441. except Exception, e:
  442. print 'some exception =%s' % e
  443. finally:
  444. while len(doing_dict) > 0:
  445. for imei in list(doing_dict.keys()):
  446. start_time = doing_dict[imei]
  447. if (int(time.time()) - start_time) > 5 * 60:
  448. doing_dict.pop(imei, None)
  449. time.sleep(1)
  450. if mqttc1883:
  451. mqttc1883.loop_stop()
  452. mqttc1883.disconnect()
  453. mqttc1883.close()
  454. if mqttc1884:
  455. mqttc1884.loop_stop()
  456. mqttc1884.disconnect()
  457. mqttc1884.close()
  458. print('finished')