hainiaoSingleNew.py 37 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864
  1. # -*- coding: utf-8 -*-
  2. #!/usr/bin/env python
  3. import time
  4. import logging
  5. from apilib.utils_datetime import timestamp_to_dt
  6. from apps.web.constant import Const, DeviceCmdCode, MQTT_TIMEOUT, DeviceErrorCodeDesc, ErrorCode
  7. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte
  8. from apps.web.core.exceptions import ServiceException
  9. from apps.web.core.networking import MessageSender
  10. from apps.web.device.models import Device, GroupDict
  11. logger = logging.getLogger(__name__)
  12. class ChargingHaiNiaoSingleNewBox(SmartBox):
  13. def __init__(self, device):
  14. super(ChargingHaiNiaoSingleNewBox, self).__init__(device)
  15. def check_dev_status(self, attachParas = None):
  16. if attachParas is None:
  17. raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口、电池类型信息'})
  18. if not attachParas.has_key('chargeIndex'):
  19. raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口'})
  20. if not self.device.need_fetch_online:
  21. raise ServiceException(
  22. {'result': 2, 'description': DeviceErrorCodeDesc.get(ErrorCode.DEVICE_CONN_CHECK_FAIL)})
  23. self.get_port_status_from_dev()
  24. group = self.device.group # type: GroupDict
  25. if group.is_free:
  26. logger.debug('{} is free. no need to check continue pay.'.format(repr(self.device)))
  27. return
  28. # 处理是否能够续充
  29. portDict = self.get_port_status()
  30. port = str(attachParas['chargeIndex'])
  31. if port in portDict:
  32. isCanAdd = self.device['devType'].get('payableWhileBusy', False)
  33. if portDict[port]['status'] == Const.DEV_WORK_STATUS_IDLE:
  34. return
  35. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FAULT:
  36. raise ServiceException({'result': 0, 'description': u'该端口故障,暂时不能使用'})
  37. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_WORKING:
  38. if isCanAdd:
  39. return
  40. else:
  41. raise ServiceException({'result': 0, 'description': u'该端口正在工作不能使用,请您使用其他端口'})
  42. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  43. raise ServiceException({'result': 0, 'description': u'该端口已被禁止使用,请您使用其他端口'})
  44. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_CONNECTED:
  45. return
  46. else:
  47. raise ServiceException({'result': 0, 'description': u'端口状态未知,暂时不能使用'})
  48. else:
  49. raise ServiceException({'result': 0, 'description': u'未知端口,暂时不能使用'})
  50. def get_port_status_from_dev(self): # 获取端口状态
  51. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  52. {'IMEI': self._device['devNo'], "funCode": '01', 'data': '00'})
  53. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  54. if devInfo['rst'] == -1:
  55. raise ServiceException(
  56. {'result': 2, 'description': u'当前设备正在玩命找网络,请您稍候再试'})
  57. elif devInfo['rst'] == 1:
  58. raise ServiceException(
  59. {'result': 2, 'description': u'当前设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  60. result = {}
  61. binStr = str(bin(int(devInfo['data'][10:12], 16)))[2:]
  62. while len(binStr) < 8:
  63. binStr = '0' + binStr
  64. if len(binStr) >= 8:
  65. break
  66. portStatus = binStr[-1]
  67. if portStatus == '0':
  68. result['1'] = {'status': Const.DEV_WORK_STATUS_IDLE}
  69. elif portStatus == '1':
  70. result['1'] = {'status': Const.DEV_WORK_STATUS_WORKING}
  71. else:
  72. raise ServiceException({'result': 2, 'description': u'端口状态返回错误'})
  73. portErrorStatus = devInfo['data'][20:22]
  74. if portErrorStatus != '00':
  75. raise ServiceException({'result': 2, 'description': u'端口故障(0x{})'.format(portErrorStatus)})
  76. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  77. Device.update_dev_control_cache(self._device['devNo'],
  78. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  79. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  80. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  81. for strPort, info in result.items():
  82. if ctrInfo.has_key(strPort):
  83. ctrInfo[strPort].update({'status': info['status']})
  84. else:
  85. ctrInfo[strPort] = info
  86. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  87. return result
  88. def get_port_status(self, force = False): # 获取端口状态(缓存)
  89. return self.get_port_status_from_dev()
  90. def get_dev_setting(self):
  91. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  92. {'IMEI': self._device['devNo'],"funCode":'02','data':'00'})
  93. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  94. if devInfo['rst'] == -1:
  95. raise ServiceException(
  96. {'result': 2, 'description': u'当前设备正在玩命找网络,请您稍候再试'})
  97. elif devInfo['rst'] == 1:
  98. raise ServiceException(
  99. {'result': 2, 'description': u'当前设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  100. confData = devInfo['data'][8::]
  101. switchData = int(confData[0:2], 16)
  102. binStr = str(bin(switchData))[2:]
  103. while len(binStr) < 8:
  104. binStr = '0' + binStr
  105. if len(binStr) >= 8:
  106. break
  107. pauseModeData = int(binStr[5:8], 2)
  108. pauseModeMap = {
  109. '1': 'pause1MinutesClear',
  110. '2': 'pause2MinutesClear',
  111. '3': 'pause3MinutesClear',
  112. '4': 'pause5MinutesStart',
  113. '5': 'pause10MinutesStart',
  114. }
  115. pauseMode = pauseModeMap[str(pauseModeData)]
  116. billingMode = 'litre' if int(binStr[4]) else 'time'
  117. workingMode = 'multiple' if int(binStr[3]) else 'single'
  118. isPause = True if int(binStr[2]) else False
  119. isPowerOffMemory = True if int(binStr[1]) else False
  120. coinLaunchMode = 'button' if int(binStr[0]) else 'direct'
  121. power1Price = int(confData[10:12], 16)
  122. power1Matter = int(confData[12:16], 16)
  123. power2Price = int(confData[16:18], 16)
  124. power2Matter = int(confData[18:22], 16)
  125. power3Price = int(confData[22:24], 16)
  126. power3Matter = int(confData[24:28], 16)
  127. power4Price = int(confData[28:30], 16)
  128. power4Matter = int(confData[30:34], 16)
  129. power5Price = int(confData[34:36], 16)
  130. power5Matter = int(confData[36:40], 16)
  131. power6Price = int(confData[40:42], 16)
  132. power6Matter = int(confData[42:46], 16)
  133. usedCoinPackage = {"power1Price":power1Price,"power1Matter":power1Matter,\
  134. "power2Price":power2Price,"power2Matter":power2Matter,\
  135. "power3Price":power3Price,"power3Matter":power3Matter,\
  136. "power4Price":power4Price,"power4Matter":power4Matter,\
  137. "power5Price":power5Price,"power5Matter":power5Matter,\
  138. "power6Price":power6Price,"power6Matter":power6Matter,
  139. }
  140. # 获取投币套餐
  141. coinPackages = Device.get_dev(self.device.devNo).get("otherConf").get("coinPackages")
  142. if coinPackages:# type: list()
  143. name = coinPackages[0].get('name')
  144. usedCoinPackage.update({"name":name,"switch":True,"unit": coinPackages[0].get('unit')})
  145. coinPackages = [usedCoinPackage]
  146. else:
  147. usedCoinPackage.update({"name": "未命名套餐", "switch": True, "unit": billingMode})
  148. coinPackages = [usedCoinPackage]
  149. cardFee = int(confData[46:50], 16)
  150. cardMin = int(confData[50:54], 16)
  151. usedCardPackage = {"cardFee": cardFee, "cardMin": cardMin}
  152. cardPackages = Device.get_dev(self.device.devNo).get("otherConf").get("cardPackages")
  153. if cardPackages:
  154. usedCardPackage.update({"name": cardPackages[0].pop('name'), "switch": True,"unit": cardPackages[0]['unit']})
  155. cardPackages = [usedCardPackage]
  156. else:
  157. usedCardPackage.update({"name": "未命名套餐", "switch": True, "unit": billingMode})
  158. cardPackages = [usedCardPackage]
  159. otherSettingsData = int(confData[54:56], 16)
  160. binStr2 = str(bin(otherSettingsData))[2:]
  161. while len(binStr2) < 8:
  162. binStr2 = '0' + binStr2
  163. if len(binStr2) >= 8:
  164. break
  165. remoteControl = True if int(binStr2[7]) else False
  166. voiceAnnouncements = True if int(binStr2[6]) else False
  167. unitPulse = int(confData[56:60], 16)
  168. device = Device.objects(devNo=self._device['devNo']).first()
  169. minConsumptionLimit = device.otherConf.get('minConsumptionLimit', 0)
  170. return {
  171. 'pauseMode': pauseMode,
  172. 'billingMode': billingMode,
  173. 'workingMode': workingMode,
  174. 'isPause': isPause,
  175. 'isPowerOffMemory': isPowerOffMemory,
  176. 'coinLaunchMode': coinLaunchMode,
  177. # 'power1Price': power1Price,
  178. # 'power1Matter': power1Matter,
  179. # 'power2Price': power2Price,
  180. # 'power2Matter': power2Matter,
  181. # 'power3Price': power3Price,
  182. # 'power3Matter': power3Matter,
  183. # 'power4Price': power4Price,
  184. # 'power4Matter': power4Matter,
  185. # 'power5Price': power5Price,
  186. # 'power5Matter': power5Matter,
  187. # 'power6Price': power6Price,
  188. # 'power6Matter': power6Matter,
  189. 'cardFee': cardFee,
  190. 'cardMin': cardMin,
  191. 'remoteControl': remoteControl,
  192. 'voiceAnnouncements': voiceAnnouncements,
  193. 'unitPulse': unitPulse,
  194. 'minConsumptionLimit': minConsumptionLimit,
  195. "coinPackages":coinPackages,
  196. "cardPackages":cardPackages,
  197. }
  198. def start_device(self, package, openId, attachParas):
  199. if attachParas is None:
  200. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  201. if not attachParas.has_key('chargeIndex'):
  202. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  203. # 只有一个端口
  204. hexPort = '0001'
  205. needTime = 0
  206. needLitre = 0
  207. needPrice = float(package['price'])
  208. hexNeedPrice = fill_2_hexByte(hex(int(needPrice * 100)))
  209. unit = package['unit']
  210. if unit == u'升':
  211. needLitre = int(package['time'])
  212. hexLitre = fill_2_hexByte(hex(needLitre * 10))
  213. data = hexPort + '01' + hexLitre + hexNeedPrice
  214. funCode = '08'
  215. elif unit == u'小时':
  216. needTime = int(package['time']) * 60
  217. hexTime = fill_2_hexByte(hex(needTime))
  218. data = hexPort + '01' + hexTime + hexNeedPrice
  219. funCode = '08'
  220. elif unit == u'秒':
  221. needTime = int(package['time'])
  222. hexTime = fill_2_hexByte(hex(needTime))
  223. data = hexPort + '01' + hexTime + hexNeedPrice
  224. funCode = '0A'
  225. else:
  226. needTime = int(package['time'])
  227. hexTime = fill_2_hexByte(hex(needTime))
  228. data = hexPort + '01' + hexTime + hexNeedPrice
  229. funCode = '08'
  230. billingMode = self.get_dev_setting()['billingMode']
  231. if billingMode == 'litre' and unit == u'升':
  232. pass
  233. elif billingMode == 'time' and unit == u'分钟':
  234. pass
  235. elif billingMode == 'time' and unit == u'小时':
  236. pass
  237. elif billingMode == 'time' and unit == u'秒':
  238. pass
  239. else:
  240. raise ServiceException({'result': 2, 'description': u'套餐与主板的启动参数不匹配(时间/流量)'})
  241. orderNo = attachParas.get('orderNo')
  242. portStatus = self.get_port_status_from_dev()
  243. if portStatus['1']['status'] == Const.DEV_WORK_STATUS_WORKING:
  244. if funCode == '08':
  245. funCode = '09'
  246. else:
  247. raise ServiceException({'result': 2, 'description': u'秒启动不支持续充'})
  248. data = data[0:4] + data[6:10]
  249. devInfo = MessageSender.send(
  250. device = self.device,
  251. cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  252. payload = {
  253. 'IMEI': self._device['devNo'],
  254. "funCode": funCode,
  255. 'data': data
  256. }, timeout = MQTT_TIMEOUT.START_DEVICE)
  257. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  258. if devInfo['rst'] == -1:
  259. raise ServiceException(
  260. {'result': 2, 'description': u'当前设备正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦'})
  261. elif devInfo['rst'] == 1:
  262. raise ServiceException({'result': 2, 'description': u'当前设备正在忙,无响应,您的金币还在,请试试其他线路,或者请稍后再试哦'})
  263. data = devInfo['data'][8::]
  264. usePort = int(data[0:4], 16)
  265. result = data[4:8]
  266. if result == '0000': # 代表失败
  267. newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'充电站故障'}}
  268. Device.update_dev_control_cache(self._device['devNo'], newValue)
  269. raise ServiceException({'result': 2, 'description': u'充电站故障'})
  270. start_timestamp = int(time.time())
  271. finishedTime = start_timestamp + needTime * 60
  272. portDict = {
  273. 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'),
  274. 'status': Const.DEV_WORK_STATUS_WORKING,
  275. 'finishedTime': finishedTime,
  276. 'needPrice': needPrice,
  277. # 个人中心断电需要用到
  278. 'coins': needPrice,
  279. 'isStart': True,
  280. 'needTime': needTime,
  281. 'needLitre': needLitre,
  282. 'openId': openId,
  283. 'refunded': False,
  284. 'vCardId': self._vcard_id
  285. }
  286. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  287. lastPortInfo = ctrInfo.get(str(usePort), None)
  288. is_continue = False
  289. if lastPortInfo is not None and \
  290. lastPortInfo.get('status', '') == Const.DEV_WORK_STATUS_WORKING and \
  291. lastPortInfo.get('openId', '') == openId:
  292. is_continue = True
  293. if 'needPrice' in lastPortInfo:
  294. portDict['needPrice'] = float(needPrice) + lastPortInfo['needPrice']
  295. if 'needTime' in lastPortInfo:
  296. portDict['needTime'] = needTime + lastPortInfo['needTime']
  297. if 'needLitre' in lastPortInfo:
  298. portDict['needLitre'] = needLitre + lastPortInfo['needLitre']
  299. finishedTime = int(time.time()) + portDict['needTime'] * 60
  300. portDict.update({'finishedTime': finishedTime})
  301. if 'linkedRechargeRecordId' in attachParas and attachParas.get('isQuickPay', False):
  302. item = {
  303. 'rechargeRcdId': str(attachParas['linkedRechargeRecordId'])
  304. }
  305. if is_continue:
  306. payInfo = lastPortInfo.get('payInfo', list())
  307. else:
  308. payInfo = list()
  309. payInfo.append(item)
  310. portDict['payInfo'] = payInfo
  311. else:
  312. if unit == u'秒':
  313. data = data[0:4] + data[6:10] + data[10:14]
  314. devInfo = MessageSender.send(
  315. device = self.device,
  316. cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  317. payload = {
  318. 'IMEI': self._device['devNo'],
  319. "funCode": funCode,
  320. 'data': data
  321. }, timeout = MQTT_TIMEOUT.START_DEVICE)
  322. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  323. if devInfo['rst'] == -1:
  324. raise ServiceException(
  325. {'result': 2, 'description': u'当前设备正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦'})
  326. elif devInfo['rst'] == 1:
  327. raise ServiceException({'result': 2, 'description': u'当前设备正在忙,无响应,您的金币还在,请试试其他线路,或者请稍后再试哦'})
  328. data = devInfo['data'][8::]
  329. usePort = 1
  330. result = data[4:8]
  331. if result == '0000': # 代表失败
  332. newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'充电站故障'}}
  333. Device.update_dev_control_cache(self._device['devNo'], newValue)
  334. raise ServiceException({'result': 2, 'description': u'充电站故障'})
  335. if unit == u'秒':
  336. needTime = int(needTime / 60)
  337. start_timestamp = int(time.time())
  338. finishedTime = start_timestamp + needTime * 60
  339. portDict = {
  340. 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'),
  341. 'status': Const.DEV_WORK_STATUS_WORKING,
  342. 'finishedTime': finishedTime,
  343. 'needPrice': needPrice,
  344. # 个人中心断电需要用到
  345. 'coins': needPrice,
  346. 'isStart': True,
  347. 'needTime': needTime,
  348. 'needLitre': needLitre,
  349. 'openId': openId,
  350. 'refunded': False,
  351. 'vCardId': self._vcard_id
  352. }
  353. if 'linkedRechargeRecordId' in attachParas:
  354. item = {
  355. 'rechargeRcdId': str(attachParas['linkedRechargeRecordId'])
  356. }
  357. portDict['payInfo'] = [item]
  358. Device.update_dev_control_cache(self._device['devNo'], {str(usePort): portDict})
  359. return devInfo
  360. @property
  361. def isHaveStopEvent(self):
  362. return True
  363. def get_port_info(self, line):
  364. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  365. {'IMEI': self._device['devNo'], "funCode": '01', 'data': '00'})
  366. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  367. if devInfo['rst'] == -1:
  368. raise ServiceException(
  369. {'result': 2, 'description': u'当前设备正在玩命找网络,请您稍候再试'})
  370. elif devInfo['rst'] == 1:
  371. raise ServiceException(
  372. {'result': 2, 'description': u'当前设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  373. leftTimeSec = int(devInfo['data'][12:20], 16)
  374. leftTime = leftTimeSec / 60
  375. return {'port': line, 'leftTime': leftTime}
  376. def stop(self, port = None):
  377. self.stop_charging_port(port)
  378. infoDict = dict()
  379. infoDict['remainder_time'] = 0
  380. return infoDict
  381. def stop_charging_port(self, port):
  382. self.active_deactive_port(port, False)
  383. def active_deactive_port(self, port, active):
  384. if active:
  385. return
  386. else:
  387. data = '000100'
  388. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  389. {'IMEI': self._device['devNo'], "funCode": '03', 'data': data + '0000'})
  390. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  391. if devInfo['rst'] == -1:
  392. raise ServiceException(
  393. {'result': 2, 'description': u'当前设备正在玩命找网络,请您稍候再试'})
  394. elif devInfo['rst'] == 1:
  395. # 不处理
  396. pass
  397. def analyze_event_data(self, data):
  398. cmdCode = data[6:8]
  399. if cmdCode == '86':
  400. channelChangeStatus = data[10:12]
  401. binChannelChangeStatus = str(bin(int(channelChangeStatus, 16)))[2:]
  402. while len(binChannelChangeStatus) < 8:
  403. binChannelChangeStatus = '0' + binChannelChangeStatus
  404. channelOperateStatus = data[14:16]
  405. binChannelOperateStatus = str(bin(int(channelOperateStatus, 16)))[2:]
  406. while len(binChannelOperateStatus) < 8:
  407. binChannelOperateStatus = '0' + binChannelOperateStatus
  408. channel1Status = False if binChannelChangeStatus[-1] == '0' else True
  409. channel1Oper = False if binChannelOperateStatus[-1] == '0' else True
  410. # 判断条件成立代表结束
  411. if channel1Status is True and channel1Oper is False:
  412. reason = data[16:18]
  413. if reason == '00':
  414. desc = u'购买的充电时间或者电量用完了。'
  415. elif reason in ['04', '06', '07']:
  416. desc = u'管理人员可能远程断电了,或是插头被拔掉, 建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
  417. elif reason == '05':
  418. desc = u'空载断电。'
  419. else:
  420. desc = u''
  421. leftTime = int(data[36:44], 16) / 60
  422. leftPrice = float(int(data[44:48], 16)) / 100
  423. cardNo = int(data[48:56], 16)
  424. return {
  425. 'status': Const.DEV_WORK_STATUS_IDLE,
  426. 'leftPrice': leftPrice,
  427. 'leftTime': leftTime,
  428. 'cmdCode': cmdCode,
  429. 'reason': desc,
  430. 'cardNo': cardNo,
  431. 'port': '1'
  432. }
  433. else:
  434. return {}
  435. if cmdCode == '8B':
  436. cardNo = int(data[8:16], 16)
  437. return {'cmdCode': cmdCode, 'cardNo': str(cardNo)}
  438. if cmdCode == '8C':
  439. cardNo = int(data[8:16], 16)
  440. operFee = round(float(int(data[16:24], 16)) / 100, 2)
  441. return {'cmdCode': cmdCode, 'operFee': operFee, 'cardNo': str(cardNo)}
  442. if cmdCode == '8D':
  443. if 'debug' in self.device.otherConf:
  444. url = 'https://develop.5tao5ai.com/userLogin?l='
  445. else:
  446. url = 'https://www.washpayer.com/userLogin?l='
  447. hexUrl = ''.join([str(hex(ord(_)))[2:].upper() for _ in url])
  448. return {'cmdCode': cmdCode, 'hexUrl': hexUrl}
  449. def pauseToUseDevice(self, port, oper):
  450. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  451. {'IMEI': self._device['devNo'], "funCode": '03', 'data': '0001' + oper + '0000'})
  452. if oper == '02':
  453. Device.update_dev_control_cache(self._device['devNo'], {'1': {'pausePort': True}})
  454. elif oper == '01':
  455. Device.update_dev_control_cache(self._device['devNo'], {'1': {'pausePort': False}})
  456. else:
  457. pass
  458. def send_setting_data(self, data):
  459. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  460. {'IMEI': self._device['devNo'], "funCode": '04', 'data': data}, timeout=30)
  461. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  462. if devInfo['rst'] == -1:
  463. raise ServiceException(
  464. {'result': 2, 'description': u'当前设备正在玩命找网络,请您稍候再试'})
  465. elif devInfo['rst'] == 1:
  466. raise ServiceException(
  467. {'result': 2, 'description': u'当前设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  468. if devInfo['data'][14:16] == '01':
  469. raise ServiceException(
  470. {'result': 2, 'description': u'设置失败'})
  471. def set_pause_mode(self, isPause):
  472. data = '08' + ('0001' if isPause else '0000')
  473. self.send_setting_data(data)
  474. def set_power_off_memory(self, isPowerOffMemory):
  475. # data = '0C' + ('0001' if isPowerOffMemory else '0000')
  476. # self.send_setting_data(data)
  477. return
  478. def set_remote_control(self, remoteControl):
  479. data = '0E' + ('0001' if remoteControl else '0000')
  480. self.send_setting_data(data)
  481. def set_voice_announcements(self, voiceAnnouncements):
  482. data = '07' + ('0001' if voiceAnnouncements else '0000')
  483. self.send_setting_data(data)
  484. def ack_query_card_balance(self, cardNo, cardBalance):
  485. cardNo = str(hex(int(cardNo)))[2:].upper().rjust(8, '0')
  486. cardBalance = str(hex(int(float(cardBalance) * 100)))[2:].upper().rjust(8, '0')
  487. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  488. {'IMEI': self._device['devNo'], "funCode": '0B', 'data': cardNo + cardBalance})
  489. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  490. if devInfo['rst'] == -1:
  491. raise ServiceException(
  492. {'result': 2, 'description': u'当前设备正在玩命找网络,请您稍候再试'})
  493. elif devInfo['rst'] == 1:
  494. raise ServiceException(
  495. {'result': 2, 'description': u'当前设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  496. def ack_consume_card(self, cardNo, cardBalance, oper):
  497. cardNo = str(hex(int(cardNo)))[2:].upper().rjust(8, '0')
  498. cardBalance = str(hex(int(float(cardBalance) * 100)))[2:].upper().rjust(8, '0')
  499. data = cardNo + cardBalance + oper
  500. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  501. {'IMEI': self._device['devNo'], "funCode": '0C', 'data': data})
  502. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  503. if devInfo['rst'] == -1:
  504. raise ServiceException(
  505. {'result': 2, 'description': u'当前设备正在玩命找网络,请您稍候再试'})
  506. elif devInfo['rst'] == 1:
  507. raise ServiceException(
  508. {'result': 2, 'description': u'当前设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  509. def init_device_QR_code(self, hexUrl):
  510. hexLogicalCode = ''.join([str(hex(ord(_)))[2:].upper() for _ in self.device['logicalCode']])
  511. data = hexUrl + hexLogicalCode
  512. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  513. {'IMEI': self._device['devNo'], "funCode": '0D', 'data': data.ljust(200, '0')})
  514. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  515. if devInfo['rst'] == -1:
  516. raise ServiceException(
  517. {'result': 2, 'description': u'当前设备正在玩命找网络,请您稍候再试'})
  518. elif devInfo['rst'] == 1:
  519. raise ServiceException(
  520. {'result': 2, 'description': u'当前设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  521. def set_power_price(self, powerPriceDict):
  522. power1PriceData = '14' + fill_2_hexByte(hex(int(powerPriceDict['power1Price'])))
  523. self.send_setting_data(power1PriceData)
  524. power2PriceData = '16' + fill_2_hexByte(hex(int(powerPriceDict['power2Price'])))
  525. self.send_setting_data(power2PriceData)
  526. power3PriceData = '18' + fill_2_hexByte(hex(int(powerPriceDict['power3Price'])))
  527. self.send_setting_data(power3PriceData)
  528. power4PriceData = '1A' + fill_2_hexByte(hex(int(powerPriceDict['power4Price'])))
  529. self.send_setting_data(power4PriceData)
  530. power5PriceData = '1C' + fill_2_hexByte(hex(int(powerPriceDict['power5Price'])))
  531. self.send_setting_data(power5PriceData)
  532. power6PriceData = '1E' + fill_2_hexByte(hex(int(powerPriceDict['power6Price'])))
  533. self.send_setting_data(power6PriceData)
  534. def set_power_matter(self, powerMatterDict):
  535. power1MatterData = '15' + fill_2_hexByte(hex(int(powerMatterDict['power1Matter'])))
  536. self.send_setting_data(power1MatterData)
  537. power2MatterData = '17' + fill_2_hexByte(hex(int(powerMatterDict['power2Matter'])))
  538. self.send_setting_data(power2MatterData)
  539. power3MatterData = '19' + fill_2_hexByte(hex(int(powerMatterDict['power3Matter'])))
  540. self.send_setting_data(power3MatterData)
  541. power4MatterData = '1B' + fill_2_hexByte(hex(int(powerMatterDict['power4Matter'])))
  542. self.send_setting_data(power4MatterData)
  543. power5MatterData = '1D' + fill_2_hexByte(hex(int(powerMatterDict['power5Matter'])))
  544. self.send_setting_data(power5MatterData)
  545. power6MatterData = '1F' + fill_2_hexByte(hex(int(powerMatterDict['power6Matter'])))
  546. self.send_setting_data(power6MatterData)
  547. def set_base_settings(self, baseSettingsDict):
  548. billingModeData = '0B' + ('0001' if baseSettingsDict['billingMode'] == 'litre' else '0000')
  549. self.send_setting_data(billingModeData)
  550. workingModeData = '0A' + ('0001' if baseSettingsDict['workingMode'] == 'multiple' else '0000')
  551. self.send_setting_data(workingModeData)
  552. coinLaunchModeData = '09' + ('0001' if baseSettingsDict['coinLaunchMode'] == 'button' else '0000')
  553. self.send_setting_data(coinLaunchModeData)
  554. hexPauseModeMap = {
  555. 'pause1MinutesClear': '0001',
  556. 'pause2MinutesClear': '0002',
  557. 'pause3MinutesClear': '0003',
  558. 'pause5MinutesStart': '0004',
  559. 'pause10MinutesStart': '0005',
  560. }
  561. pauseModeData = hexPauseModeMap[baseSettingsDict['pauseMode']]
  562. self.send_setting_data('0D' + pauseModeData)
  563. # cardFeeData = str(hex(int(baseSettingsDict['cardFee'])))[2:].upper().rjust(4, '0')
  564. # self.send_setting_data('20' + cardFeeData)
  565. #
  566. # cardMinData = str(hex(int(baseSettingsDict['cardMin'])))[2:].upper().rjust(4, '0')
  567. # self.send_setting_data('21' + cardMinData)
  568. unitPulseData = str(hex(int(baseSettingsDict['unitPulse'])))[2:].upper().rjust(4, '0')
  569. unitPulseData = '01D6' if unitPulseData == '0000' else unitPulseData
  570. self.send_setting_data('22' + unitPulseData)
  571. device = Device.objects(devNo=self.device['devNo']).first()
  572. device.otherConf['minConsumptionLimit'] = baseSettingsDict['minConsumptionLimit']
  573. device.save()
  574. Device.invalid_device_cache(self.device['devNo'])
  575. def set_device_function_param(self, request, lastSetConf):
  576. if 'billingMode' in request.POST \
  577. and 'workingMode' in request.POST \
  578. and 'minConsumptionLimit' in request.POST \
  579. and 'pauseMode' in request.POST \
  580. and 'unitPulse' in request.POST \
  581. and 'coinLaunchMode' in request.POST:
  582. billingMode = request.POST['billingMode']
  583. workingMode = request.POST['workingMode']
  584. minConsumptionLimit = request.POST['minConsumptionLimit']
  585. pauseMode = request.POST['pauseMode']
  586. # cardFee = request.POST['cardFee']
  587. # cardMin = request.POST['cardMin']
  588. unitPulse = request.POST['unitPulse']
  589. coinLaunchMode = request.POST['coinLaunchMode']
  590. self.set_base_settings({
  591. 'billingMode': billingMode,
  592. 'workingMode': workingMode,
  593. 'minConsumptionLimit': minConsumptionLimit,
  594. 'coinLaunchMode': coinLaunchMode,
  595. 'pauseMode': pauseMode,
  596. # 'cardFee': cardFee,
  597. # 'cardMin': cardMin,
  598. 'unitPulse': unitPulse
  599. })
  600. if 'cardPackages' in request.POST and request.POST['cardPackages']:
  601. newCardPackages = []
  602. for cardPackage in request.POST['cardPackages']:
  603. billingMode = request.POST['billingMode'] or lastSetConf.get('billingMode')
  604. if billingMode in [u'time', u'second']:
  605. billingMode = [u'time', u'second']
  606. else:
  607. billingMode = [u'litre']
  608. if cardPackage['unit'] not in billingMode:
  609. raise ServiceException(
  610. {'result': 2, 'description': u'套餐计费单位需与计费模式相同'})
  611. cardFeeData = str(hex(int(cardPackage['cardFee'])))[2:].upper().rjust(4, '0')
  612. self.send_setting_data('20' + cardFeeData)
  613. cardMinData = str(hex(int(cardPackage['cardMin'])))[2:].upper().rjust(4, '0')
  614. self.send_setting_data('21' + cardMinData)
  615. newCardPackages.append({'name':cardPackage.get('name'),'unit':cardPackage['unit']})
  616. device = Device.objects.get(logicalCode=self.device.logicalCode)
  617. device.otherConf['cardPackages'] = newCardPackages
  618. device.save()
  619. Device.invalid_device_cache(self.device.devNo)
  620. if 'coinPackages' in request.POST and request.POST['coinPackages']:
  621. newCoinPackages = []
  622. for coinPackage in request.POST['coinPackages']:
  623. if len(request.POST['coinPackages']) == 1:
  624. request.POST['coinPackages'][0].update({'switch' : True})
  625. power1Price = coinPackage['power1Price']
  626. power1Price = 1 if power1Price == 0 else power1Price
  627. power2Price = coinPackage['power2Price']
  628. power2Price = 2 if power2Price == 0 else power2Price
  629. power3Price = coinPackage['power3Price']
  630. power3Price = 3 if power3Price == 0 else power3Price
  631. power4Price = coinPackage['power4Price']
  632. power4Price = 4 if power4Price == 0 else power4Price
  633. power5Price = coinPackage['power5Price']
  634. power5Price = 5 if power5Price == 0 else power5Price
  635. power6Price = coinPackage['power6Price']
  636. power6Price = 6 if power6Price == 0 else power6Price
  637. power1Matter = coinPackage['power1Matter']
  638. power1Matter = 5 if power1Matter == 0 else power1Matter
  639. power2Matter = coinPackage['power2Matter']
  640. power2Matter = 25 if power2Matter == 0 else power2Matter
  641. power3Matter = coinPackage['power3Matter']
  642. power3Matter = 40 if power3Matter == 0 else power3Matter
  643. power4Matter = coinPackage['power4Matter']
  644. power4Matter = 60 if power4Matter == 0 else power4Matter
  645. power5Matter = coinPackage['power5Matter']
  646. power5Matter = 80 if power5Matter == 0 else power5Matter
  647. power6Matter = coinPackage['power6Matter']
  648. power6Matter = 100 if power6Matter == 0 else power6Matter
  649. if billingMode == u'time' or billingMode == [u'time', u'second']:
  650. billingMode = [u'time', u'second']
  651. else:
  652. billingMode = [u'litre']
  653. if coinPackage['unit'] not in billingMode:
  654. raise ServiceException(
  655. {'result': 2, 'description': u'套餐计费单位需与计费模式相同'})
  656. self.set_power_price({
  657. 'power1Price': power1Price,
  658. 'power2Price': power2Price,
  659. 'power3Price': power3Price,
  660. 'power4Price': power4Price,
  661. 'power5Price': power5Price,
  662. 'power6Price': power6Price
  663. })
  664. self.set_power_matter({
  665. 'power1Matter': power1Matter,
  666. 'power2Matter': power2Matter,
  667. 'power3Matter': power3Matter,
  668. 'power4Matter': power4Matter,
  669. 'power5Matter': power5Matter,
  670. 'power6Matter': power6Matter
  671. })
  672. newCoinPackages.append({'name':coinPackage.get('name'),'unit':coinPackage.get('unit')})
  673. device = Device.objects.get(logicalCode=self.device.logicalCode)
  674. device.otherConf['coinPackages'] = newCoinPackages
  675. device.save()
  676. Device.invalid_device_cache(self.device.devNo)
  677. def set_device_function(self, request, lastSetConf):
  678. if 'isPause' in request.POST:
  679. isPause = request.POST['isPause']
  680. self.set_pause_mode(isPause)
  681. if 'isPowerOffMemory' in request.POST:
  682. isPowerOffMemory = request.POST['isPowerOffMemory']
  683. self.set_power_off_memory(isPowerOffMemory)
  684. if 'remoteControl' in request.POST:
  685. remoteControl = request.POST['remoteControl']
  686. self.set_remote_control(remoteControl)
  687. if 'voiceAnnouncements' in request.POST:
  688. voiceAnnouncements = request.POST['voiceAnnouncements']
  689. self.set_voice_announcements(voiceAnnouncements)