weifule_mini.py 59 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import copy
  4. import datetime
  5. import time
  6. import uuid
  7. from decimal import Decimal
  8. from apilib.utils_AES import EncryptDate
  9. from apilib.utils_datetime import to_datetime
  10. from apps.web.constant import DeviceCmdCode, Const, MQTT_TIMEOUT, FAULT_CODE, ErrorCode
  11. from apps.web.core.adapter.base import SmartBox
  12. from apps.web.core.exceptions import ServiceException
  13. from apps.web.core.networking import MessageSender
  14. from apps.web.device.models import Device
  15. from apps.web.user.models import ConsumeRecord, Card
  16. cardKey = 'FR4e1OFCnDdrYA7u'
  17. class ChargingWEIFULEBox(SmartBox):
  18. def __init__(self, device):
  19. super(ChargingWEIFULEBox, self).__init__(device)
  20. def translate_funcode(self, fun_code):
  21. fun_codeDict = {
  22. '01': u'查询所有端口状态',
  23. '02': u'查询端口详细信息',
  24. '03': u'上报投币充电事件',
  25. '04': u'上报刷卡事件',
  26. '05': u'上报充电结束事件',
  27. '06': u'远程停止充电',
  28. '07': u'远程启动充电',
  29. '08': u'查询投币总额',
  30. '09': u'清除投币总数',
  31. '0A': u'查询订单信息',
  32. }
  33. return fun_codeDict.get(fun_code, '')
  34. def translate_event_cmdcode(self, cmdCode):
  35. cmdDict = {
  36. }
  37. return cmdDict.get(cmdCode, '')
  38. def test(self, coins):
  39. data = {'fun_code': 0x07, 'order_id': '1111', 'coins': coins, 'port': 1, 'time': 60}
  40. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  41. {'IMEI': self._device['devNo'], 'data': data})
  42. return devInfo
  43. def check_feedback_result(self, devInfo):
  44. if not devInfo.has_key('rst'):
  45. raise ServiceException({'result': 2, 'description': u'报文异常'})
  46. if devInfo['rst'] == -1:
  47. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  48. if devInfo['rst'] == 1:
  49. raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'})
  50. if devInfo['rst'] == 2:
  51. raise ServiceException({'result': 2, 'description': u'端口被禁用'})
  52. if devInfo['rst'] == 3:
  53. raise ServiceException({'result': 2, 'description': u'端口计量器故障'})
  54. if devInfo['rst'] == 4:
  55. raise ServiceException({'result': 2, 'description': u'设备订单已达上限'})
  56. if devInfo['rst'] == 5:
  57. raise ServiceException({'result': 2, 'description': u'设备正在自检'})
  58. def _check_package(self, package):
  59. unit = package.get("unit")
  60. _time = package.get("time")
  61. chrmt = self.device['otherConf'].get('chrmt')
  62. if not chrmt:
  63. chrmt = self.get_dev_setting().get('chrmt')
  64. if chrmt == 'TIME' or chrmt == 'POWER':
  65. if unit == u'秒':
  66. if int(package['time']) < 60:
  67. raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'})
  68. _time = int(package['time'])
  69. unit = '秒'
  70. elif unit == u'分钟':
  71. _time = int(package['time']) * 60
  72. unit = '秒'
  73. elif unit == u'小时':
  74. _time = int(float(package['time']) * 60 * 60)
  75. unit = '秒'
  76. elif unit == u'天':
  77. _time = int(float(package['time']) * 60 * 60 * 24)
  78. unit = '秒'
  79. else:
  80. raise ServiceException({"result": 2, "description": u"套餐单位错误,应选取单位(时间),请联系经销商"})
  81. elif chrmt == 'ELEC':
  82. if unit == u'度':
  83. _time = int(float(package['time']) * 1000000) # 微度,需要乘于16个零
  84. else:
  85. raise ServiceException({"result": 2, "description": u"套餐单位错误,应选取单位(度),请联系经销商"})
  86. else:
  87. raise ServiceException({"result": 2, "description": u"套餐单位错误,应选取单位(时间,度),请联系经销商"})
  88. return _time, unit
  89. def check_dev_status(self, attachParas = None):
  90. if attachParas.get("isTempPackage") == True:
  91. washConfig = self.device.get("tempWashConfig", {})
  92. else:
  93. washConfig = self.device.get("washConfig", {})
  94. packageId = attachParas.get("packageId")
  95. if not packageId: # 快捷支付过来的 第一次拉起支付的时候已经校验通过了
  96. return
  97. package = washConfig.get(packageId)
  98. self._check_package(package)
  99. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get('price') == 0:
  100. port = int(attachParas['chargeIndex'])
  101. lineInfo = Device.get_dev_control_cache(self.device.devNo).get(str(port), {})
  102. if lineInfo.get('status') == Const.DEV_WORK_STATUS_WORKING:
  103. raise ServiceException({'result': 2, 'description': u'当前端口已处于工作状态,无法使用充满自停套餐, 请换个端口进行充电'})
  104. def start_device(self, package, openId, attachParas):
  105. if attachParas is None:
  106. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  107. if not attachParas.has_key('chargeIndex'):
  108. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  109. port = int(attachParas['chargeIndex'])
  110. unit = package.get('unit', u'分钟')
  111. needTime, power = None, None
  112. coins = int(float(package['coins']) * 100) # 单位为分
  113. onPoints = attachParas.get('onPoints')
  114. if onPoints: # 远程上分
  115. self.stop_charging_port(port)
  116. order_no = ConsumeRecord.make_no()
  117. else:
  118. order_no = str(attachParas.get("orderNo"))
  119. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get('price') == 0:
  120. lineInfo = Device.get_dev_control_cache(self.device.devNo).get(str(port), {})
  121. if lineInfo.get('status') == Const.DEV_WORK_STATUS_WORKING:
  122. raise ServiceException({'result': 2, 'description': u'当前端口已处于工作状态, 请换个端口使用充电'})
  123. needTime = 999 * 60
  124. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': 10 * 100, 'port': port, 'time': needTime}
  125. else:
  126. if unit == u'秒':
  127. if int(package['time']) < 60:
  128. raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'})
  129. needTime = int(float(package['time']))
  130. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  131. elif unit == u'分钟':
  132. needTime = int(package['time']) * 60
  133. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  134. elif unit == u'小时':
  135. needTime = int(float(package['time']) * 60 * 60)
  136. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  137. elif unit == u'天':
  138. needTime = int(float(package['time']) * 60 * 60 * 24)
  139. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  140. elif unit == u'度':
  141. power = int(float(package['time']) * 1000000) # 微度,需要乘于16个零
  142. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'elec': power}
  143. else:
  144. needTime = int(package['time'])
  145. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  146. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  147. {'IMEI': self._device['devNo'], 'data': data}, timeout=MQTT_TIMEOUT.START_DEVICE)
  148. self.check_feedback_result(devInfo)
  149. data = devInfo['data']
  150. if devInfo['rst'] == 0: # 成功
  151. devInfo['consumeOrderNo'] = order_no
  152. newValue = {
  153. str(port): {
  154. 'status': Const.DEV_WORK_STATUS_WORKING,
  155. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
  156. }
  157. }
  158. else: # TODO result的枚举列出原因
  159. raise ServiceException({'result': 2, 'description': u'充电桩响应异常,请您稍后再试哦'})
  160. if needTime:
  161. finishedTime = int(time.time()) + needTime
  162. devInfo['needTime'] = needTime / 60
  163. if power:
  164. finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束
  165. devInfo['needElec'] = float(package['time'])
  166. newValue.update({'finishedTime': finishedTime})
  167. Device.update_dev_control_cache(self._device['devNo'], newValue)
  168. devInfo['finished_time'] = finishedTime
  169. devInfo['consumeOrderNo'] = order_no
  170. return devInfo
  171. def analyze_event_data(self, data):
  172. if data.get('fun_code') == '34': # 如果是结束事件,需要把reason翻译出来
  173. descDict = {
  174. '1': u'开始充电,但是没有接充电器',
  175. '2': u'充电过程中,插座脱落',
  176. '3': u'用户按下关闭按钮关闭',
  177. '4': u'用户刷卡结束充电',
  178. '5': u'远程结束充电',
  179. '6': u'充电端口故障,为了安全主动关闭',
  180. '7': u'订购的时间使用完毕',
  181. '8': u'订购的电量使用完毕',
  182. '9': u'本端口功率过载,主动关闭',
  183. '10': u'整机功率过载,主动关闭',
  184. '11': u'其他异常导致的关闭'
  185. }
  186. order = data['order']
  187. order['reason'] = descDict.get(str(order['closeType']), u'')
  188. data['order'] = order
  189. return data
  190. def get_dev_consume_count(self):
  191. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  192. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x08}})
  193. self.check_feedback_result(devInfo)
  194. data = devInfo['data']
  195. return {'cardFee': data['total_card'] / 100.0, 'coinFee': data['total_coin'] / 100.0} # 单位为分
  196. def get_many_port_info(self, portList):
  197. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  198. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x12}})
  199. self.check_feedback_result(devInfo)
  200. pay_unit = self.show_pay_unit
  201. resultDict = {}
  202. for port, data in devInfo['data']['details'].items():
  203. if port not in portList:
  204. continue
  205. result = {'index': port}
  206. result['status'] = self.__translate_status_from_str(data['status'])
  207. result['power'] = round(data.get('watt', 0), 2)
  208. result['ampere'] = round(data.get('ampr', 0) / 1000.0, 2)
  209. result['voltage'] = round(data.get('volt'), 2)
  210. _wait = []
  211. for exec_order in data['orders']:
  212. if exec_order.get('status') == 'running':
  213. result['coins'] = round(exec_order.get('coins', 0) * 0.01, 2)
  214. result['usedTime'] = round(exec_order.get('time', 0) / 60.0, 1)
  215. result['usedElec'] = round(exec_order.get('elec') / 1000000.0, 2)
  216. result['startTime'] = datetime.datetime.fromtimestamp(int(exec_order.get('execute_time', 0))).strftime(
  217. '%m-%d %H:%M:%S')
  218. if exec_order.get('chrmt') == 'TIME':
  219. result['needTime'] = round(exec_order.get('amount_time', 0) / 60.0, 1)
  220. result['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1)
  221. leftMoney = round((result['coins'] * exec_order.get('left_time', 0) / exec_order.get('amount_time', 0)), 2)
  222. consumeMoney = round((result['coins'] - leftMoney), 2)
  223. if exec_order.get('order_type') == 'apps_start':
  224. result['consumeType'] = 'mobile'
  225. result['consumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  226. result['leftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  227. try:
  228. orderNo = exec_order.get('id', 0)
  229. order = ConsumeRecord.objects.get(orderNo=orderNo)
  230. result['nickName'] = order.user.nickname
  231. package = order.package
  232. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get(
  233. 'price') == 0: # 后付费
  234. result['consumeType'] = 'postpaid'
  235. result['needTime'] = '充满自停'
  236. result.pop('needElec', None)
  237. result.pop('leftMoney', None)
  238. result.pop('leftTime', None)
  239. result.pop('leftElec', None)
  240. except:
  241. pass
  242. if exec_order.get('order_type') == 'card_start':
  243. result['consumeType'] = 'card'
  244. result['cardNo'] = str(int(exec_order.get('card_no', 0), 16))
  245. result['cardConsumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  246. result['cardLeftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  247. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.01, 2), pay_unit)
  248. try:
  249. card = Card.objects.get(cardNo=str(int(exec_order.get('card_no', 0), 16)))
  250. result['nickName'] = card.cardName or card.nickName
  251. if card.cardType == 'ID': # id卡 订单余额显示有问题
  252. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.001, 2),
  253. pay_unit)
  254. except:
  255. pass
  256. elif exec_order.get('chrmt') == 'ELEC':
  257. result['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2)
  258. result['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4)
  259. leftMoney = round((result['coins'] * exec_order.get('left_elec', 0) / exec_order.get('amount_elec', 0)), 2)
  260. consumeMoney = round((result['coins'] - leftMoney), 2)
  261. if exec_order.get('order_type') == 'apps_start':
  262. result['consumeType'] = 'mobile'
  263. result['consumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  264. result['leftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  265. try:
  266. orderNo = exec_order.get('id')
  267. order = ConsumeRecord.objects.get(orderNo=orderNo)
  268. result['nickName'] = order.user.nickname
  269. package = order.package
  270. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get(
  271. 'price') == 0: # 后付费
  272. result['consumeType'] = 'postpaid'
  273. result['needTime'] = '充满自停'
  274. result.pop('needElec', None)
  275. result.pop('leftMoney', None)
  276. result.pop('leftTime', None)
  277. result.pop('leftElec', None)
  278. except:
  279. pass
  280. if exec_order.get('order_type') == 'card_start':
  281. result['consumeType'] = 'card'
  282. result['cardNo'] = str(int(exec_order.get('card_no', 0), 16))
  283. result['cardConsumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  284. result['cardLeftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  285. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.01, 2), pay_unit)
  286. try:
  287. card = Card.objects.get(cardNo=str(int(exec_order.get('card_no', 0), 16)))
  288. result['nickName'] = card.cardName or card.nickName
  289. if card.cardType == 'ID': # id卡 订单余额显示有问题
  290. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.001, 2),
  291. pay_unit)
  292. except:
  293. pass
  294. else:
  295. pass
  296. elif exec_order.get('status') == 'waiting':
  297. _one = {}
  298. if exec_order.get('chrmt') == 'TIME':
  299. _one['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1)
  300. _one['needTime'] = '{}分钟'.format(round(exec_order.get('amount_time', 0) / 60.0, 1))
  301. elif exec_order.get('chrmt') == 'ELEC':
  302. _one['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4)
  303. _one['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2)
  304. else:
  305. pass
  306. if exec_order.get('order_type') == 'apps_start':
  307. _one['consumeType'] = 'mobile'
  308. _one['coins'] = '{}{}'.format(round(exec_order.get('coins', 0) / 100.0, 2), pay_unit)
  309. try:
  310. order = ConsumeRecord.objects.get(orderNo=exec_order.get('id', 0))
  311. _one['nickName'] = order.user.nickname
  312. except Exception:
  313. pass
  314. elif exec_order.get('order_type') == 'card_start':
  315. _one['consumeType'] = 'card'
  316. _one['coins'] = '{}{}'.format(round(exec_order.get('coins', 0) / 100.0, 2), pay_unit)
  317. _one['cardNo'] = str(int(exec_order.get('card_no', 0), 16))
  318. _one['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.01, 2), pay_unit)
  319. try:
  320. card = Card.objects.get(cardNo=str(int(exec_order.get('card_no', 0), 16)))
  321. _one['nickName'] = card.cardName or card.nickName
  322. if card.cardType == 'ID': # id卡 订单余额显示有问题
  323. _one['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.001, 2), pay_unit)
  324. except:
  325. pass
  326. else:
  327. pass
  328. _wait.append(_one)
  329. else:
  330. pass
  331. if _wait:
  332. result['waittingOrder'] = _wait
  333. resultDict[port] = result
  334. return resultDict
  335. def get_port_info(self, line):
  336. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  337. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x02, 'port': int(line)}})
  338. self.check_feedback_result(devInfo)
  339. portInfo = devInfo.get('data', {})
  340. result = {}
  341. pay_unit = self.show_pay_unit
  342. exec_orders = portInfo.get('orders', [])
  343. _wait = []
  344. for exec_order in exec_orders:
  345. if exec_order['status'] == 'running':
  346. result['voltage'] = round(portInfo.get('volt', 0), 2)
  347. result['power'] = round(portInfo.get('watt', 0), 2)
  348. result['ampere'] = round((portInfo.get('ampr', 0) * 0.001), 2)
  349. result['coins'] = '{}'.format(round(exec_order['coins'] / 100.0, 2))
  350. result['usedTime'] = round(exec_order.get('time', 0) / 60, 1)
  351. result['usedElec'] = round(exec_order.get('elec', 0) * 0.000001, 4)
  352. if exec_order['chrmt'] == 'TIME':
  353. result['leftTime'] = round(exec_order.get('left_time', 0) / 60, 1)
  354. result['needTime'] = '{}分钟'.format(round(exec_order['amount_time'] / 60.0, 1))
  355. elif exec_order['chrmt'] == 'ELEC':
  356. result['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2)
  357. result['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4)
  358. else:
  359. pass
  360. if exec_order['order_type'] == 'apps_start':
  361. result['consumeType'] = 'mobile'
  362. result['consumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), pay_unit)
  363. result['leftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2),
  364. pay_unit)
  365. try:
  366. orderNo = exec_order['id']
  367. order = ConsumeRecord.objects.get(orderNo=orderNo)
  368. result['nickName'] = order.user.nickname
  369. package = order.package
  370. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get(
  371. 'price') == 0: # 后付费
  372. result['consumeType'] = 'postpaid'
  373. result['needTime'] = '充满自停'
  374. result.pop('needElec', None)
  375. result.pop('leftMoney', None)
  376. result.pop('leftTime', None)
  377. result.pop('leftElec', None)
  378. except:
  379. pass
  380. if exec_order['order_type'] == 'card_start':
  381. result['consumeType'] = 'card'
  382. result['cardNo'] = str(int(exec_order['card_no'], 16))
  383. result['cardConsumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2),
  384. pay_unit)
  385. result['cardLeftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2),
  386. pay_unit)
  387. result['cardBalance'] = '{}{}'.format(round(exec_order['balance'] * 0.01, 2), pay_unit)
  388. try:
  389. card = Card.objects.get(cardNo=exec_order['card_no'])
  390. result['nickName'] = card.cardName or card.nickName
  391. except:
  392. pass
  393. else:
  394. pass
  395. if exec_order['status'] == 'waiting':
  396. _one = {}
  397. if exec_order['chrmt'] == 'TIME':
  398. _one['leftTime'] = round(exec_order.get('left_time', 0) / 60, 1)
  399. _one['needTime'] = '{}分钟'.format(round(exec_order['amount_time'] / 60.0, 1))
  400. elif exec_order['chrmt'] == 'ELEC':
  401. _one['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2)
  402. _one['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4)
  403. else:
  404. pass
  405. if exec_order['order_type'] == 'apps_start':
  406. _one['consumeType'] = 'mobile'
  407. _one['coins'] = '{}{}'.format(round(exec_order['coins'] / 100.0, 2), pay_unit)
  408. try:
  409. order = ConsumeRecord.objects.get(orderNo=exec_order['id'])
  410. _one['nickName'] = order.user.nickname
  411. except Exception:
  412. pass
  413. elif exec_order['order_type'] == 'card_start':
  414. _one['consumeType'] = 'card'
  415. _one['coins'] = '{}{}'.format(round(exec_order['coins'] / 100.0, 2), pay_unit)
  416. _one['cardNo'] = str(int(exec_order['card_no'], 16))
  417. _one['cardBalance'] = '{}{}'.format(round(exec_order['balance'] * 0.01, 2), pay_unit)
  418. try:
  419. card = Card.objects.get(cardNo=exec_order['card_no'])
  420. _one['nickName'] = card.cardName or card.nickName
  421. except Exception:
  422. pass
  423. else:
  424. pass
  425. _wait.append(_one)
  426. if _wait:
  427. result['waittingOrder'] = _wait
  428. return result
  429. def __translate_status_from_str(self, status):
  430. dictConf = {
  431. 'idle': Const.DEV_WORK_STATUS_IDLE,
  432. 'busy': Const.DEV_WORK_STATUS_WORKING,
  433. 'forbid': Const.DEV_WORK_STATUS_FORBIDDEN,
  434. 'fault': Const.DEV_WORK_STATUS_FAULT,
  435. 'running': Const.DEV_WORK_STATUS_WORKING
  436. }
  437. return dictConf.get(status, Const.DEV_WORK_STATUS_IDLE)
  438. # 访问设备,获取设备端口信息
  439. def get_port_status_from_dev(self):
  440. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  441. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x01}})
  442. self.check_feedback_result(devInfo)
  443. data = devInfo['data']
  444. result = {}
  445. portNum = data.get('total', 10)
  446. ii = 0
  447. while ii < portNum:
  448. ii += 1
  449. result[str(ii)] = {'status': self.__translate_status_from_str(data['status'].get(str(ii)))}
  450. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  451. Device.update_dev_control_cache(self._device['devNo'],
  452. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  453. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  454. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  455. for strPort, info in result.items():
  456. if ctrInfo.has_key(strPort):
  457. ctrInfo[strPort].update({'status': info['status']})
  458. else:
  459. ctrInfo[strPort] = info
  460. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  461. return result
  462. def get_port_status(self, force=False):
  463. if force:
  464. return self.get_port_status_from_dev()
  465. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  466. if not ctrInfo.has_key('allPorts'):
  467. self.get_port_status_from_dev()
  468. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  469. allPorts = ctrInfo.get('allPorts', 10)
  470. statusDict = {}
  471. for ii in range(allPorts):
  472. tempDict = ctrInfo.get(str(ii + 1), {})
  473. if tempDict.has_key('status'):
  474. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  475. elif tempDict.has_key('isStart'):
  476. if tempDict['isStart']:
  477. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  478. else:
  479. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  480. else:
  481. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  482. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  483. Device.update_dev_control_cache(self._device['devNo'],
  484. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  485. return statusDict
  486. def lock_unlock_port(self, port, lock=True):
  487. portInfo = self.get_port_info(port)
  488. if portInfo and portInfo['status'] == Const.DEV_WORK_STATUS_WORKING and lock:
  489. raise ServiceException({'result': 2, 'description': u'端口正忙,请先关闭端口后,再禁止端口'})
  490. typeStr = 'deactive' if lock else 'active'
  491. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  492. {'IMEI': self._device['devNo'],
  493. 'data': {'port': int(port), 'type': typeStr, 'fun_code': 0x0D}})
  494. self.check_feedback_result(devInfo)
  495. if devInfo['rst'] == 0:
  496. if lock:
  497. Device.update_dev_control_cache(self._device['devNo'],
  498. {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  499. else:
  500. Device.update_dev_control_cache(self._device['devNo'],
  501. {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  502. else:
  503. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  504. def active_deactive_port(self, port, active):
  505. if active:
  506. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  507. return self.stop_charging_port(port)
  508. # 停止该端口下的所有任务
  509. def stop_charging_port(self, port):
  510. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  511. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x06, 'port': port}})
  512. self.check_feedback_result(devInfo)
  513. if devInfo['rst'] == 0:
  514. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  515. return True if devInfo['rst'] == 0 else False
  516. def get_order(self, order_no):
  517. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  518. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x0A, 'order_id': order_no}})
  519. self.check_feedback_result(devInfo)
  520. data = devInfo.get('data', {})
  521. exec_order = data.get('order', {})
  522. result = {}
  523. if not exec_order.get('order_type'): # 有可能没有订单,应该返回空
  524. return result
  525. pay_unit = self.show_pay_unit
  526. # result['ampere'] = round(data.get('ampr', 0) / 1000.0, 2)
  527. # result['voltage'] = round(data.get('volt'), 2)
  528. result['status'] = exec_order.get('status', 0)
  529. result['coins'] = round(exec_order.get('coins', 0) * 0.01, 2)
  530. result['usedTime'] = round(exec_order.get('time', 0) / 60.0, 1)
  531. result['usedElec'] = round(exec_order.get('elec') / 1000000.0, 2)
  532. if exec_order.get('status') == 'running':
  533. result['startTime'] = datetime.datetime.fromtimestamp(int(exec_order.get('execute_time', 0))).strftime(
  534. '%m-%d %H:%M:%S')
  535. result['power'] = round(exec_order.get('watt', 0), 2)
  536. if exec_order.get('chrmt') == 'TIME':
  537. result['needTime'] = round(exec_order.get('amount_time', 0) / 60.0, 1)
  538. result['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1)
  539. leftMoney = round((result['coins'] * exec_order.get('left_time', 0) / exec_order.get('amount_time', 0)), 2)
  540. consumeMoney = round((result['coins'] - leftMoney), 2)
  541. if exec_order.get('order_type') == 'apps_start':
  542. result['consumeType'] = 'mobile'
  543. result['consumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  544. result['leftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  545. try:
  546. orderNo = exec_order.get('id', 0)
  547. order = ConsumeRecord.objects.get(orderNo=orderNo)
  548. result['nickName'] = order.user.nickname
  549. package = order.package
  550. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get(
  551. 'price') == 0: # 后付费
  552. result['consumeType'] = 'postpaid'
  553. result['needTime'] = '充满自停'
  554. result.pop('needElec', None)
  555. result.pop('leftMoney', None)
  556. result.pop('leftTime', None)
  557. result.pop('leftElec', None)
  558. except:
  559. pass
  560. if exec_order.get('order_type') == 'card_start':
  561. result['consumeType'] = 'card'
  562. result['cardNo'] = str(int(exec_order.get('card_no', 0), 16))
  563. result['cardConsumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  564. result['cardLeftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  565. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.01, 2), pay_unit)
  566. try:
  567. card = Card.objects.get(cardNo=str(int(exec_order.get('card_no', 0), 16)))
  568. result['cardName'] = card.cardName or card.nickName
  569. if card.cardType == 'ID': # id卡 订单余额显示有问题
  570. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.001, 2), pay_unit)
  571. except:
  572. pass
  573. elif exec_order.get('chrmt') == 'ELEC':
  574. result['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2)
  575. result['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4)
  576. leftMoney = round((result['coins'] * exec_order.get('left_elec', 0) / exec_order.get('amount_elec', 0)), 2)
  577. consumeMoney = round((result['coins'] - leftMoney), 2)
  578. if exec_order.get('order_type') == 'apps_start':
  579. result['consumeType'] = 'mobile'
  580. result['consumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  581. result['leftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  582. try:
  583. orderNo = exec_order.get('id', 0)
  584. order = ConsumeRecord.objects.get(orderNo=orderNo)
  585. result['nickName'] = order.user.nickname
  586. package = order.package
  587. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get(
  588. 'price') == 0: # 后付费
  589. result['consumeType'] = 'postpaid'
  590. result['needTime'] = '充满自停'
  591. result.pop('needElec', None)
  592. result.pop('leftMoney', None)
  593. result.pop('leftTime', None)
  594. result.pop('leftElec', None)
  595. except:
  596. pass
  597. if exec_order.get('order_type') == 'card_start':
  598. result['consumeType'] = 'card'
  599. result['cardNo'] = str(int(exec_order.get('card_no', 0), 16))
  600. result['cardConsumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  601. result['cardLeftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  602. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.01, 2), pay_unit)
  603. try:
  604. card = Card.objects.get(cardNo=str(int(exec_order.get('card_no', 0), 16)))
  605. result['cardName'] = card.cardName or card.nickName
  606. if card.cardType == 'ID': # id卡 订单余额显示有问题
  607. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.001, 2), pay_unit)
  608. except:
  609. pass
  610. else:
  611. pass
  612. return result
  613. def response_card_balance(self, cardNo, balance, result):
  614. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  615. {'IMEI': self._device['devNo'],
  616. 'data': {'fun_code': 35, 'card_no': cardNo, 'balance': int(100 * float(balance)),
  617. 'result': result}})
  618. self.check_feedback_result(devInfo)
  619. # 获取设备配置参数
  620. def get_dev_setting(self):
  621. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  622. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x0C}})
  623. self.check_feedback_result(devInfo)
  624. result = devInfo['data']
  625. result.update({
  626. 'fcharge_watt': result['fcharge']['watt'],
  627. 'fcharge_time': result['fcharge']['time'],
  628. 'fcharge_check': result['fcharge'].get('check', 10),
  629. })
  630. # 按功率分档收费
  631. TIME = result['price']['TIME'] # [{"max":"xxx","time":"xxx"}]
  632. result['package_time'] = []
  633. for _ in TIME:
  634. item = {}
  635. item['power'] = _[0]
  636. item['time'] = int(_[1]) / 60 # 时间未秒转换为分
  637. result['package_time'].append(item)
  638. # 按功率收费显示
  639. package_power = []
  640. for _item in TIME:
  641. package_power.append({'power': _item[0], 'price': round(1.0 / (_item[1] / 60.0 / 60.0), 2)})
  642. result['package_power'] = package_power
  643. # 按电量收费
  644. result['package_elec'] = []
  645. elec = Decimal(result['price']['ELEC']) / 1000000 # 默认为毫度
  646. price = result['price'].get('price', 1) # 默认为一块钱
  647. result['package_elec'].append({'price': price, 'elec': elec})
  648. noload_check = result.get('noload_check')
  649. if not noload_check:
  650. noload_check = {
  651. "time": 99,
  652. "watt": 99
  653. },
  654. result['emptyPower'] = noload_check['watt']
  655. result['emptyTime'] = noload_check['time']
  656. defaultVolume = 0
  657. volumeList = []
  658. for k, v in result['volume'].items():
  659. if k == 'default':
  660. defaultVolume = v
  661. else:
  662. tempList = k.split('-')
  663. volumeList.append({'start': tempList[0], 'end': tempList[1], 'volume': v})
  664. result.pop('volume')
  665. result['volume'] = defaultVolume
  666. result['volume_list'] = volumeList
  667. result['minAfterStartCoins'] = self.device['otherConf'].get('minAfterStartCoins', 0)
  668. result['refundProtection'] = self.device['otherConf'].get('refundProtection', 5)
  669. result['chrmt'] = self.device['otherConf'].get('chrmt') or result['chrmt']
  670. return result
  671. # 获取设备配置参数
  672. def set_dev_setting(self, setConf):
  673. # 时间套餐不能为空
  674. if setConf.has_key('package_time') and len(setConf['package_time']) == 0:
  675. raise ServiceException({'result': 2, 'description': u'按时间计费的套餐不能为空'})
  676. # 检查数据
  677. if not (int(setConf['fcharge_time']) >= 1 and int(setConf['fcharge_time']) <= 300):
  678. raise ServiceException({'result': 2, 'description': u'浮充时间必须大于等于1分钟,小于等于300分钟'})
  679. if not (int(setConf['fcharge_check']) >= 2 and int(setConf['fcharge_check']) <= 30):
  680. raise ServiceException({'result': 2, 'description': u'浮充检测时间必须大于等于2分钟,小于等于30分钟'})
  681. if not (int(setConf['fcharge_watt']) >= 20 and int(setConf['fcharge_watt']) <= 100):
  682. raise ServiceException({'result': 2, 'description': u'浮充功率必须大于等于20瓦,小于等于100瓦'})
  683. if not (int(setConf['volume']) >= 0 and int(setConf['volume']) <= 7):
  684. raise ServiceException({'result': 2, 'description': u'音量必须大于等于0,小于等于7'})
  685. volumeDict = {'default': int(setConf['volume'])}
  686. for vl in setConf['volume_list']:
  687. startTime = to_datetime('2020-01-01 %s:00' % vl['start'])
  688. endTime = to_datetime('2020-01-01 %s:00' % vl['end'])
  689. if endTime <= startTime:
  690. raise ServiceException({'result': 2, 'description': u'结束时间一定要大于起始时间。比如起始时间为07:00,结束时间为23:59'})
  691. volumeDict['%s-%s' % (vl['start'], vl['end'])] = int(vl['volume'])
  692. setConf.pop('volume')
  693. setConf.pop('volume_list')
  694. setConf['volume'] = volumeDict
  695. # setConf['once_card'] = int(float(setConf['once_card']) * 100)
  696. # setConf['once_coin'] = int(float(setConf['once_coin']) * 100)
  697. setConf['max_watt'] = int(setConf['max_watt'])
  698. if not (int(setConf['max_watt']) >= 50 and int(setConf['max_watt']) <= 1000):
  699. raise ServiceException({'result': 2, 'description': u'最大功率必须大于等于100瓦,小于等于1000瓦'})
  700. setConf.update({'fun_code': 0x0B})
  701. setConf['fcharge'] = {
  702. 'watt': int(setConf['fcharge_watt']),
  703. 'time': int(setConf['fcharge_time']),
  704. 'check': int(setConf['fcharge_check']),
  705. }
  706. setConf.pop('fcharge_watt')
  707. setConf.pop('fcharge_time')
  708. setConf.pop('fcharge_check')
  709. chrmt = setConf.get('chrmt')
  710. if chrmt:
  711. package_time = setConf.get('package_time')
  712. package_elec = setConf.get('package_elec')
  713. package_power = setConf.get('package_power')
  714. price = {'ELEC': int(float(package_elec[0]['elec']) * 1000000)}
  715. # 组织功率收费价格参数
  716. TIME = []
  717. if chrmt == 'POWER': # 主板实际并没有power计费方式 实际为功率分档模式的换一种显示
  718. for _item in package_power:
  719. if float(_item['price']) == 0:
  720. raise ServiceException({'result': 2, 'description': u'计费参数设置(按功率收费)价格不能为0'})
  721. TIME.append(
  722. [int(_item['power']), round(1.0 / float(_item['price']) * 60 * 60, 1)]
  723. # 价格倍率 * 固定时间(60分钟) * 60秒
  724. )
  725. if not TIME:
  726. raise ServiceException({'result': 2, 'description': u'计费参数设置(按功率收费)缺少收费标准'})
  727. setConf['chrmt'] = 'TIME'
  728. elif chrmt == 'TIME': # 时间模式下 的时间计费规则
  729. for _item in package_time:
  730. TIME.append(
  731. [int(_item['power']), int(_item['time']) * 60]
  732. )
  733. if not TIME:
  734. raise ServiceException({'result': 2, 'description': u'计费参数设置(按时间收费)缺少收费标准'})
  735. price['TIME'] = TIME
  736. setConf['chrmt'] = 'TIME'
  737. elif chrmt == 'ELEC': # 同样也处理一次时间计费规则 用于下发给设备
  738. for _item in package_time:
  739. TIME.append(
  740. [int(_item['power']), int(_item['time']) * 60]
  741. )
  742. setConf['chrmt'] = 'ELEC'
  743. else:
  744. pass
  745. price['TIME'] = TIME
  746. setConf.update({'price': price})
  747. setConf.pop('package_time', None)
  748. setConf.pop('package_power', None)
  749. setConf.pop('package_elec', None)
  750. # 空载检测
  751. setConf['noload_check'] = {}
  752. setConf['noload_check']['watt'] = int(setConf.pop('emptyPower'))
  753. setConf['noload_check']['time'] = int(setConf.pop('emptyTime'))
  754. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  755. {'IMEI': self._device['devNo'], 'data': setConf})
  756. self.check_feedback_result(devInfo)
  757. # 服务器侧需要保存的参数处理
  758. unit_price = None
  759. if chrmt == 'TIME':
  760. unit_price = {'unit': '分钟', 'value': max(map(lambda _: _[1] / 60.0, setConf['price']['TIME']))}
  761. elif chrmt == 'POWER':
  762. unit_price = {'unit': '分钟', 'value': max(map(lambda _: _[1] / 60.0, setConf['price']['TIME']))}
  763. elif chrmt == 'ELEC':
  764. unit_price = {'unit': '度', 'value': round(setConf['price']['ELEC'] / 1000000.0, 2)}
  765. if unit_price:
  766. Device.get_collection().update_one(filter={'devNo': self.device.devNo},
  767. update={'$set': {
  768. 'otherConf.unit_price': unit_price,
  769. 'otherConf.chrmt': chrmt,
  770. }})
  771. Device.invalid_device_cache(self.device.devNo)
  772. def ack_event(self, orderNo, funCode):
  773. devInfo = MessageSender.send(self.device, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
  774. {'IMEI': self._device['devNo'],
  775. 'data': {'fun_code': funCode, 'order_id': orderNo}})
  776. self.check_feedback_result(devInfo)
  777. def clear_dev_feecount(self):
  778. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  779. {'IMEI': self._device['devNo'],
  780. 'data': {'fun_code': 0x09, 'total_coin': True, 'total_card': True}})
  781. self.check_feedback_result(devInfo)
  782. def response_card_charge_result(self, cardNo, result):
  783. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SERVER_ASYNC,
  784. {'IMEI': self._device['devNo'],
  785. 'data': {'fun_code': 37, 'card_no': cardNo, 'result': result}})
  786. def reboot_device(self):
  787. data = {'fun_code': 0x0B, 'reset_mcu': True}
  788. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  789. {'IMEI': self._device['devNo'], 'data': data})
  790. MessageSender.async_send(self.device, DeviceCmdCode.SET_DEVINFO,
  791. {'IMEI': self._device['devNo'], 'restart': True})
  792. def set_device_function(self, request, lastSetConf):
  793. if request.POST.has_key('clearSum'):
  794. self.clear_dev_feecount()
  795. elif request.POST.has_key('reboot'):
  796. self.reboot_device()
  797. def set_device_function_param(self, request, lastSetConf):
  798. newConf = copy.deepcopy(request.POST)
  799. newConf.pop('logicalCode', None)
  800. if 'minAfterStartCoins' in newConf:
  801. minAfterStartCoins = round(float(newConf.get('minAfterStartCoins', 0.0)), 1)
  802. Device.get_collection().update_one(filter={'devNo': self.device.devNo},
  803. update={'$set': {'otherConf.minAfterStartCoins': minAfterStartCoins}})
  804. Device.invalid_device_cache(self.device.devNo)
  805. if 'refundProtection' in newConf:
  806. refundProtection = round(float(newConf.get('refundProtection', 0.0)), 1)
  807. Device.get_collection().update_one(filter={'devNo': self.device.devNo},
  808. update={'$set': {'otherConf.refundProtection': refundProtection}})
  809. Device.invalid_device_cache(self.device.devNo)
  810. self.set_dev_setting(newConf)
  811. def get_card_pwd(self):
  812. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  813. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x11}})
  814. self.check_feedback_result(devInfo)
  815. result = devInfo['data']
  816. enObj = EncryptDate(cardKey)
  817. cardPwd = enObj.decrypt(result['card_pwd'])
  818. if not cardPwd:
  819. cardPwd = ''
  820. return {'card_pwd': cardPwd}
  821. def translante_card_no(self, hexCardNo):
  822. return int(hexCardNo, 16)
  823. def check_pwd(self, pwd):
  824. if len(pwd) != 6:
  825. raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'})
  826. for char in pwd:
  827. if not (char >= '0' and char <= '9'):
  828. raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'})
  829. return
  830. def set_card_pwd(self, pwd):
  831. self.check_pwd(pwd)
  832. enObj = EncryptDate(cardKey)
  833. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  834. {'IMEI': self._device['devNo'],
  835. 'data': {'fun_code': 0x0B, 'card_pwd': enObj.encrypt(pwd)}})
  836. self.check_feedback_result(devInfo)
  837. def set_card_mode(self, setConf):
  838. cardMode = int(setConf.get('card_mode'))
  839. valueDict = {'fun_code': 0x10}
  840. if cardMode == 0:
  841. valueDict.update({'mode': cardMode})
  842. elif cardMode == 1: # 格式化为离线卡
  843. self.check_pwd(setConf['new_pwd'])
  844. newPwd = setConf['new_pwd']
  845. if not str(setConf['balance']).isdigit():
  846. raise ServiceException({'result': 2, 'description': u'余额必须是数字'})
  847. balance = int(setConf['balance'])
  848. if not (balance >= 0 and balance <= 5000):
  849. raise ServiceException({'result': 2, 'description': u'余额必须在0和5000元之间'})
  850. balance = balance * 10 # 硬件模块记录的单位是角
  851. enObj = EncryptDate(cardKey)
  852. valueDict.update({'mode': 1, 'new_pwd': enObj.encrypt(str(newPwd)), 'balance': balance})
  853. elif cardMode == 2:
  854. self.check_pwd(setConf['old_pwd'])
  855. self.check_pwd(setConf['new_pwd'])
  856. newPwd = setConf['new_pwd']
  857. oldPwd = setConf['old_pwd']
  858. enObj = EncryptDate(cardKey)
  859. valueDict.update({'mode': 2, 'old_pwd': enObj.encrypt(str(oldPwd)), 'new_pwd': enObj.encrypt(str(newPwd))})
  860. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  861. {'IMEI': self._device['devNo'], 'data': valueDict})
  862. self.check_feedback_result(devInfo)
  863. def get_card_mode(self):
  864. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  865. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x11}})
  866. self.check_feedback_result(devInfo)
  867. cardMode = devInfo['data']['card_mode']
  868. return {'card_mode': cardMode}
  869. def check_alarm(self, alarm):
  870. if alarm.faultCode == FAULT_CODE.MCU_REBOOT:
  871. return u'此告警,建议您多观察,如果比较频繁不停上报单台设备的告警,可能会运行不稳定。需要您联系技术支持确认。'
  872. elif alarm.faultCode == FAULT_CODE.COUNTER_FAULT:
  873. portInfo = self.get_port_info(alarm.portNo)
  874. if portInfo['status'] == Const.DEV_WORK_STATUS_FAULT:
  875. return u'此端口目前已经为故障状态,继电器可能运行不稳定,建议您联系技术支持,以确认设备运行情况。'
  876. else:
  877. return u'端口状态检查正常,继电器或存偶尔无法获取数据。暂不影响使用。'
  878. elif alarm.faultCode == FAULT_CODE.RELAY_FAULT:
  879. return u'无法进行远程诊断,建议您到现场,直接插上插座,然后检查是否不用付款,就能够充电。如果是的,就属于继电器粘连。'
  880. elif alarm.faultCode == FAULT_CODE.DEV_OVERLOAD:
  881. return u'整机功率最大限定为7500瓦,接入的负载超过此负载,为了安全,将强行关闭所有充电端口。'
  882. elif alarm.faultCode == FAULT_CODE.COPY_CARD:
  883. return u'出现一模一样的卡,可能是用户复制了另外一张离线卡,然后使用,会给您造成经济上的损失,建议冻结。'
  884. return ''
  885. def get_part_info(self):
  886. # devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  887. # {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x05}})
  888. # self.check_feedback_result(devInfo)
  889. #
  890. # partInfo = devInfo['data']
  891. # result = {}
  892. # nameDesc = {'networkBoard': u'网络板', 'chargeBoard': u'充电板', 'cardBoard': u'刷卡板'}
  893. # for k, v in partInfo.items():
  894. # if k not in nameDesc:
  895. # continue
  896. #
  897. # result[nameDesc.get(k)] = {'SN': v}
  898. #
  899. # return result
  900. return {}
  901. def recharge_card(self, cardNo, money, orderNo=None):
  902. hex_cardNo = hex(int(cardNo))[2::].replace('L', '').upper()
  903. result = MessageSender.send(self.device, self.make_random_cmdcode(),
  904. {'IMEI': self.device['devNo'],
  905. 'data': {'fun_code': 37, 'result': 1, 'card_no': hex_cardNo,
  906. 'charge': int(money * 100),
  907. 'order_id': orderNo}})
  908. # 返回验证
  909. self.check_feedback_result(result)
  910. card = Card.objects.filter(cardNo=cardNo,dealerId=self.device.ownerId).first()
  911. if not card:
  912. return {
  913. 'result': ErrorCode.EXCEPTION,
  914. 'description': ''
  915. }, None
  916. balance = card.balance + money
  917. return {
  918. 'result': ErrorCode.SUCCESS,
  919. 'description': ''
  920. }, balance
  921. def recharge_card_async(self, cardNo, money, orderNo):
  922. cardNo = hex(int(cardNo))[2::].replace('L', '').upper()
  923. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SERVER_ASYNC,
  924. {'IMEI': self._device['devNo'],
  925. 'data': {'fun_code': 37, 'result': 1, 'card_no': cardNo, 'charge': int(money * 100),
  926. 'order_id': orderNo}})
  927. @property
  928. def isHaveStopEvent(self):
  929. return True
  930. # api相关
  931. def apiStartDeviceForYtb(self, record):
  932. port = int(record['port'])
  933. packageId = record['packageId']
  934. device = Device.objects(devNo=self.device['devNo']).first()
  935. package = device.washConfig[str(packageId)]
  936. coins = int(float(package['coins']) * 100)
  937. order_no = 'YTB' + str(uuid.uuid4())
  938. needTime, power = None, None
  939. unit = package.get('unit', u'分钟')
  940. if unit == u'秒':
  941. if int(package['time']) < 60:
  942. raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'})
  943. needTime = int(float(package['time']))
  944. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  945. elif unit == u'分钟':
  946. needTime = int(package['time']) * 60
  947. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  948. elif unit == u'小时':
  949. needTime = int(float(package['time']) * 60 * 60)
  950. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  951. elif unit == u'天':
  952. needTime = int(float(package['time']) * 60 * 60 * 24)
  953. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  954. elif unit == u'度':
  955. power = int(float(package['time']) * 1000000) # 微度,需要乘于16个零
  956. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'elec': power}
  957. else:
  958. needTime = int(package['time'])
  959. data = {'fun_code': 0x07, 'order_id': order_no, 'coins': coins, 'port': port, 'time': needTime}
  960. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  961. {'IMEI': self._device['devNo'], 'data': data}, timeout=MQTT_TIMEOUT.START_DEVICE)
  962. self.check_feedback_result(devInfo)
  963. value = {
  964. str(port): {
  965. 'status': Const.DEV_WORK_STATUS_WORKING,
  966. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  967. 'port': port,
  968. 'coins': coins,
  969. 'order_id': order_no,
  970. 'needTime': needTime,
  971. 'power': power,
  972. 'isAPI': True
  973. }
  974. }
  975. Device.update_dev_control_cache(self._device['devNo'], value)
  976. return devInfo
  977. def apiGetPortInfoFromYtb(self, record):
  978. return self.get_port_info(int(record['port']))
  979. def apiGetPortStatusFromYtb(self, record):
  980. return self.get_port_status_from_dev()
  981. def apiStopChargingPortForYtb(self, record):
  982. self.stop_charging_port(int(record['port']))
  983. return {}
  984. @property
  985. def show_pay_unit(self):
  986. """
  987. 前台显示付费的时候,目前有不同的客户希望 显示不同的单位 有的显示金币 有的显示元, 这个地方处理下
  988. :return:
  989. """
  990. if self.device['otherConf'].get('pay_unit'):
  991. return self.device['otherConf'].get('pay_unit')
  992. return u"币"
  993. def get_port_using_detail(self, port, ctrInfo, isLazy=False):
  994. return self.get_port_info(port)
  995. def stop(self, port = None):
  996. return self.stop_charging_port(port)
  997. def get_customize_score_unit(self):
  998. return u'元'
  999. def get_customize_package_unit(self):
  1000. chrmt = self.device['otherConf'].get('chrmt')
  1001. if not chrmt:
  1002. chrmt = self.get_dev_setting().get('chrmt')
  1003. # 按时间计费
  1004. if chrmt == 'TIME' or chrmt == 'POWER':
  1005. return u'分钟'
  1006. # 按电量计费
  1007. elif chrmt == 'ELEC':
  1008. return u'度'
  1009. return u'元'
  1010. def start_customize_point(self,pointNum,openId,port):
  1011. unit = self.get_customize_package_unit()
  1012. package = {'name':'customizePoint','price':pointNum,'coins':pointNum,'unit':unit,'time':999}
  1013. attachParas = {'chargeIndex':port,'onPoints':True}
  1014. return self.start_device(package, openId, attachParas)