weifule2.py 67 KB

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