zhixia.py 58 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. # TODO 目前采用主体相同协议拷贝的方式, 后续需要考虑更适合的方式
  4. # 修改zhixia.py问题的时候需要考虑是否修改aiyaxin5.py和zhixia2.py.
  5. # 三者协议一致, 但是因为加载reload问题, 目前必须拆开.
  6. import datetime
  7. import logging
  8. import time
  9. from decimal import Decimal
  10. from typing import TYPE_CHECKING
  11. from apilib.monetary import RMB
  12. from apps.web.constant import DeviceCmdCode, Const, ErrorCode, DeviceErrorCodeDesc, MQTT_TIMEOUT
  13. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte, make_six_bytes_session_id
  14. from apps.web.core.exceptions import ServiceException
  15. from apps.web.core.networking import MessageSender
  16. from apps.web.device.models import Device, DeviceType
  17. from apps.web.south_intf.yuhuan_fire import YuhuanNorther
  18. if TYPE_CHECKING:
  19. from apps.web.device.models import GroupDict
  20. logger = logging.getLogger(__name__)
  21. class ChargingZHIXIABox(SmartBox):
  22. def __init__(self, device):
  23. super(ChargingZHIXIABox, self).__init__(device)
  24. def translate_funcode(self, funCode):
  25. funCodeDict = {
  26. '01': u'获取端口数量',
  27. '02': u'移动支付',
  28. '0C': u'获取设备设置',
  29. '08': u'设置设备参数',
  30. '06': u'获取设备端口详情',
  31. '07': u'获取刷卡投币统计数据',
  32. '09': u'设置刷卡投币使能',
  33. '0A': u'端口使能',
  34. '0B': u'端口关闭',
  35. '16': u'设置设备参数',
  36. '20': u'设备重启',
  37. '13': u'设置卡充满退费',
  38. '15': u'获取功率费率配置',
  39. '14': u'设置功率费率配置',
  40. '12': u'充值',
  41. }
  42. return funCodeDict.get(funCode, '')
  43. def translate_event_cmdcode(self, cmdCode):
  44. cmdDict = {
  45. '03': u'投币上报',
  46. '04': u'刷卡上报',
  47. '05': u'充电结束',
  48. '16': u'充电结束',
  49. '10': u'刷卡上报',
  50. '0D': u'故障',
  51. '20': u'启动设备',
  52. '11': u'刷卡使用',
  53. '12': u'卡充值',
  54. '21': u'电流上报',
  55. '22': u'温度上报',
  56. '23': u'烟感上报',
  57. }
  58. return cmdDict.get(cmdCode, '')
  59. def is_port_can_use(self, port, canAdd = False):
  60. # 电川的在启动的时候去判断是否需要续充
  61. return True, ''
  62. def check_dev_status(self, attachParas = None):
  63. """
  64. 如果超过两个心跳周期没有报心跳,并且最后一次更新时间在2个小时内,需要从设备获取状态
  65. 否则以缓存状态为准。
  66. :param attachParas:
  67. :return:
  68. """
  69. if attachParas is None:
  70. raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口、电池类型信息'})
  71. if not attachParas.has_key('chargeIndex'):
  72. raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口'})
  73. if not self.device.need_fetch_online:
  74. raise ServiceException(
  75. {'result': 2, 'description': DeviceErrorCodeDesc.get(ErrorCode.DEVICE_CONN_CHECK_FAIL)})
  76. self.get_port_status_from_dev()
  77. group = self.device.group # type: GroupDict
  78. if group.is_free:
  79. logger.debug('{} is free. no need to check continue pay.'.format(repr(self.device)))
  80. return
  81. # 处理是否能够续充
  82. portDict = self.get_port_status()
  83. port = str(attachParas['chargeIndex'])
  84. if port in portDict:
  85. isCanAdd = self.device['devType'].get('payableWhileBusy', False)
  86. if portDict[port]['status'] == Const.DEV_WORK_STATUS_IDLE:
  87. return
  88. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FAULT:
  89. raise ServiceException({'result': 0, 'description': u'该端口故障,暂时不能使用'})
  90. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_WORKING:
  91. if isCanAdd:
  92. return
  93. else:
  94. raise ServiceException({'result': 0, 'description': u'该端口正在工作不能使用,请您使用其他端口'})
  95. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  96. raise ServiceException({'result': 0, 'description': u'该端口已被禁止使用,请您使用其他端口'})
  97. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_CONNECTED:
  98. return
  99. else:
  100. raise ServiceException({'result': 0, 'description': u'端口状态未知,暂时不能使用'})
  101. else:
  102. raise ServiceException({'result': 0, 'description': u'未知端口,暂时不能使用'})
  103. def test(self, coins):
  104. hexPort = fill_2_hexByte(hex(int(1)), 2)
  105. hexTime = fill_2_hexByte(hex(5))
  106. devInfo = MessageSender.send(device = self.device,
  107. cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  108. payload = {
  109. 'IMEI': self._device['devNo'],
  110. "funCode": '02',
  111. 'data': hexPort + '0000' + hexTime
  112. },
  113. timeout = MQTT_TIMEOUT.SHORT)
  114. return devInfo
  115. def port_is_busy(self, port_dict):
  116. if not port_dict:
  117. return False
  118. if 'status' not in port_dict:
  119. return False
  120. if 'coins' not in port_dict:
  121. return False
  122. if 'price' not in port_dict:
  123. return False
  124. if 'needTime' not in port_dict:
  125. return False
  126. if port_dict['status'] == Const.DEV_WORK_STATUS_WORKING:
  127. return True
  128. else:
  129. return False
  130. def start_device(self, package, openId, attachParas):
  131. if attachParas is None:
  132. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  133. if not attachParas.has_key('chargeIndex'):
  134. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  135. port = hex(int(attachParas['chargeIndex']))
  136. hexPort = fill_2_hexByte(port, 2)
  137. needTime = int(package['time'])
  138. unit = package.get('unit', u'分钟')
  139. if unit == u'小时':
  140. needTime = int(package['time']) * 60
  141. elif unit == u'天':
  142. needTime = int(package['time']) * 1440
  143. coins = float(package['coins'])
  144. price = float(package['price'])
  145. hexTime = fill_2_hexByte(hex(needTime))
  146. devInfo = MessageSender.send(
  147. device = self.device,
  148. cmd = DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC,
  149. payload = {
  150. 'IMEI': self._device['devNo'],
  151. "funCode": '02',
  152. 'data': 'EE0D02{}'.format(make_six_bytes_session_id()) + hexPort + '0000' + hexTime
  153. }, timeout = MQTT_TIMEOUT.START_DEVICE)
  154. usePort = int(attachParas['chargeIndex'])
  155. if 'rst' not in devInfo:
  156. raise ServiceException(
  157. {
  158. 'result': 2,
  159. 'description': u'启动设备失败,您的支付金额已经退还,请重新扫码设备试试(1001)'
  160. })
  161. if devInfo['rst'] != 0:
  162. if devInfo['rst'] == -1:
  163. raise ServiceException(
  164. {
  165. 'result': 2,
  166. 'description': u'充电桩正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦'
  167. })
  168. elif devInfo['rst'] == 1:
  169. self.check_serial_port_for_startcmd(attachParas['chargeIndex'])
  170. else:
  171. raise ServiceException(
  172. {
  173. 'result': 2,
  174. 'description': u'启动设备失败,您的支付金额已经退回,请重新扫码设备({})'.format(devInfo['rst'])
  175. })
  176. else:
  177. if 'data' not in devInfo:
  178. logger.warning('no data in success response. result = {}'.format(str(devInfo)))
  179. raise ServiceException(
  180. {
  181. 'result': 2,
  182. 'description': u'启动设备失败,您的支付金额已经退还,请重试'
  183. })
  184. else:
  185. data = devInfo['data'][18::]
  186. result = data[2:4]
  187. if result == '01': # 成功
  188. pass
  189. elif result == '02':
  190. newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'充电站故障'}}
  191. Device.update_dev_control_cache(self._device['devNo'], newValue)
  192. raise ServiceException({'result': 2, 'description': u'充电站故障'})
  193. elif result == '03':
  194. newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_WORKING, 'statusInfo': u''}}
  195. Device.update_dev_control_cache(self._device['devNo'], newValue)
  196. raise ServiceException({'result': 2, 'description': u'该端口正在使用中'})
  197. else:
  198. raise ServiceException({
  199. 'result': 2,
  200. 'description': u'启动设备失败({}),您的支付金额已经退回,请重新扫码设备'.format(result)
  201. })
  202. portDict = {
  203. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  204. 'status': Const.DEV_WORK_STATUS_WORKING,
  205. 'coins': coins,
  206. 'price': price,
  207. 'isStart': True,
  208. 'needTime': needTime,
  209. 'openId': openId,
  210. 'refunded': False,
  211. 'vCardId': self._vcard_id,
  212. 'payInfo': list()
  213. }
  214. ctrInfo = Device.get_dev_control_cache(self._device.devNo)
  215. lastPortInfo = ctrInfo.get(str(usePort), {})
  216. if self.port_is_busy(lastPortInfo) and \
  217. lastPortInfo.get('openId') == openId:
  218. is_continus = True
  219. portDict['coins'] = float(coins) + lastPortInfo['coins']
  220. portDict['price'] = float(price) + lastPortInfo['price']
  221. portDict['needTime'] = needTime + lastPortInfo['needTime']
  222. else:
  223. is_continus = False
  224. portDict['coins'] = float(coins)
  225. portDict['price'] = float(price)
  226. portDict['needTime'] = needTime
  227. if 'linkedRechargeRecordId' in attachParas:
  228. if is_continus:
  229. payInfo = lastPortInfo.get("payInfo", list())
  230. if not payInfo:
  231. logger.warning("miss payInfo! {}-{}".format(self._device["devNo"], usePort))
  232. else:
  233. payInfo = list()
  234. payInfo.append({'rechargeRcdId': str(attachParas['linkedRechargeRecordId'])})
  235. portDict['payInfo'] = payInfo
  236. else:
  237. if is_continus:
  238. portDict['payInfo'] = lastPortInfo.get("payInfo", list())
  239. else:
  240. portDict['payInfo'] = list()
  241. finishedTime = int(time.time()) + needTime * 60
  242. portDict.update({'finishedTime': finishedTime})
  243. if 'orderNo' in attachParas:
  244. portDict.update({'orderNo': attachParas['orderNo']})
  245. Device.update_dev_control_cache(
  246. self._device['devNo'],
  247. {
  248. str(usePort): portDict
  249. })
  250. # 玉环的对接,放这里吧
  251. YuhuanNorther.send_dev_status(self._device, attachParas['chargeIndex'], '1')
  252. return devInfo
  253. def analyze_event_data(self, data):
  254. cmdCode = data[4:6]
  255. if cmdCode in ['05']:
  256. port = int(data[18:20], 16)
  257. leftTime = int(data[20:24], 16)
  258. reason = data[24:26]
  259. devType = DeviceType.objects(id=self.device['devType']['id']).first()
  260. finishedReasonDict = devType.finishedReasonDict
  261. if finishedReasonDict != {}:
  262. desc_map = finishedReasonDict
  263. else:
  264. desc_map = {
  265. '00': u'购买的充电时间或电量用完了。',
  266. '01': u'插头被拔或者松动,或者电瓶已经充满(系统判断为异常断电,电瓶车充电器种类繁多,可能存在误差)',
  267. '02': u'电池已经充满',
  268. '03': u'设备或者端口故障。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电',
  269. '04': u'警告!您的电池功率超过本机最大限制。为了公共安全,不建议您在该充电桩充电',
  270. '05': u'刷卡退费结束',
  271. '06': u'可能是插头被拔掉或者未连接充电器。如果不是自己操作,建议您到现场检查是否有人误操作',
  272. '07': u'远程方式停止充电。如果不是自己操作,建议到现场尽快恢复充电'
  273. }
  274. desc = desc_map.get(reason, u'电池没有充满!原因未知。')
  275. # 刷卡充电的结束
  276. if len(data) > 34:
  277. cardNo = int(data[26:34], 16)
  278. backMoney = int(data[34:36], 16) / 10.0
  279. cardType = 'ID' if data[36:40] == 'AA33' else 'IC'
  280. if cardNo != 0:
  281. return {'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port,
  282. 'leftTime': leftTime, 'reason': desc, 'isStart': False, 'cardNo': cardNo,
  283. 'backMoney': backMoney, 'cardType': cardType, 'endType': reason,
  284. 'reasonCode': reason, 'uartData': data}
  285. else:
  286. return {'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port,
  287. 'leftTime': leftTime, 'reason': desc, 'isStart': False, 'endType': reason,
  288. 'reasonCode': reason, 'uartData': data}
  289. # 非刷卡充电的结束
  290. else:
  291. return {'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port,
  292. 'leftTime': leftTime, 'reason': desc, 'isStart': False, 'endType': reason,
  293. 'reasonCode': reason, 'uartData': data}
  294. elif cmdCode == '16': # 高版本的
  295. port = int(data[8:10], 16)
  296. leftTime = int(data[10:14], 16)
  297. elec = int(data[14:18], 16)
  298. reason = data[18:20]
  299. if reason == '00':
  300. desc = u'您购买的充电时间用完了。'
  301. elif reason == '01':
  302. desc = u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。'
  303. elif reason == '02':
  304. desc = u'恭喜您!电池已经充满电!'
  305. elif reason == '03':
  306. desc = u'警告!您的电池功率超过本机最大限制,已经停止充电,为了公共安全,不建议您在该充电桩充电!提醒您,为了安全大功率的电池不要放入楼道、室内等位置充电哦'
  307. elif reason == '04':
  308. desc = u'管理人员可能远程断电了,建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
  309. elif reason == '0B':
  310. desc = u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
  311. else:
  312. desc = ''
  313. return {'status': Const.DEV_WORK_STATUS_IDLE, 'reason': desc, 'cmdCode': cmdCode, 'port': port,
  314. 'leftTime': leftTime, 'elec': elec, 'isStart': False, 'reasonCode': reason, 'uartData': data}
  315. elif cmdCode == '0D':
  316. port = int(data[16:18], 16)
  317. errCode = data[18:20]
  318. if errCode == '01':
  319. return {'statusInfo': u'端口输出故障', 'cmdCode': cmdCode, 'port': port, 'FaultCode': errCode, "uart": data}
  320. elif errCode == '02':
  321. return {'statusInfo': u'机器整体充电功率过大', 'cmdCode': cmdCode, 'port': port, 'FaultCode': errCode, "uart": data}
  322. elif errCode == '03':
  323. return {'statusInfo': u'电源故障', 'cmdCode': cmdCode, 'port': port, 'FaultCode': errCode, "uart": data}
  324. elif cmdCode == '10': # 用户刷卡上报的信息
  325. cardNo = data[8:16]
  326. cardNo = str(int(cardNo, 16))
  327. preFee = int(data[16:18], 16) / 10.0
  328. oper = data[18:20]
  329. return {'cardNo': cardNo, 'preFee': preFee, 'cmdCode': cmdCode, 'oper': oper}
  330. elif cmdCode == '20': # 启动设备
  331. port = int(data[8:10], 16)
  332. needTime = int(data[10:14], 16)
  333. elec = int(data[14:18], 16)
  334. consumeType = data[18:20]
  335. money = int(data[20:22], 16)
  336. return {'cmdCode': cmdCode, 'port': port, 'needTime': needTime, 'elec': elec, 'consumeType': consumeType,
  337. 'coins': money}
  338. elif cmdCode == '03':
  339. coin = int(data[18:20], 16)
  340. return {'cmdCode': cmdCode, 'coins': coin}
  341. elif cmdCode == '11':
  342. cardNo = data[18:26]
  343. cardNo = str(int(cardNo, 16))
  344. money = int(data[26:28], 16) / 10.0
  345. balance = int(data[28:32], 16) / 10.0
  346. port = int(data[36:38], 16)
  347. status = data[38:40]
  348. return {'cmdCode': cmdCode, 'cardNo': cardNo, 'coins': money, 'balance': balance, 'status': status,
  349. 'port': port}
  350. elif cmdCode == '12':
  351. cardNo = data[18:26]
  352. cardNo = str(int(cardNo, 16))
  353. balance = int(data[26:30], 16) / 10.0
  354. cardType = data[30:34]
  355. return {'cmdCode': cmdCode, 'balance': balance, 'cardType': cardType, 'cardNo': cardNo}
  356. elif cmdCode == '04': # 旧版本的刷卡报文
  357. money = int(data[18:20], 16)
  358. return {'cmdCode': cmdCode, 'money': money}
  359. elif cmdCode == '30': # 宇泽家的,主动上报电流
  360. portData = data[18:48]
  361. port1 = int(portData[2:4])
  362. port2 = int(portData[4:6])
  363. port3 = int(portData[6:8])
  364. port4 = int(portData[8:10])
  365. port5 = int(portData[10:12])
  366. port6 = int(portData[12:14])
  367. port7 = int(portData[14:16])
  368. port8 = int(portData[16:18])
  369. port9 = int(portData[18:20])
  370. port10 = int(portData[20:22])
  371. device = int(portData[22:24])
  372. return {
  373. 'cmdCode': cmdCode,
  374. 'port1': port1,
  375. 'port2': port2,
  376. 'port3': port3,
  377. 'port4': port4,
  378. 'port5': port5,
  379. 'port6': port6,
  380. 'port7': port7,
  381. 'port8': port8,
  382. 'port9': port9,
  383. 'port10': port10,
  384. 'device': device,
  385. }
  386. elif cmdCode == '31': # 宇泽家的,主动上报温度
  387. portData = data[18:48]
  388. port1 = int(portData[2:4])
  389. port2 = int(portData[4:6])
  390. port3 = int(portData[6:8])
  391. port4 = int(portData[8:10])
  392. port5 = int(portData[10:12])
  393. port6 = int(portData[12:14])
  394. port7 = int(portData[14:16])
  395. port8 = int(portData[16:18])
  396. port9 = int(portData[18:20])
  397. port10 = int(portData[20:22])
  398. device = int(portData[22:24])
  399. return {
  400. 'cmdCode': cmdCode,
  401. 'port1': port1,
  402. 'port2': port2,
  403. 'port3': port3,
  404. 'port4': port4,
  405. 'port5': port5,
  406. 'port6': port6,
  407. 'port7': port7,
  408. 'port8': port8,
  409. 'port9': port9,
  410. 'port10': port10,
  411. 'device': device,
  412. }
  413. elif cmdCode == '32': # 宇泽家的,主动上报温度
  414. if data[18:20] == '01':
  415. return {'isYangan': True, 'cmdCode': cmdCode}
  416. else:
  417. return {'isYangan': False, 'cmdCode': cmdCode}
  418. elif cmdCode == '17':
  419. """
  420. IC卡回收余额成功,上报回收的数目
  421. 样例 660F170048614800052DDA5A0D000001DD
  422. """
  423. cardNo = int(data[18:26], 16)
  424. cardNo = str(cardNo)
  425. backMoney = int(data[26:30], 16) / 10.0
  426. return {'cmdCode': cmdCode, 'cardNo': cardNo, 'backMoney': backMoney}
  427. def get_dev_consume_count(self):
  428. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  429. payload = {'IMEI': self._device['devNo'], "funCode": '07', 'data': '00'},
  430. timeout = MQTT_TIMEOUT.SHORT)
  431. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  432. if devInfo['rst'] == -1:
  433. raise ServiceException(
  434. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  435. elif devInfo['rst'] == 1:
  436. raise ServiceException(
  437. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  438. data = devInfo['data'][16::]
  439. cardFee = int(data[2:6], 16) / 10.0 # 以角为单位
  440. coinFee = int(data[6:10], 16) # 以元为单位
  441. return {'cardFee': cardFee, 'coinFee': coinFee}
  442. def get_port_info(self, line):
  443. support_06 = self._device.get('otherConf', {}).get('support_06', True)
  444. if not support_06:
  445. return {'port': line}
  446. data = fill_2_hexByte(hex(int(line)), 2)
  447. devInfo = MessageSender.send(device = self.device, cmd = self.make_random_cmdcode(),
  448. payload = {'IMEI': self._device['devNo'], "funCode": '06', 'data': data},
  449. timeout = MQTT_TIMEOUT.SHORT)
  450. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  451. if devInfo['rst'] == -1:
  452. raise ServiceException(
  453. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  454. elif devInfo['rst'] == 1:
  455. raise ServiceException(
  456. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  457. data = devInfo['data'][16::]
  458. leftTime = int(data[4:8], 16)
  459. if data[8:12] == 'FFFF':
  460. power = 0
  461. else:
  462. power = int(data[8:12], 16) / 10.0
  463. return {'port': line, 'leftTime': leftTime, 'power': power}
  464. # 访问设备电流
  465. def get_port_elec_from_dev(self):
  466. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  467. payload = {'IMEI': self._device['devNo'], "funCode": '21', 'data': '00'},
  468. timeout = MQTT_TIMEOUT.SHORT)
  469. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  470. if devInfo['rst'] == -1:
  471. raise ServiceException(
  472. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  473. elif devInfo['rst'] == 1:
  474. raise ServiceException(
  475. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  476. portData = devInfo['data'][18::]
  477. port1 = int(portData[2:4], 16)
  478. port2 = int(portData[4:6], 16)
  479. port3 = int(portData[6:8], 16)
  480. port4 = int(portData[8:10], 16)
  481. port5 = int(portData[10:12], 16)
  482. port6 = int(portData[12:14], 16)
  483. port7 = int(portData[14:16], 16)
  484. port8 = int(portData[16:18], 16)
  485. port9 = int(portData[18:20], 16)
  486. port10 = int(portData[20:22], 16)
  487. device = int(portData[22:24], 16)
  488. return {
  489. 'port1': port1,
  490. 'port2': port2,
  491. 'port3': port3,
  492. 'port4': port4,
  493. 'port5': port5,
  494. 'port6': port6,
  495. 'port7': port7,
  496. 'port8': port8,
  497. 'port9': port9,
  498. 'port10': port10,
  499. 'device': device,
  500. }
  501. # 访问设备
  502. def get_port_temperature_from_dev(self):
  503. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  504. payload = {'IMEI': self._device['devNo'], "funCode": '22', 'data': '00'},
  505. timeout = MQTT_TIMEOUT.SHORT)
  506. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  507. if devInfo['rst'] == -1:
  508. raise ServiceException(
  509. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  510. elif devInfo['rst'] == 1:
  511. raise ServiceException(
  512. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  513. portData = devInfo['data'][18::]
  514. port1 = int(portData[2:4], 16)
  515. port2 = int(portData[4:6], 16)
  516. port3 = int(portData[6:8], 16)
  517. port4 = int(portData[8:10], 16)
  518. port5 = int(portData[10:12], 16)
  519. port6 = int(portData[12:14], 16)
  520. port7 = int(portData[14:16], 16)
  521. port8 = int(portData[16:18], 16)
  522. port9 = int(portData[18:20], 16)
  523. port10 = int(portData[20:22], 16)
  524. device = int(portData[22:24], 16)
  525. return {
  526. 'port1': port1,
  527. 'port2': port2,
  528. 'port3': port3,
  529. 'port4': port4,
  530. 'port5': port5,
  531. 'port6': port6,
  532. 'port7': port7,
  533. 'port8': port8,
  534. 'port9': port9,
  535. 'port10': port10,
  536. 'device': device,
  537. }
  538. # 访问设备,获取设备端口信息
  539. def get_port_status_from_dev(self):
  540. devInfo = MessageSender.send(device = self.device,
  541. cmd = DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC,
  542. payload = {
  543. 'IMEI': self._device['devNo'],
  544. 'funCode': '01',
  545. 'data': 'EE0901{}'.format(make_six_bytes_session_id()) + '00'
  546. })
  547. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  548. if devInfo['rst'] == -1:
  549. raise ServiceException(
  550. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试', 'rst': -1})
  551. elif devInfo['rst'] == 1:
  552. raise ServiceException(
  553. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1})
  554. data = devInfo['data'][16::]
  555. result = {}
  556. portNum = int(data[2:4], 16)
  557. portData = data[4::]
  558. ii = 0
  559. while ii < portNum:
  560. statusTemp = portData[ii * 2:ii * 2 + 2]
  561. if statusTemp == '01':
  562. status = {'status': Const.DEV_WORK_STATUS_IDLE}
  563. elif statusTemp == '02':
  564. status = {'status': Const.DEV_WORK_STATUS_WORKING}
  565. elif statusTemp == '03':
  566. status = {'status': Const.DEV_WORK_STATUS_FORBIDDEN}
  567. elif statusTemp == '04':
  568. status = {'status': Const.DEV_WORK_STATUS_FAULT}
  569. ii += 1
  570. result[str(ii)] = status
  571. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  572. Device.update_dev_control_cache(self._device['devNo'],
  573. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  574. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  575. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  576. for strPort, info in result.items():
  577. if ctrInfo.has_key(strPort):
  578. ctrInfo[strPort].update({'status': info['status']})
  579. else:
  580. ctrInfo[strPort] = info
  581. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  582. return result
  583. def get_default_port_nums(self):
  584. default_num = 10
  585. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_DIANCHUAN_HIGH:
  586. default_num = 2
  587. return default_num
  588. def get_port_status(self, force = False):
  589. if force:
  590. return self.get_port_status_from_dev()
  591. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  592. if 'allPorts' in ctrInfo and ctrInfo['allPorts'] > 0:
  593. allPorts = ctrInfo['allPorts']
  594. else:
  595. allPorts = self.get_default_port_nums()
  596. statusDict = {}
  597. for ii in range(allPorts):
  598. tempDict = ctrInfo.get(str(ii + 1), {})
  599. if tempDict.has_key('status'):
  600. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  601. elif tempDict.has_key('isStart'):
  602. if tempDict['isStart']:
  603. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  604. else:
  605. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  606. else:
  607. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  608. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  609. Device.update_dev_control_cache(self._device['devNo'],
  610. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  611. return statusDict
  612. def lock_unlock_port(self, port, lock = True):
  613. lockStr = '00' if lock else '01'
  614. portStr = fill_2_hexByte(hex(int(port)), 2)
  615. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  616. payload = {'IMEI': self._device['devNo'], "funCode": '0A',
  617. 'data': portStr + lockStr}, timeout = MQTT_TIMEOUT.SHORT)
  618. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  619. if devInfo['rst'] == -1:
  620. raise ServiceException(
  621. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  622. elif devInfo['rst'] == 1:
  623. raise ServiceException(
  624. {'result': 2, 'description': u'端口禁用功能只有带保险丝版本的才有。可能是您的设备版本过低,暂时不支持此功能,也可能是设备繁忙无响应。'})
  625. data = devInfo['data'][18::]
  626. if data[0:2] == '01': # 表示成功
  627. pass
  628. else:
  629. raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
  630. if lock:
  631. Device.update_dev_control_cache(self._device['devNo'],
  632. {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  633. else:
  634. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  635. def active_deactive_port(self, port, active):
  636. if active:
  637. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  638. self.stop_charging_port(port)
  639. devInfo = Device.get_dev_control_cache(self._device['devNo'])
  640. portCtrInfo = devInfo.get(str(port), {})
  641. portCtrInfo.update({'isStart': False, 'status': Const.DEV_WORK_STATUS_IDLE, 'needTime': 0, 'leftTime': 0,
  642. 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  643. newValue = {str(port): portCtrInfo}
  644. Device.update_dev_control_cache(self._device['devNo'], newValue)
  645. def stop_charging_port(self, port):
  646. portStr = fill_2_hexByte(hex(int(port)), 2)
  647. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  648. payload = {'IMEI': self._device['devNo'], "funCode": '0B', 'data': portStr},
  649. timeout = MQTT_TIMEOUT.SHORT)
  650. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  651. if devInfo['rst'] == -1:
  652. raise ServiceException(
  653. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  654. elif devInfo['rst'] == 1:
  655. raise ServiceException(
  656. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  657. data = devInfo['data'][16::]
  658. port = int(data[2:4], 16)
  659. leftTime = int(data[4:8], 16)
  660. return {'port': port, 'leftTime': leftTime}
  661. # 获取IC卡、投币、最大功率设置
  662. def get_IC_coin_power_config(self):
  663. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  664. payload = {'IMEI': self._device['devNo'], "funCode": '0C', 'data': '00'},
  665. timeout = MQTT_TIMEOUT.SHORT)
  666. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  667. if devInfo['rst'] == -1:
  668. raise ServiceException(
  669. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  670. elif devInfo['rst'] == 1:
  671. raise ServiceException(
  672. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  673. confData = devInfo['data'][18::]
  674. maxPower = int(confData[0:4], 16)
  675. icMoney = int(confData[4:6], 16)
  676. if len(confData) > 6:
  677. time1 = int(confData[6:10], 16)
  678. time2 = int(confData[10:14], 16)
  679. time3 = int(confData[14:18], 16)
  680. else:
  681. time1, time2, time3 = 0, 0, 0
  682. return {'maxPower': maxPower, 'icMoney': icMoney, 'time1': time1,
  683. 'time2': time2, 'time3': time3}
  684. def set_IC_coin_power_config(self, infoDict):
  685. data = ''
  686. data += fill_2_hexByte(hex(int(infoDict['maxPower'])), 4)
  687. data += fill_2_hexByte(hex(int(infoDict['icMoney'])), 2)
  688. data += fill_2_hexByte(hex(int(infoDict['time1'])), 4)
  689. data += fill_2_hexByte(hex(int(infoDict['time2'])), 4)
  690. data += fill_2_hexByte(hex(int(infoDict['time3'])), 4)
  691. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  692. payload = {'IMEI': self._device['devNo'], "funCode": '08', 'data': data},
  693. timeout = MQTT_TIMEOUT.SHORT)
  694. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  695. if devInfo['rst'] == -1:
  696. raise ServiceException(
  697. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  698. elif devInfo['rst'] == 1:
  699. raise ServiceException(
  700. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  701. def get_coin_card_enable(self):
  702. devs = Device.get_collection().find({'devNo': self._device['devNo']})
  703. if devs.count == 0:
  704. raise ServiceException(
  705. {'result': 2, 'description': u'没有找到设备哦'})
  706. return {'putCoins': devs[0].get('otherConf', {}).get('putCoins', False),
  707. 'icCard': devs[0].get('otherConf', {}).get('icCard', False)}
  708. def set_coin_card_enable(self, infoDict):
  709. data = ''
  710. if infoDict['putCoins']:
  711. data += '01'
  712. else:
  713. data += '00'
  714. if infoDict['icCard']:
  715. data += '01'
  716. else:
  717. data += '00'
  718. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  719. payload = {'IMEI': self._device['devNo'], "funCode": '09', 'data': data},
  720. timeout = MQTT_TIMEOUT.SHORT)
  721. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  722. if devInfo['rst'] == -1:
  723. raise ServiceException(
  724. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  725. elif devInfo['rst'] == 1:
  726. raise ServiceException(
  727. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  728. try:
  729. conf = Device.objects.get(devNo = self._device['devNo']).otherConf
  730. conf.update({'putCoins': infoDict['putCoins'], 'icCard': infoDict['icCard']})
  731. Device.get_collection().update({'devNo': self._device['devNo']}, {'$set': {'otherConf': conf}})
  732. except Exception, e:
  733. logger.error('update dev=%s coin enable ic enable e=%s' % (self._device['devNo'], e))
  734. # 获取设备配置参数
  735. def get_dev_setting(self):
  736. resultDict = self.get_IC_coin_power_config()
  737. tempDict = self.get_coin_card_enable()
  738. resultDict.update(tempDict)
  739. tempDict = self.get_gear_conf()
  740. resultDict.update(tempDict)
  741. tempDict = self.get_fullstop_cardrefund()
  742. resultDict.update(tempDict)
  743. dev = Device.objects.get(devNo = self._device['devNo'])
  744. # todo 电川新版本才支持浮充设置, 现网做兼容, 获取数据从数据库获取
  745. fuchongPower = dev.otherConf.get('fuchongPower', '')
  746. fuchongTime = dev.otherConf.get('fuchongTime', '')
  747. # 兼容刷卡时间 2a指令
  748. try:
  749. tempDict = self.get_freemode_volume_andsoon_config()
  750. except Exception:
  751. tempDict = {}
  752. card1Time = tempDict.get('card1Time', '')
  753. card2Time = tempDict.get('card2Time', '')
  754. card3Time = tempDict.get('card3Time', '')
  755. fuchongPower = tempDict.get('fuchongPower') or fuchongPower
  756. fuchongTime = tempDict.get('fuchongTime') or fuchongTime
  757. volume = tempDict.get('volume', '')
  758. resultDict.update({'card1Time': card1Time})
  759. resultDict.update({'card2Time': card2Time})
  760. resultDict.update({'card3Time': card3Time})
  761. resultDict.update({'volume': volume})
  762. resultDict.update({'fuchongPower': fuchongPower})
  763. resultDict.update({'fuchongTime': fuchongTime})
  764. return resultDict
  765. # 获取设备配置参数
  766. def set_dev_setting(self, setConf):
  767. keys = setConf.keys()
  768. if 'putCoins' in keys or 'icCard' in keys:
  769. self.set_coin_card_enable(setConf)
  770. if 'maxPower' in keys or 'icMoney' in keys or 'time1' in keys or 'time2' in keys or 'time3' in keys:
  771. self.set_IC_coin_power_config(setConf)
  772. def get_fullstop_cardrefund(self):
  773. try:
  774. dev = Device.objects.get(devNo = self._device['devNo'])
  775. except Exception, e:
  776. logger.error('get dev error = %s' % e)
  777. return {'autoStop': False, 'cardRefund': False}
  778. return {'autoStop': dev['otherConf'].get('autoStop', False),
  779. 'cardRefund': dev['otherConf'].get('cardRefund', False)}
  780. def set_fullstop_cardrefund(self, infoDict):
  781. data = ''
  782. if infoDict['autoStop']:
  783. data += '01'
  784. else:
  785. data += '00'
  786. if infoDict['cardRefund']:
  787. data += '01'
  788. else:
  789. data += '00'
  790. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  791. payload = {'IMEI': self._device['devNo'], "funCode": '13', 'data': data},
  792. timeout = MQTT_TIMEOUT.SHORT)
  793. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  794. if devInfo['rst'] == -1:
  795. raise ServiceException(
  796. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  797. elif devInfo['rst'] == 1:
  798. raise ServiceException(
  799. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  800. try:
  801. conf = Device.objects.get(devNo = self._device['devNo']).otherConf
  802. conf.update({'autoStop': infoDict['autoStop'], 'cardRefund': infoDict['cardRefund']})
  803. Device.get_collection().update({'devNo': self._device['devNo']}, {'$set': {'otherConf': conf}})
  804. except Exception, e:
  805. logger.error('update dev=%s coin enable ic enable e=%s' % (self._device['devNo'], e))
  806. def get_gear_conf(self):
  807. resultDict = {'power1': 0, 'power1ratio': 0, 'power2': 0,
  808. 'power2ratio': 0, 'power3': 0, 'power3ratio': 0}
  809. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  810. payload = {'IMEI': self._device['devNo'], "funCode": '15', 'data': '00'},
  811. timeout = MQTT_TIMEOUT.SHORT)
  812. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  813. if devInfo['rst'] == -1:
  814. raise ServiceException(
  815. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  816. elif devInfo['rst'] == 1:
  817. return resultDict
  818. confData = devInfo['data'][18::]
  819. power1 = int(confData[0:4], 16)
  820. power1ratio = int(confData[4:6], 16) * 10
  821. power2 = int(confData[6:10], 16)
  822. power2ratio = int(confData[10:12], 16) * 10
  823. power3 = int(confData[12:16], 16)
  824. power3ratio = int(confData[16:18], 16) * 10
  825. result = {
  826. 'power1': power1, 'power1ratio': power1ratio, 'power2': power2,
  827. 'power2ratio': power2ratio, 'power3': power3, 'power3ratio': power3ratio
  828. }
  829. if len(confData) > 31:
  830. power4 = int(confData[18:22], 16)
  831. power4ratio = int(confData[22:24], 16) * 10
  832. power5 = int(confData[24:28], 16)
  833. power5ratio = int(confData[28:30], 16) * 10
  834. result.update({'power4': power4, 'power4ratio': power4ratio,
  835. 'power5': power5, 'power5ratio': power5ratio})
  836. return result
  837. def set_gear_conf(self, infoDict):
  838. data = ''
  839. data += fill_2_hexByte(hex(int(infoDict['power1'])), 4)
  840. data += fill_2_hexByte(hex(int(infoDict['power1ratio']) / 10), 2)
  841. data += fill_2_hexByte(hex(int(infoDict['power2'])), 4)
  842. data += fill_2_hexByte(hex(int(infoDict['power2ratio']) / 10), 2)
  843. data += fill_2_hexByte(hex(int(infoDict['power3'])), 4)
  844. data += fill_2_hexByte(hex(int(infoDict['power3ratio']) / 10), 2)
  845. if infoDict.has_key('power4'):
  846. data += fill_2_hexByte(hex(int(infoDict['power4'])), 4)
  847. data += fill_2_hexByte(hex(int(infoDict['power4ratio']) / 10), 2)
  848. data += fill_2_hexByte(hex(int(infoDict['power5'])), 4)
  849. data += fill_2_hexByte(hex(int(infoDict['power5ratio']) / 10), 2)
  850. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  851. payload = {'IMEI': self._device['devNo'], "funCode": '14', 'data': data},
  852. timeout = MQTT_TIMEOUT.SHORT)
  853. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  854. if devInfo['rst'] == -1:
  855. raise ServiceException(
  856. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  857. elif devInfo['rst'] == 1:
  858. raise ServiceException(
  859. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  860. # 给实体卡充值
  861. def recharge_card(self, cardNo, money, orderNo = None):
  862. # type:(str,RMB)->(dict, RMB)
  863. try:
  864. data = 'EE1012{}'.format(make_six_bytes_session_id())
  865. cardNo = fill_2_hexByte(hex(int(cardNo)), 8)
  866. data += cardNo + fill_2_hexByte(hex(int(money * 10)), 4) + '0001'
  867. devInfo = MessageSender.send(device = self.device,
  868. cmd = DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC,
  869. payload = {
  870. 'IMEI': self._device['devNo'], 'data': data, 'funCode': '12'
  871. },
  872. timeout = MQTT_TIMEOUT.LONGEST)
  873. if devInfo['rst'] != 0:
  874. if devInfo['rst'] == ErrorCode.DEVICE_CONN_FAIL:
  875. # 离线无法判断是否成功, 认为充值成功, 走售后解决
  876. return {
  877. 'result': ErrorCode.DEVICE_CONN_FAIL,
  878. 'description': u'当前充电桩正在玩命找网络,请您稍候再试'
  879. }, None
  880. elif devInfo['rst'] == ErrorCode.BOARD_UART_TIMEOUT:
  881. return {
  882. 'result': ErrorCode.BOARD_UART_TIMEOUT,
  883. 'description': u'当前充电桩忙,无响应,请您稍候再试'
  884. }, None
  885. else:
  886. return {
  887. 'result': devInfo['rst'],
  888. 'description': u'系统异常'
  889. }, None
  890. resultData = devInfo['data']
  891. if resultData[4:6] != '16':
  892. return {
  893. 'result': ErrorCode.PARAMETER_ERROR_TO_BOX,
  894. 'description': u'充值返回报文命令码不为16'
  895. }, None
  896. balance = RMB(int(resultData[26:30], 16)) * Decimal('0.1')
  897. result = True if resultData[34:36] == '01' else False
  898. if result:
  899. return {
  900. 'result': ErrorCode.SUCCESS,
  901. 'description': ''
  902. }, balance
  903. else:
  904. return {
  905. 'result': ErrorCode.IC_RECHARGE_FAIL,
  906. 'description': u'充值失败'
  907. }, balance
  908. except Exception as e:
  909. logger.exception(e)
  910. return {
  911. 'result': ErrorCode.EXCEPTION,
  912. 'description': e.message
  913. }, None
  914. # 获取IC卡、投币、最大功率设置
  915. def get_freemode_volume_andsoon_config(self):
  916. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  917. payload = {'IMEI': self._device['devNo'], "funCode": '2A', 'data': '00'},
  918. timeout = MQTT_TIMEOUT.SHORT)
  919. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  920. if devInfo['rst'] == -1:
  921. raise ServiceException(
  922. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  923. elif devInfo['rst'] == 1:
  924. raise ServiceException(
  925. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  926. confData = devInfo['data'][18::]
  927. card1Time = int(confData[0:4], 16)
  928. card2Time = int(confData[4:8], 16)
  929. card3Time = int(confData[8:12], 16)
  930. chargeFree = True if confData[12:14] == '01' else False
  931. volume = int(confData[14:16], 16)
  932. fuchongPower = int(confData[16:20], 16)
  933. fuchongTime = int(confData[20:24], 16)
  934. return {'card1Time': card1Time, 'card2Time': card2Time, 'card3Time': card3Time,
  935. 'chargeFree': chargeFree, 'volume': volume, 'fuchongPower': fuchongPower,
  936. 'fuchongTime': fuchongTime}
  937. def get_mcu_version(self):
  938. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  939. payload = {'IMEI': self._device['devNo'], "funCode": '25', 'data': '00'},
  940. timeout = MQTT_TIMEOUT.SHORT)
  941. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  942. if devInfo['rst'] == -1:
  943. raise ServiceException(
  944. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  945. elif devInfo['rst'] == 1:
  946. raise ServiceException(
  947. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  948. confData = devInfo['data'][18::]
  949. mcuVersion = int(confData[0:4], 16)
  950. return {'mcuVersion': mcuVersion}
  951. def set_freemode_volume_config(self, infoDict):
  952. data = '01' if infoDict['chargeFree'] else '00'
  953. data += fill_2_hexByte(hex(int(infoDict.get('volume', 5))), 2)
  954. devInfo = MessageSender.send(device = self.device, cmd = self.make_random_cmdcode(),
  955. payload = {'IMEI': self._device['devNo'], "funCode": '27', 'data': data},
  956. timeout = MQTT_TIMEOUT.SHORT)
  957. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  958. if devInfo['rst'] == -1:
  959. raise ServiceException(
  960. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  961. elif devInfo['rst'] == 1:
  962. raise ServiceException(
  963. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  964. def set_fuchong_config(self, infoDict):
  965. data = fill_2_hexByte(hex(int(infoDict['fuchongPower']) * 10), 4)
  966. data += fill_2_hexByte(hex(int(infoDict['fuchongTime'])), 4)
  967. devInfo = MessageSender.send(device = self.device, cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
  968. payload = {'IMEI': self._device['devNo'], "funCode": '28', 'data': data},
  969. timeout = MQTT_TIMEOUT.SHORT)
  970. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  971. if devInfo['rst'] == -1:
  972. raise ServiceException(
  973. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  974. elif devInfo['rst'] == 1:
  975. raise ServiceException(
  976. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  977. dev = Device.objects.get(devNo = self._device['devNo'])
  978. dev.otherConf.update({'fuchongPower': int(infoDict['fuchongPower'])})
  979. dev.otherConf.update({'fuchongTime': int(infoDict['fuchongTime'])})
  980. dev.save()
  981. def set_card_time_config(self, infoDict):
  982. data = fill_2_hexByte(hex(int(infoDict['card1Time'])), 4)
  983. data += fill_2_hexByte(hex(int(infoDict['card2Time'])), 4)
  984. data += fill_2_hexByte(hex(int(infoDict['card3Time'])), 4)
  985. devInfo = MessageSender.send(device = self.device, cmd = self.make_random_cmdcode(),
  986. payload = {'IMEI': self._device['devNo'], "funCode": '29', 'data': data},
  987. timeout = MQTT_TIMEOUT.SHORT)
  988. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  989. if devInfo['rst'] == -1:
  990. raise ServiceException(
  991. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  992. elif devInfo['rst'] == 1:
  993. raise ServiceException(
  994. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  995. def set_device_function(self, request, lastSetConf):
  996. if request.POST.has_key('putCoins'):
  997. # putCoins = True if request.POST.get('putCoins') == 'true' else False
  998. putCoins = request.POST.get("putCoins", False)
  999. lastSetConf.update({'putCoins': putCoins})
  1000. self.set_coin_card_enable(lastSetConf)
  1001. if request.POST.has_key('icCard'):
  1002. # icCard = True if request.POST.get('icCard') == 'true' else False
  1003. icCard = request.POST.get("icCard", False)
  1004. lastSetConf.update({'icCard': icCard})
  1005. self.set_coin_card_enable(lastSetConf)
  1006. if request.POST.has_key('autoStop'):
  1007. # autoStop = True if request.POST.get('autoStop') == 'true' else False
  1008. autoStop = request.POST.get("autoStop", False)
  1009. lastSetConf.update({'autoStop': autoStop})
  1010. self.set_fullstop_cardrefund(lastSetConf)
  1011. if request.POST.has_key('cardRefund'):
  1012. # cardRefund = True if request.POST.get('cardRefund') == 'true' else False
  1013. cardRefund = request.POST.get("cardRefund", False)
  1014. lastSetConf.update({'cardRefund': cardRefund})
  1015. self.set_fullstop_cardrefund(lastSetConf)
  1016. if request.POST.has_key('chargeFree'):
  1017. # chargeFree = True if request.POST.get('chargeFree') == 'true' else False
  1018. chargeFree = request.POST.get("chargeFree", False)
  1019. lastSetConf.update({'chargeFree': chargeFree})
  1020. self.set_freemode_volume_config(lastSetConf)
  1021. def set_device_function_param(self, request, lastSetConf):
  1022. if request.POST.has_key('maxPower') and request.POST.has_key('icMoney'):
  1023. lastSetConf.update({'maxPower': int(request.POST.get('maxPower', 0))})
  1024. lastSetConf.update({'icMoney': int(request.POST.get('icMoney', 0))})
  1025. self.set_IC_coin_power_config(lastSetConf)
  1026. if request.POST.has_key('time1') and request.POST.has_key('time2') and request.POST.has_key('time3'):
  1027. lastSetConf.update({'time1': int(request.POST.get('time1', 0))})
  1028. lastSetConf.update({'time2': int(request.POST.get('time2', 0))})
  1029. lastSetConf.update({'time3': int(request.POST.get('time3', 0))})
  1030. self.set_IC_coin_power_config(lastSetConf)
  1031. if request.POST.has_key('power1') and request.POST.has_key('power1ratio'):
  1032. lastSetConf.update({'power1': int(request.POST.get('power1', 0))})
  1033. lastSetConf.update({'power1ratio': int(request.POST.get('power1ratio', 0))})
  1034. lastSetConf.update({'power2': int(request.POST.get('power2', 0))})
  1035. lastSetConf.update({'power2ratio': int(request.POST.get('power2ratio', 0))})
  1036. lastSetConf.update({'power3': int(request.POST.get('power3', 0))})
  1037. lastSetConf.update({'power3ratio': int(request.POST.get('power3ratio', 0))})
  1038. lastSetConf.update({'power4': int(request.POST.get('power4', 0))})
  1039. lastSetConf.update({'power4ratio': int(request.POST.get('power4ratio', 0))})
  1040. lastSetConf.update({'power5': int(request.POST.get('power5', 0))})
  1041. lastSetConf.update({'power5ratio': int(request.POST.get('power5ratio', 0))})
  1042. self.set_gear_conf(lastSetConf)
  1043. if request.POST.has_key('card1Time') and request.POST.has_key('card2Time') and request.POST.has_key(
  1044. 'card3Time'):
  1045. lastSetConf.update({'card1Time': int(request.POST.get('card1Time', 0))})
  1046. lastSetConf.update({'card2Time': int(request.POST.get('card2Time', 0))})
  1047. lastSetConf.update({'card3Time': int(request.POST.get('card3Time', 0))})
  1048. self.set_card_time_config(lastSetConf)
  1049. if 'fuchongPower' in request.POST and 'fuchongTime' in request.POST:
  1050. fuchongPower = 0 if request.POST.get('fuchongPower') == '' else int(request.POST.get('fuchongPower'))
  1051. fuchongTime = 0 if request.POST.get('fuchongTime') == '' else int(request.POST.get('fuchongTime'))
  1052. lastSetConf.update({'fuchongPower': fuchongPower})
  1053. lastSetConf.update({'fuchongTime': fuchongTime})
  1054. self.set_fuchong_config(lastSetConf)
  1055. if 'cardPassword' in request.POST:
  1056. lastSetConf.update({'cardPassword': int(request.POST.get('cardPassword', 0))})
  1057. self.set_IC_card_password(lastSetConf)
  1058. if 'cardNoRangeStart' in request.POST and 'cardNoRangeEnd' in request.POST:
  1059. lastSetConf.update({'cardNoRangeStart': int(request.POST.get('cardNoRangeStart', 0))})
  1060. lastSetConf.update({'cardNoRangeEnd': int(request.POST.get('cardNoRangeEnd', 0))})
  1061. self.set_IC_card_range(lastSetConf)
  1062. def get_IC_card_password(self):
  1063. raise ServiceException(
  1064. {'result': 2, 'description': u'您的设备暂不支持该功能'})
  1065. def set_IC_card_password(self, lastSetConf):
  1066. raise ServiceException(
  1067. {'result': 2, 'description': u'您的设备暂不支持该功能'})
  1068. def set_IC_card_range(self, lastSetConf):
  1069. raise ServiceException(
  1070. {'result': 2, 'description': u'您的设备暂不支持该功能'})
  1071. def format_upload_power(self, power):
  1072. return float(power / 10)
  1073. @property
  1074. def isHaveStopEvent(self):
  1075. return True
  1076. def get_server_setting(self):
  1077. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_DIANCHUAN_HIGH:
  1078. default_refund_protection_time = 3
  1079. else:
  1080. default_refund_protection_time = 5
  1081. return {
  1082. 'refundProtectionTime': int(
  1083. self.device.get_other_conf_item('refundProtectionTime', default_refund_protection_time)),
  1084. }
  1085. def set_server_setting(self, payload):
  1086. refundProtectionTime = int(payload['refundProtectionTime'])
  1087. self.device.update_other_conf(refundProtectionTime=refundProtectionTime)