yuze5_dianchuan.py 65 KB

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