weifule_mini_policy.py 38 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import copy
  4. import datetime
  5. import time
  6. from decimal import Decimal
  7. from apilib.utils_AES import EncryptDate
  8. from apilib.utils_datetime import to_datetime
  9. from apps.web.constant import DeviceCmdCode, Const, FAULT_CODE, ErrorCode, CONSUMETYPE
  10. from apps.web.core.adapter.weifuleCommon import PolicyBase
  11. from apps.web.core.exceptions import ServiceException
  12. from apps.web.core.networking import MessageSender
  13. from apps.web.device.models import Device, DeviceType
  14. from apps.web.user.models import ConsumeRecord, Card, ServiceProgress
  15. cardKey = 'FR4e1OFCnDdrYA7u'
  16. class PolicyWEIFULEBox(PolicyBase):
  17. def __init__(self, device):
  18. super(PolicyWEIFULEBox, self).__init__(device)
  19. def translate_funcode(self, fun_code):
  20. fun_codeDict = {
  21. '01': u'查询所有端口状态',
  22. '02': u'查询端口详细信息',
  23. '03': u'上报投币充电事件',
  24. '04': u'上报刷卡事件',
  25. '05': u'上报充电结束事件',
  26. '06': u'远程停止充电',
  27. '07': u'远程启动充电',
  28. '08': u'查询投币总额',
  29. '09': u'清除投币总数',
  30. '0A': u'查询订单信息',
  31. }
  32. return fun_codeDict.get(fun_code, '')
  33. def translate_event_cmdcode(self, cmdCode):
  34. cmdDict = {
  35. }
  36. return cmdDict.get(cmdCode, '')
  37. def test(self, coins):
  38. data = {'fun_code': 0x07, 'order_id': '1111', 'coins': coins, 'port': 1, 'time': 60}
  39. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  40. {'IMEI': self._device['devNo'], 'data': data})
  41. return devInfo
  42. def check_feedback_result(self, devInfo):
  43. if not devInfo.has_key('rst'):
  44. raise ServiceException({'result': 2, 'description': u'报文异常'})
  45. if devInfo['rst'] == -1:
  46. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  47. if devInfo['rst'] == 1:
  48. raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'})
  49. if devInfo['rst'] == 2:
  50. raise ServiceException({'result': 2, 'description': u'端口被禁用'})
  51. if devInfo['rst'] == 3:
  52. raise ServiceException({'result': 2, 'description': u'端口计量器故障'})
  53. if devInfo['rst'] == 4:
  54. raise ServiceException({'result': 2, 'description': u'设备订单已达上限'})
  55. if devInfo['rst'] == 5:
  56. raise ServiceException({'result': 2, 'description': u'设备正在自检'})
  57. def analyze_event_data(self, data):
  58. if data['fun_code'] == '34': # 如果是结束事件,需要把reason翻译出来
  59. descDict = {
  60. '1': u'开始充电,但是没有接充电器',
  61. '2': u'充电过程中,插座脱落',
  62. '3': u'用户按下关闭按钮关闭',
  63. '4': u'用户刷卡结束充电',
  64. '5': u'远程结束充电',
  65. '6': u'充电端口故障,为了安全主动关闭',
  66. '7': u'订购的时间使用完毕',
  67. '8': u'订购的电量使用完毕',
  68. '9': u'本端口功率过载,主动关闭',
  69. '10': u'整机功率过载,主动关闭',
  70. '11': u'其他异常导致的关闭'
  71. }
  72. order = data['order']
  73. order['reason'] = descDict.get(str(order['closeType']), u'')
  74. data['order'] = order
  75. return data
  76. def get_dev_consume_count(self):
  77. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  78. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x08}})
  79. self.check_feedback_result(devInfo)
  80. data = devInfo['data']
  81. return {'cardFee': round(data['total_card'] / 100.0,2), 'coinFee': data['total_coin'] / 100.0} # 单位为分
  82. def get_many_port_info(self, portList):
  83. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  84. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x12}})
  85. self.check_feedback_result(devInfo)
  86. resultDict = {}
  87. for port, data in devInfo['data']['details'].items():
  88. if port not in portList:
  89. continue
  90. result = {'index': port}
  91. result['status'] = self.__translate_status_from_str(data['status'])
  92. result['power'] = round(data.get('watt', 0), 2)
  93. result['ampere'] = round(data.get('ampr', 0) / 1000.0, 2)
  94. result['voltage'] = round(data.get('volt'), 2)
  95. for exec_order in data['orders']:
  96. orderNo = exec_order.get('id')
  97. order = ConsumeRecord.objects.filter(orderNo=orderNo).first()
  98. if exec_order.get('status') == 'running':
  99. result['usedTime'] = round(exec_order.get('time', 0) / 60.0, 1)
  100. result['usedElec'] = round(exec_order.get('elec') / 1000000.0, 2)
  101. result['startTime'] = datetime.datetime.fromtimestamp(exec_order['exec_time']).strftime('%m-%d %H:%M:%S')
  102. result['nickName'] = order and order.nickname
  103. if 'card_no' in exec_order:
  104. result['cardNo'] = str(int(exec_order.get('card_no', 0), 16))
  105. policy = exec_order.get('policy', {})
  106. policyType = policy.get('type')
  107. billingMethod = policy.get('billingMethod')
  108. result['openId'] = policy.get('open_id')
  109. result['consumeMoney'] = '{}元'.format(round(exec_order.get('money') * 0.01, 2))
  110. if billingMethod == 'prepaid':
  111. result['coins'] = round(policy.get('money') * 0.01, 2)
  112. if exec_order.get('order_type') == 'apps_start':
  113. result['consumeType'] = 'mobile'
  114. elif exec_order.get('order_type') == 'card_start':
  115. result['consumeType'] = 'card'
  116. result['cardBalance'] = '{}元'.format(round(exec_order.get('balance') * 0.01, 2))
  117. elif billingMethod == 'postpaid':
  118. result['consumeType'] = 'postpaid'
  119. if exec_order.get('order_type') == 'apps_start':
  120. needFiled = 'need{}'.format(policyType.capitalize())
  121. result[needFiled] = order and order.servicedInfo.get(needFiled)
  122. elif exec_order.get('order_type') == 'card_start':
  123. result['cardBalance'] = '{}元'.format(round(exec_order.get('balance') * 0.01, 2))
  124. else:
  125. pass
  126. else:
  127. pass
  128. resultDict[port] = result
  129. return resultDict
  130. def __translate_status_from_str(self, status):
  131. dictConf = {
  132. 'idle': Const.DEV_WORK_STATUS_IDLE,
  133. 'busy': Const.DEV_WORK_STATUS_WORKING,
  134. 'forbid': Const.DEV_WORK_STATUS_FORBIDDEN,
  135. 'fault': Const.DEV_WORK_STATUS_FAULT,
  136. 'running': Const.DEV_WORK_STATUS_WORKING,
  137. 'link': Const.DEV_WORK_STATUS_CONNECTED
  138. }
  139. return dictConf.get(status, Const.DEV_WORK_STATUS_IDLE)
  140. # 访问设备,获取设备端口信息
  141. def get_port_status_from_dev(self):
  142. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  143. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x01}})
  144. self.check_feedback_result(devInfo)
  145. data = devInfo['data']
  146. result = {}
  147. portNum = data.get('total', 10)
  148. ii = 0
  149. while ii < portNum:
  150. ii += 1
  151. result[str(ii)] = {'status': self.__translate_status_from_str(data['status'].get(str(ii)))}
  152. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  153. Device.update_dev_control_cache(self._device['devNo'],
  154. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  155. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  156. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  157. for strPort, info in result.items():
  158. if ctrInfo.has_key(strPort):
  159. ctrInfo[strPort].update({'status': info['status']})
  160. else:
  161. ctrInfo[strPort] = info
  162. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  163. return result
  164. def get_port_status(self, force=False):
  165. if force:
  166. return self.get_port_status_from_dev()
  167. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  168. if not ctrInfo.has_key('allPorts'):
  169. self.get_port_status_from_dev()
  170. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  171. allPorts = ctrInfo.get('allPorts', 10)
  172. statusDict = {}
  173. for ii in range(allPorts):
  174. tempDict = ctrInfo.get(str(ii + 1), {})
  175. if tempDict.has_key('status'):
  176. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  177. elif tempDict.has_key('isStart'):
  178. if tempDict['isStart']:
  179. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  180. else:
  181. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  182. else:
  183. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  184. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  185. Device.update_dev_control_cache(self._device['devNo'],
  186. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  187. return statusDict
  188. def lock_unlock_port(self, port, lock=True):
  189. portInfo = self.get_port_info(port)
  190. if portInfo and portInfo['status'] == Const.DEV_WORK_STATUS_WORKING and lock:
  191. raise ServiceException({'result': 2, 'description': u'端口正忙,请先关闭端口后,再禁止端口'})
  192. typeStr = 'deactive' if lock else 'active'
  193. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  194. {'IMEI': self._device['devNo'],
  195. 'data': {'port': int(port), 'type': typeStr, 'fun_code': 0x0D}})
  196. self.check_feedback_result(devInfo)
  197. if devInfo['rst'] == 0:
  198. if lock:
  199. Device.update_dev_control_cache(self._device['devNo'],
  200. {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  201. else:
  202. Device.update_dev_control_cache(self._device['devNo'],
  203. {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  204. else:
  205. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  206. def active_deactive_port(self, port, active):
  207. if active:
  208. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  209. return self.stop_charging_port(port)
  210. # 停止该端口下的所有任务
  211. def stop_charging_port(self, port):
  212. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  213. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x06, 'port': port}})
  214. self.check_feedback_result(devInfo)
  215. if devInfo['rst'] == 0:
  216. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  217. return True if devInfo['rst'] == 0 else False
  218. def get_order(self, order_no):
  219. order = ConsumeRecord.objects.filter(orderNo=order_no).first()
  220. port = order.used_port
  221. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  222. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x02, 'port': int(port)}})
  223. self.check_feedback_result(devInfo)
  224. data = devInfo.get('data', {})
  225. exec_orders = data.get('orders', [])
  226. if not exec_orders:
  227. return {}
  228. result = {}
  229. for exec_order in exec_orders:
  230. if not exec_order.get('order_type'): # 有可能没有订单,应该返回空
  231. return result
  232. if exec_order.get('status') != 'running':
  233. return {}
  234. result['power'] = round(data.get('watt', 0), 2)
  235. pay_unit = self.show_pay_unit
  236. # result['ampere'] = round(data.get('ampr', 0) / 1000.0, 2)
  237. # result['voltage'] = round(data.get('volt'), 2)
  238. result['status'] = exec_order.get('status', 0)
  239. orderNo = exec_order.get('id')
  240. order = ConsumeRecord.objects.filter(orderNo=orderNo).first()
  241. if order:
  242. result['coins'] = round(order.coin, 2)
  243. else:
  244. result['coins'] = round(exec_order.get('coins', 0) * 0.01, 2)
  245. result['usedTime'] = round(exec_order.get('time', 0) / 60.0, 1)
  246. result['usedElec'] = round(exec_order.get('elec') / 1000000.0, 2)
  247. if exec_order.get('status') == 'running':
  248. result['startTime'] = datetime.datetime.fromtimestamp(int(exec_order.get('execute_time', 0))).strftime(
  249. '%m-%d %H:%M:%S')
  250. if exec_order.get('chrmt') == 'TIME':
  251. result['needTime'] = round(exec_order.get('amount_time', 0) / 60.0, 1)
  252. result['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1)
  253. leftMoney = round((result['coins'] * exec_order.get('left_time', 0) / exec_order.get('amount_time', 0)),
  254. 2)
  255. consumeMoney = round((result['coins'] - leftMoney), 2)
  256. if exec_order.get('order_type') == 'apps_start':
  257. result['consumeType'] = 'mobile'
  258. result['consumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  259. result['leftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  260. try:
  261. orderNo = exec_order.get('id', 0)
  262. order = ConsumeRecord.objects.get(orderNo=orderNo)
  263. result['nickName'] = order.user.nickname
  264. package = order.package
  265. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get(
  266. 'price') == 0: # 后付费
  267. coins = round(exec_order.get('coins', 0) * 0.01, 2)
  268. consumeMoney = round(
  269. (coins * exec_order.get('time', 0) / exec_order.get(
  270. 'amount_time', 0)), 2)
  271. result['consumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  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['cardName'] = 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. elif exec_order.get('chrmt') == 'ELEC':
  295. result['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2)
  296. result['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4)
  297. leftMoney = round((result['coins'] * exec_order.get('left_elec', 0) / exec_order.get('amount_elec', 0)),
  298. 2)
  299. consumeMoney = round((result['coins'] - leftMoney), 2)
  300. if exec_order.get('order_type') == 'apps_start':
  301. result['consumeType'] = 'mobile'
  302. result['consumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  303. result['leftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  304. try:
  305. orderNo = exec_order.get('id', 0)
  306. order = ConsumeRecord.objects.get(orderNo=orderNo)
  307. result['nickName'] = order.user.nickname
  308. package = order.package
  309. if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get(
  310. 'price') == 0: # 后付费
  311. result['consumeType'] = 'postpaid'
  312. coins = round(exec_order.get('coins', 0) * 0.01, 2)
  313. consumeMoney = round(
  314. (coins * exec_order.get('elec', 0) / exec_order.get(
  315. 'amount_elec', 0)), 2)
  316. result['consumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  317. result['needTime'] = '充满自停'
  318. result.pop('needElec', None)
  319. result.pop('leftMoney', None)
  320. result.pop('leftTime', None)
  321. result.pop('leftElec', None)
  322. if package.get('billingMethod') == CONSUMETYPE.BILL_AS_SERVICE:
  323. result.pop('consumeMoney', None)
  324. result['elecFee'] = self.device.bill_as_service_feature.current_elec_fee(
  325. consumeMoney).mongo_amount
  326. result['serviceFee'] = self.device.bill_as_service_feature.current_service_fee(
  327. consumeMoney).mongo_amount
  328. except:
  329. pass
  330. if exec_order.get('order_type') == 'card_start':
  331. result['consumeType'] = 'card'
  332. result['cardNo'] = str(int(exec_order.get('card_no', 0), 16))
  333. result['cardConsumeMoney'] = '{}{}'.format(consumeMoney, pay_unit)
  334. result['cardLeftMoney'] = '{}{}'.format(leftMoney, pay_unit)
  335. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.01, 2), pay_unit)
  336. try:
  337. card = Card.objects.get(cardNo=str(int(exec_order.get('card_no', 0), 16)))
  338. result['cardName'] = card.cardName or card.nickName
  339. if card.cardType == 'ID': # id卡 订单余额显示有问题
  340. result['cardBalance'] = '{}{}'.format(round(exec_order.get('balance', 0) * 0.001, 2),
  341. pay_unit)
  342. except:
  343. pass
  344. else:
  345. pass
  346. return result
  347. def response_card_balance(self, cardNo, balance, result):
  348. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  349. {'IMEI': self._device['devNo'],
  350. 'data': {'fun_code': 35, 'card_no': cardNo, 'balance': int(100 * float(balance)),
  351. 'result': result}})
  352. self.check_feedback_result(devInfo)
  353. # 获取设备配置参数
  354. def get_dev_setting(self):
  355. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  356. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x0C}})
  357. self.check_feedback_result(devInfo)
  358. result = devInfo['data']
  359. result.update({
  360. 'fcharge_watt': result['fcharge']['watt'],
  361. 'fcharge_time': result['fcharge']['time'],
  362. 'fcharge_check': result['fcharge'].get('check', 10),
  363. })
  364. # # 按功率分档收费
  365. # TIME = result['price']['TIME'] # [{"max":"xxx","time":"xxx"}]
  366. # result['package_time'] = []
  367. # for _ in TIME:
  368. # item = {}
  369. # item['power'] = _[0]
  370. # item['time'] = int(_[1]) / 60 # 时间未秒转换为分
  371. # result['package_time'].append(item)
  372. #
  373. # # 按功率收费显示
  374. # package_power = []
  375. # for _item in TIME:
  376. # package_power.append({'power': _item[0], 'price': round(1.0 / (_item[1] / 60.0 / 60.0), 2)})
  377. # result['package_power'] = package_power
  378. #
  379. # # 按电量收费
  380. # result['package_elec'] = []
  381. # elec = Decimal(result['price']['ELEC']) / 1000000 # 默认为毫度
  382. # price = result['price'].get('price', 1) # 默认为一块钱
  383. # result['package_elec'].append({'price': price, 'elec': elec})
  384. noload_check = result.get('noload_check')
  385. if not noload_check:
  386. noload_check = {
  387. "time": 99,
  388. "watt": 99
  389. },
  390. result['emptyPower'] = noload_check['watt']
  391. result['emptyTime'] = noload_check['time']
  392. defaultVolume = 0
  393. volumeList = []
  394. for k, v in result['volume'].items():
  395. if k == 'default':
  396. defaultVolume = v
  397. else:
  398. tempList = k.split('-')
  399. volumeList.append({'start': tempList[0], 'end': tempList[1], 'volume': v})
  400. result.pop('volume')
  401. result['volume'] = defaultVolume
  402. result['volume_list'] = volumeList
  403. result['refundProtectionTime'] = self.device['otherConf'].get('refundProtectionTime', 5)
  404. return result
  405. # 获取设备配置参数
  406. def set_dev_setting(self, setConf):
  407. # 检查数据
  408. if not (int(setConf['fcharge_time']) >= 1 and int(setConf['fcharge_time']) <= 300):
  409. raise ServiceException({'result': 2, 'description': u'浮充时间必须大于等于1分钟,小于等于300分钟'})
  410. if not (int(setConf['fcharge_check']) >= 2 and int(setConf['fcharge_check']) <= 30):
  411. raise ServiceException({'result': 2, 'description': u'浮充检测时间必须大于等于2分钟,小于等于30分钟'})
  412. if not (int(setConf['fcharge_watt']) >= 20 and int(setConf['fcharge_watt']) <= 100):
  413. raise ServiceException({'result': 2, 'description': u'浮充功率必须大于等于20瓦,小于等于100瓦'})
  414. if not (int(setConf['volume']) >= 0 and int(setConf['volume']) <= 7):
  415. raise ServiceException({'result': 2, 'description': u'音量必须大于等于0,小于等于7'})
  416. volumeDict = {'default': int(setConf['volume'])}
  417. for vl in setConf['volume_list']:
  418. startTime = to_datetime('2020-01-01 %s:00' % vl['start'])
  419. endTime = to_datetime('2020-01-01 %s:00' % vl['end'])
  420. if endTime <= startTime:
  421. raise ServiceException({'result': 2, 'description': u'结束时间一定要大于起始时间。比如起始时间为07:00,结束时间为23:59'})
  422. volumeDict['%s-%s' % (vl['start'], vl['end'])] = int(vl['volume'])
  423. setConf.pop('volume')
  424. setConf.pop('volume_list')
  425. setConf['volume'] = volumeDict
  426. # setConf['once_card'] = int(float(setConf['once_card']) * 100)
  427. # setConf['once_coin'] = int(float(setConf['once_coin']) * 100)
  428. setConf['max_watt'] = int(setConf['max_watt'])
  429. if not (int(setConf['max_watt']) >= 50 and int(setConf['max_watt']) <= 1000):
  430. raise ServiceException({'result': 2, 'description': u'最大功率必须大于等于100瓦,小于等于1000瓦'})
  431. setConf.update({'fun_code': 0x0B})
  432. setConf['fcharge'] = {
  433. 'watt': int(setConf['fcharge_watt']),
  434. 'time': int(setConf['fcharge_time']),
  435. 'check': int(setConf['fcharge_check']),
  436. }
  437. setConf.pop('fcharge_watt')
  438. setConf.pop('fcharge_time')
  439. setConf.pop('fcharge_check')
  440. # 空载检测
  441. setConf['noload_check'] = {}
  442. setConf['noload_check']['watt'] = int(setConf.pop('emptyPower'))
  443. setConf['noload_check']['time'] = int(setConf.pop('emptyTime'))
  444. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  445. {'IMEI': self._device['devNo'], 'data': setConf})
  446. self.check_feedback_result(devInfo)
  447. def ack_event(self, orderNo, funCode):
  448. devInfo = MessageSender.send(self.device, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
  449. {'IMEI': self._device['devNo'],
  450. 'data': {'fun_code': funCode, 'order_id': orderNo}})
  451. self.check_feedback_result(devInfo)
  452. def clear_dev_feecount(self):
  453. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  454. {'IMEI': self._device['devNo'],
  455. 'data': {'fun_code': 0x09, 'total_coin': True, 'total_card': True}})
  456. self.check_feedback_result(devInfo)
  457. def response_card_charge_result(self, cardNo, result):
  458. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SERVER_ASYNC,
  459. {'IMEI': self._device['devNo'],
  460. 'data': {'fun_code': 37, 'card_no': cardNo, 'result': result}})
  461. def reboot_device(self):
  462. data = {'fun_code':0x0B,'reset_mcu':True}
  463. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  464. {'IMEI': self._device['devNo'], 'data': data})
  465. MessageSender.async_send(self.device, DeviceCmdCode.SET_DEVINFO,
  466. {'IMEI': self._device['devNo'], 'restart': True})
  467. def set_device_function(self, request, lastSetConf):
  468. if request.POST.has_key('clearSum'):
  469. self.clear_dev_feecount()
  470. elif request.POST.has_key('reboot'):
  471. self.reboot_device()
  472. def set_device_function_param(self, request, lastSetConf):
  473. newConf = copy.deepcopy(request.POST)
  474. newConf.pop('logicalCode', None)
  475. if 'refundProtectionTime' in newConf:
  476. refundProtectionTime = round(float(newConf.get('refundProtectionTime', 0.0)), 1)
  477. Device.get_collection().update_one(filter={'devNo': self.device.devNo}, update={'$set': {'otherConf.refundProtectionTime': refundProtectionTime}})
  478. Device.invalid_device_cache(self.device.devNo)
  479. self.set_dev_setting(newConf)
  480. def get_card_pwd(self):
  481. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  482. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x11}})
  483. self.check_feedback_result(devInfo)
  484. result = devInfo['data']
  485. enObj = EncryptDate(cardKey)
  486. cardPwd = enObj.decrypt(result['card_pwd'])
  487. if not cardPwd:
  488. cardPwd = ''
  489. return {'card_pwd': cardPwd}
  490. def translante_card_no(self, hexCardNo):
  491. return int(hexCardNo, 16)
  492. def check_pwd(self, pwd):
  493. if len(pwd) != 6:
  494. raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'})
  495. for char in pwd:
  496. if not (char >= '0' and char <= '9'):
  497. raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'})
  498. return
  499. def set_card_pwd(self, pwd):
  500. self.check_pwd(pwd)
  501. enObj = EncryptDate(cardKey)
  502. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  503. {'IMEI': self._device['devNo'],
  504. 'data': {'fun_code': 0x0B, 'card_pwd': enObj.encrypt(pwd)}})
  505. self.check_feedback_result(devInfo)
  506. def set_card_mode(self, setConf):
  507. cardMode = int(setConf.get('card_mode'))
  508. valueDict = {'fun_code': 0x10}
  509. if cardMode == 0:
  510. valueDict.update({'mode': cardMode})
  511. elif cardMode == 1: # 格式化为离线卡
  512. self.check_pwd(setConf['new_pwd'])
  513. newPwd = setConf['new_pwd']
  514. if not str(setConf['balance']).isdigit():
  515. raise ServiceException({'result': 2, 'description': u'余额必须是数字'})
  516. balance = int(setConf['balance'])
  517. if not (balance >= 0 and balance <= 5000):
  518. raise ServiceException({'result': 2, 'description': u'余额必须在0和5000元之间'})
  519. balance = balance * 10 # 硬件模块记录的单位是角
  520. enObj = EncryptDate(cardKey)
  521. valueDict.update({'mode': 1, 'new_pwd': enObj.encrypt(str(newPwd)), 'balance': balance})
  522. elif cardMode == 2:
  523. self.check_pwd(setConf['old_pwd'])
  524. self.check_pwd(setConf['new_pwd'])
  525. newPwd = setConf['new_pwd']
  526. oldPwd = setConf['old_pwd']
  527. enObj = EncryptDate(cardKey)
  528. valueDict.update({'mode': 2, 'old_pwd': enObj.encrypt(str(oldPwd)), 'new_pwd': enObj.encrypt(str(newPwd))})
  529. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  530. {'IMEI': self._device['devNo'], 'data': valueDict})
  531. self.check_feedback_result(devInfo)
  532. def get_card_mode(self):
  533. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  534. {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x11}})
  535. self.check_feedback_result(devInfo)
  536. cardMode = devInfo['data']['card_mode']
  537. return {'card_mode': cardMode}
  538. def check_alarm(self, alarm):
  539. if alarm.faultCode == FAULT_CODE.MCU_REBOOT:
  540. return u'此告警,建议您多观察,如果比较频繁不停上报单台设备的告警,可能会运行不稳定。需要您联系技术支持确认。'
  541. elif alarm.faultCode == FAULT_CODE.COUNTER_FAULT:
  542. portInfo = self.get_port_info(alarm.portNo)
  543. if portInfo['status'] == Const.DEV_WORK_STATUS_FAULT:
  544. return u'此端口目前已经为故障状态,继电器可能运行不稳定,建议您联系技术支持,以确认设备运行情况。'
  545. else:
  546. return u'端口状态检查正常,继电器或存偶尔无法获取数据。暂不影响使用。'
  547. elif alarm.faultCode == FAULT_CODE.RELAY_FAULT:
  548. return u'无法进行远程诊断,建议您到现场,直接插上插座,然后检查是否不用付款,就能够充电。如果是的,就属于继电器粘连。'
  549. elif alarm.faultCode == FAULT_CODE.DEV_OVERLOAD:
  550. return u'整机功率最大限定为7500瓦,接入的负载超过此负载,为了安全,将强行关闭所有充电端口。'
  551. elif alarm.faultCode == FAULT_CODE.COPY_CARD:
  552. return u'出现一模一样的卡,可能是用户复制了另外一张离线卡,然后使用,会给您造成经济上的损失,建议冻结。'
  553. return ''
  554. # def get_part_info(self):
  555. # devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  556. # {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x05}})
  557. # self.check_feedback_result(devInfo)
  558. #
  559. # partInfo = devInfo['data']
  560. # result = {}
  561. # nameDesc = {'networkBoard': u'网络板', 'chargeBoard': u'充电板', 'cardBoard': u'刷卡板'}
  562. # for k, v in partInfo.items():
  563. # if k not in nameDesc:
  564. # continue
  565. #
  566. # result[nameDesc.get(k)] = {'SN': v}
  567. #
  568. # return result
  569. def recharge_card(self, cardNo, money, orderNo=None):
  570. hex_cardNo = hex(int(cardNo))[2::].replace('L', '').upper()
  571. result = MessageSender.send(self.device, self.make_random_cmdcode(),
  572. {'IMEI': self.device['devNo'],
  573. 'data': {'fun_code': 37, 'result': 1, 'card_no': hex_cardNo,
  574. 'charge': int(money * 100),
  575. 'order_id': orderNo}})
  576. # 返回验证
  577. self.check_feedback_result(result)
  578. card = Card.objects.filter(cardNo=cardNo,dealerId=self.device.ownerId).first()
  579. if not card:
  580. return {
  581. 'result': ErrorCode.EXCEPTION,
  582. 'description': ''
  583. }, None
  584. balance = card.balance + money
  585. return {
  586. 'result': ErrorCode.SUCCESS,
  587. 'description': ''
  588. }, balance
  589. def recharge_card_async(self, cardNo, money, orderNo):
  590. cardNo = hex(int(cardNo))[2::].replace('L', '').upper()
  591. MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SERVER_ASYNC,
  592. {'IMEI': self._device['devNo'],
  593. 'data': {'fun_code': 37, 'result': 1, 'card_no': cardNo, 'charge': int(money * 100),
  594. 'order_id': orderNo}})
  595. @property
  596. def isHaveStopEvent(self):
  597. return True
  598. def stop(self, port = None):
  599. return self.stop_charging_port(port)
  600. def get_current_use(self, **kw):
  601. base_data = kw.get('base_data')
  602. spDict = kw.get('spDict')
  603. sp = ServiceProgress.objects.filter(id=spDict['_id']).first()
  604. data = {'fun_code': 2, 'port': spDict.get('port')}
  605. devInfo = self.send_mqtt(data)
  606. portInfo = devInfo.get('data', {})
  607. exec_orders = portInfo.get('orders', [])
  608. if not exec_orders:
  609. sp.update(isFinished=True, status='finished', consumes=[])
  610. return []
  611. for exec_order in exec_orders: # 循环过来sp消费单同步
  612. if exec_order['id'] not in sp.consumes:
  613. sp.consumes.append(exec_order['id'])
  614. sp.finished_time = int(time.time()) + 12 * 60 * 60
  615. sp.isFinished = False
  616. if exec_order['status'] == 'running':
  617. sp.start_time = exec_order['exec_time']
  618. pay_unit = self.show_pay_unit
  619. result_list = [] # 数据整理返回
  620. for exec_order in exec_orders:
  621. item = {}
  622. item.update(base_data)
  623. item['orderNo'] = exec_order['id']
  624. item['port'] = exec_order['port']
  625. order = ConsumeRecord.objects.filter(orderNo=exec_order['id']).first()
  626. item['voltage'] = format(portInfo.get('volt', 0), '.2f')
  627. item['power'] = format(portInfo.get('watt', 0), '.2f')
  628. item['ampere'] = format((portInfo.get('ampr', 0) * 0.001), '.2f')
  629. item['usedTime'] = format(exec_order.get('time', 0) / 60.0, '.2f')
  630. # item['elec'] = format(exec_order.get('elec', 0) * 0.000001, '.4f')
  631. if exec_order['order_type'] == 'apps_start':
  632. try:
  633. item['consumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), pay_unit)
  634. policy = exec_order['policy']
  635. if policy.get('billingMethod', 'postpaid') == CONSUMETYPE.POSTPAID:
  636. item['order'] = {
  637. 'orderNo': exec_order['id'], # 停止按钮传订单停单用
  638. # 'coin': '{}{}'.format(round(order.coin, 2), pay_unit),
  639. 'port': exec_order['port'],
  640. 'consumeType': 'postpaid',
  641. }
  642. else:
  643. item['order'] = {
  644. 'orderNo': exec_order['id'], # 停止按钮传订单停单用
  645. 'coin': '{}{}'.format(round(order.coin, 2), pay_unit),
  646. 'port': exec_order['port'],
  647. 'consumeType': 'mobile',
  648. }
  649. item['leftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2),
  650. pay_unit)
  651. except:
  652. pass
  653. item.update(DeviceType.get_services_button(self.device['devType']['id']))
  654. result_list.append(item)
  655. return result_list
  656. def check_dev_status(self, attachParas=None):
  657. port = int(attachParas['chargeIndex'])
  658. openId = attachParas['openId']
  659. port_stat = self.get_port_info(port)
  660. status = port_stat.get('status')
  661. # if status not in ['busy', 'link']:
  662. # raise ServiceException({'result': 2, 'description': u'请先连接充电插座,再启动充电'})
  663. last_openId = port_stat.get('openId')
  664. if status == 'busy':
  665. if openId and self.device.devType.get('payableWhileBusy'):
  666. if openId != last_openId:
  667. raise ServiceException({'result': 2, 'description': u'当前充电的设备不是您的设备哦!无法进行续充'})
  668. else:
  669. if 'cardNo' in port_stat:
  670. raise ServiceException({'result': 2, 'description': u'刷卡启动的订单,无法扫码续充哦'})
  671. else:
  672. raise ServiceException({'result': 2, 'description': u'当前端口处于充电状态, 请确认是否为您选择的充电端口哦!'})