weifule_policy_classic.py 40 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. from decimal import Decimal
  5. from apilib.monetary import RMB
  6. from apilib.utils_AES import EncryptDate
  7. from apps.web.constant import DeviceCmdCode, Const, ErrorCode
  8. from apps.web.core.adapter.policy_common import PolicyPackageInit
  9. from apps.web.core.adapter.weifuleCommon import PolicyBase
  10. from apps.web.core.exceptions import ServiceException
  11. from apps.web.core.networking import MessageSender
  12. from apps.web.device.models import Device, DeviceType
  13. from apps.web.user.models import Card, ServiceProgress, ConsumeRecord, UserVirtualCard
  14. cardKey = 'FR4e1OFCnDdrYA7u'
  15. class MyPackageInit(PolicyPackageInit):
  16. def get_reg_model(self, dealer, devTypeId, isTemp=False, **kw):
  17. policyTemp = self.INIT_POLICY
  18. displaySwitchs = self._get_displaySwitch(isTemp)
  19. ruleList = [
  20. {
  21. 'autoRefund': False,
  22. 'autoStop': True,
  23. 'billingMethod': 'prepaid',
  24. 'coins': 0.0,
  25. "name": "60分钟",
  26. 'price': 1.0,
  27. 'sn': 2,
  28. 'switch': True,
  29. 'time': 60.0,
  30. "unit": "分钟",
  31. },
  32. ]
  33. if devTypeId in dealer.defaultWashConfig:
  34. payload = dealer.defaultWashConfig[devTypeId]
  35. if not payload.get('policyTemp'):
  36. payload['policyTemp'] = policyTemp
  37. if not payload.get('displaySwitchs'):
  38. payload['displaySwitchs'] = displaySwitchs
  39. if not payload.get('ruleList'):
  40. payload['ruleList'] = ruleList
  41. else:
  42. payload = {'ruleList': ruleList, 'displaySwitchs': displaySwitchs, 'policyTemp': policyTemp}
  43. return payload
  44. def _formart_ruleList(self, isTemp=False):
  45. if not isTemp and not filter(lambda _: _.get('switch') == True, self.ruleList):
  46. raise ServiceException(
  47. {'result': 0, 'description': '没有可供用户选择的套餐, 请新增或启用 至少一个用户套餐',
  48. 'payload': {}})
  49. ids = [str(rule['id']) for rule in self.ruleList if 'id' in rule]
  50. for i, rule in enumerate(self.ruleList):
  51. ruleId = str(rule.get('id', ''))
  52. if not ruleId:
  53. ruleId = self._generate_id(ids)
  54. ids.append(ruleId)
  55. # 充满自停套餐
  56. if ruleId == 'autoPackage':
  57. rule['time'] = float(rule.get('time') or 0)
  58. # 自定义输入套餐
  59. if ruleId == 'customPackage':
  60. rule['time'] = float(rule.get('time') or 0)
  61. self.washConfig[ruleId] = {
  62. 'price': round(RMB(rule.get('price') or 0), 2),
  63. 'coins': round(RMB(rule.get('price') or 0), 2)
  64. }
  65. if 'switch' in rule:
  66. self.washConfig[ruleId].update({'switch': rule.get('switch', True)})
  67. if 'time' in rule:
  68. self.washConfig[ruleId].update({'time': round(float(rule.get('time') or 0), 2)})
  69. if 'name' in rule:
  70. self.washConfig[ruleId].update({'name': rule.get('name') or '套餐{}'.format(i + 1)})
  71. if 'unit' in rule:
  72. self.washConfig[ruleId].update({'unit': rule.get('unit')})
  73. if 'sn' in rule:
  74. self.washConfig[ruleId].update({'sn': rule['sn']})
  75. if 'autoStop' in rule:
  76. self.washConfig[ruleId]['autoStop'] = rule['autoStop']
  77. if 'autoRefund' in rule:
  78. self.washConfig[ruleId]['autoRefund'] = rule.get('autoRefund', False)
  79. # 此处有可能传入空字符串 加一个or判断为0
  80. if 'minAfterStartCoins' in rule:
  81. self.washConfig[ruleId]['minAfterStartCoins'] = round(RMB(rule['minAfterStartCoins'] or 0), 2)
  82. # 此处有可能传入空字符串 加一个or判断为0
  83. self.washConfig[ruleId]['billingMethod'] = 'prepaid'
  84. # 检验部分
  85. if RMB(rule.get('price') or 0) > self.dealer.maxPackagePrice:
  86. raise ServiceException({'result': 0, 'description': '套餐( {} )金额超限'.format(rule['name']), 'payload': {}})
  87. def _get_displaySwitch(self, isTemp=False):
  88. displaySwitchs = {
  89. "displayCoinsSwitch": False,
  90. "displayPriceSwitch": True,
  91. "displayTimeSwitch": True,
  92. "setBasePriceAble": False,
  93. "setPulseAble": False
  94. }
  95. return displaySwitchs
  96. class POLICYBox(PolicyBase, MyPackageInit):
  97. def __init__(self, device):
  98. super(POLICYBox, self).__init__(device)
  99. def translate_funcode(self, fun_code):
  100. fun_codeDict = {
  101. '01': u'查询所有端口状态',
  102. '02': u'查询端口详细信息',
  103. '03': u'上报投币充电事件',
  104. '04': u'上报刷卡事件',
  105. '05': u'上报充电结束事件',
  106. '06': u'远程停止充电',
  107. '07': u'远程启动充电',
  108. '08': u'查询投币总额',
  109. '09': u'清除投币总数',
  110. '0A': u'查询订单信息',
  111. }
  112. return fun_codeDict.get(fun_code, '')
  113. def translate_event_cmdcode(self, cmdCode):
  114. cmdDict = {
  115. }
  116. return cmdDict.get(cmdCode, '')
  117. def check_feedback_result(self, result):
  118. if 'rst' not in result:
  119. raise ServiceException({'result': 2, 'description': u'报文异常'})
  120. if result['rst'] == -1:
  121. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  122. if result['rst'] == 1:
  123. raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'})
  124. if result['rst'] == 2:
  125. raise ServiceException({'result': 2, 'description': u'订单已满'})
  126. if result['rst'] == 3:
  127. raise ServiceException({'result': 2, 'description': u'端口已被禁用'})
  128. if result['rst'] == 4:
  129. raise ServiceException({'result': 2, 'description': u'检测插头未连接,请先插上插头后再使用'})
  130. if result['rst'] == 5:
  131. raise ServiceException({'result': 2, 'description': u'计费类型无效'})
  132. if result['rst'] == 7:
  133. raise ServiceException({'result': 2, 'description': u'端口计量故障'})
  134. # def get_port_info(self, port):
  135. # data = {'fun_code': 2, 'port': int(port)}
  136. # devInfo = self.send_mqtt(data)
  137. # portInfo = devInfo.get('data', {})
  138. # result = {'status': portInfo['status']}
  139. #
  140. # exec_orders = portInfo.get('exec_orders', [])
  141. # _wait = []
  142. # for exec_order in exec_orders:
  143. # if exec_order['status'] == 'running':
  144. # policy = exec_order.get('policy', {})
  145. # result['openId'] = policy['open_id']
  146. # result['billingMethod'] = policy['billingMethod']
  147. # result['policyType'] = policy['type']
  148. # result['voltage'] = round(portInfo.get('volt', 0), 2)
  149. # result['power'] = round(portInfo.get('watt', 0), 2)
  150. # result['ampere'] = round((portInfo.get('ampr', 0) * 0.001), 2)
  151. # result['usedTime'] = round(exec_order.get('time', 0) / 60.0, 1)
  152. # result['usedElec'] = round(exec_order.get('elec', 0) * 0.000001, 4)
  153. # result['startTime'] = datetime.datetime.fromtimestamp(int(exec_order['exec_time'])).strftime('%m-%d %H:%M:%S')
  154. # if 'card_no' in result:
  155. # result['cardNo'] = result['card_no']
  156. #
  157. # if exec_order['status'] == 'waiting':
  158. # _one = {}
  159. #
  160. # _wait.append(_one)
  161. #
  162. # if _wait:
  163. # result['waittingOrder'] = _wait
  164. #
  165. # return result
  166. def check_params_range(self, params, minData=None, maxData=None, desc=''):
  167. # type:(str,float,float,str) -> str
  168. """
  169. 检查参数,返回字符串参数
  170. """
  171. if params is None:
  172. raise ServiceException({'result': 2, 'description': u'{} 参数错误(值为空).'.format(desc)})
  173. if not isinstance(params, Decimal):
  174. params = Decimal(params)
  175. if not minData and maxData:
  176. if not isinstance(maxData, Decimal):
  177. maxData = Decimal(maxData)
  178. if params <= maxData:
  179. return '%g' % params
  180. else:
  181. raise ServiceException(
  182. {'result': 2, 'description': u'%s超出可选范围(值为: %s),可选最大值为%g' % (desc, params, maxData)})
  183. if not maxData and minData:
  184. if not isinstance(minData, Decimal):
  185. minData = Decimal(minData)
  186. if minData <= params:
  187. return '%g' % params
  188. else:
  189. raise ServiceException(
  190. {'result': 2, 'description': u'%s超出可选范围(值为: %s),可选最小值为%g' % (desc, params, minData)})
  191. if not minData and not maxData:
  192. return '%g' % params
  193. else:
  194. if not isinstance(minData, Decimal):
  195. minData = Decimal(minData)
  196. if not isinstance(maxData, Decimal):
  197. maxData = Decimal(maxData)
  198. if minData <= params <= maxData:
  199. return '%g' % params
  200. else:
  201. raise ServiceException(
  202. {'result': 2, 'description': u'%s参数超出可选范围(值为: %s),可取范围为%g-%g' % (desc, params, minData, maxData)})
  203. def test(self, coins):
  204. data = {'fun_code': 0x07, 'order_id': '1111', 'coins': coins, 'port': 1, 'time': 60}
  205. devInfo = self.send_mqtt(data)
  206. return devInfo
  207. def get_port_status_from_dev(self):
  208. data = {'fun_code': 0x01, 'all': True}
  209. devInfo = self.send_mqtt(data)
  210. portData = devInfo['data']['port_stat']
  211. result = {}
  212. for k, v in portData.items():
  213. if v == 'idle':
  214. result[k] = {'status': Const.DEV_WORK_STATUS_IDLE}
  215. elif v == 'link':
  216. result[k] = {'status': Const.DEV_WORK_STATUS_CONNECTED}
  217. elif v == 'busy':
  218. result[k] = {'status': Const.DEV_WORK_STATUS_WORKING}
  219. elif v == 'fault':
  220. result[k] = {'status': Const.DEV_WORK_STATUS_FAULT}
  221. elif v == 'forbid':
  222. result[k] = {'status': Const.DEV_WORK_STATUS_FORBIDDEN}
  223. else:
  224. result[k] = {'status': Const.DEV_WORK_STATUS_FAULT}
  225. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  226. Device.update_dev_control_cache(self._device['devNo'],
  227. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  228. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  229. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  230. for strPort, info in result.items():
  231. if strPort in ctrInfo:
  232. ctrInfo[strPort].update({'status': info['status']})
  233. else:
  234. ctrInfo[strPort] = info
  235. Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
  236. return result
  237. def get_port_status(self, force=False):
  238. if force:
  239. return self.get_port_status_from_dev()
  240. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  241. if 'allPorts' not in ctrInfo:
  242. self.get_port_status_from_dev()
  243. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  244. allPorts = ctrInfo.get('allPorts', 2)
  245. statusDict = {}
  246. for ii in range(allPorts):
  247. tempDict = ctrInfo.get(str(ii + 1), {})
  248. if 'status' in tempDict:
  249. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  250. elif 'isStart' in tempDict:
  251. if tempDict['isStart']:
  252. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  253. else:
  254. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  255. else:
  256. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  257. allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
  258. Device.update_dev_control_cache(self._device['devNo'],
  259. {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
  260. return statusDict
  261. def active_deactive_port(self, port, active):
  262. if active:
  263. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  264. return self.stop_charging_port(port)
  265. # 停止该端口下的所有任务
  266. def stop_charging_port(self, port):
  267. data = {'fun_code': 0x06, 'port': port}
  268. devInfo = self.send_mqtt(data)
  269. if devInfo['rst'] == 0:
  270. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  271. return True if devInfo['rst'] == 0 else False
  272. def analyze_event_data(self, data):
  273. if data['fun_code'] == '32': # 成功启动设备需要回复该事件
  274. return data['order']
  275. if data['fun_code'] == '34': # 如果是结束事件,需要把reason翻译出来
  276. descDict = {
  277. 'outofmoney': u'购买的充电时间或电量用完了',
  278. 'userstop': u'用户远程结束充电',
  279. 'adminstop': u'管理员远程结束充电',
  280. 'dealerstop': u'经销商远程结束充电',
  281. 'unplug': u'未检测到充电器, 结束充电',
  282. 'wattoverload': u'功率过载, 结束充电',
  283. 'voltoverload': u'电压过载, 结束充电',
  284. 'amproverload': u'电流过载, 结束充电',
  285. 'machoverload': u'整机功率过载, 结束充电',
  286. 'tempexcursion': u'温度过载, 结束充电',
  287. 'stopforfull': u'充满自停, 结束充电'
  288. }
  289. order = data['order']
  290. order['reasonDesc'] = descDict.get(str(order['cause_desc']), u'')
  291. data['order'] = order
  292. return data
  293. def ack_event(self, order_id, fun_code):
  294. data = {'order_id': order_id, 'fun_code': fun_code}
  295. self.send_mqtt(data)
  296. def get_card_pwd(self):
  297. devInfo = self.send_mqtt({'fun_code': 17})
  298. data = devInfo.get('data', {})
  299. card_cur_key = data.get('card_cur_key')
  300. enObj = EncryptDate(cardKey)
  301. card_cur_key = enObj.decrypt(card_cur_key)
  302. return {'card_pwd': card_cur_key}
  303. def set_device_function(self, request, lastSetConf):
  304. if 'clearSum' in request.POST:
  305. self.clear_dev_feecount()
  306. elif 'reboot' in request.POST:
  307. self.reboot_device()
  308. def set_device_function_param(self, request, lastSetConf):
  309. """
  310. 设置参数 对于计费模式做一下转换 顺便服务器保留一份
  311. :param request:
  312. :param lastSetConf:
  313. :return:
  314. """
  315. # 服务器侧的参数 先处理掉
  316. if request.POST.get('id_card_oncefee') is not None:
  317. id_card_oncefee = request.POST['id_card_oncefee']
  318. if not id_card_oncefee:
  319. raise ServiceException({'result': 2, 'description': u'在线卡单次刷卡金额不能为0'})
  320. Device.get_collection().update_one(filter={'devNo': self.device.devNo},
  321. update={'$set': {
  322. 'otherConf.id_card_oncefee': round(float(id_card_oncefee), 2),
  323. }})
  324. Device.invalid_device_cache(self.device.devNo)
  325. if request.POST.get('refundProtection') is not None:
  326. refundProtection = request.POST['refundProtection']
  327. Device.get_collection().update_one(filter={'devNo': self.device.devNo},
  328. update={'$set': {
  329. 'otherConf.refundProtection': round(float(refundProtection), 2),
  330. }})
  331. Device.invalid_device_cache(self.device.devNo)
  332. if request.POST.get('minAfterStartCoins') is not None:
  333. minAfterStartCoins = request.POST['minAfterStartCoins']
  334. Device.get_collection().update_one(filter={'devNo': self.device.devNo},
  335. update={'$set': {
  336. 'otherConf.minAfterStartCoins': round(float(minAfterStartCoins), 2),
  337. }})
  338. Device.invalid_device_cache(self.device.devNo)
  339. # 参数发向设备 11, 16指令
  340. setconfig1 = {'fun_code': 11}
  341. setconfig2 = {'fun_code': 16}
  342. # 音量适配
  343. if request.POST.get('volume_list'):
  344. volume_list = request.POST.get('volume_list')
  345. volumes = {}
  346. self.check_params_range(params=request.POST.get('volume'), minData=0.0, maxData=7.0, desc='语音音量参数')
  347. volumes.update({'default': int(request.POST.get('volume'))})
  348. for obj in volume_list:
  349. self.check_params_range(params=obj['volume'], minData=0.0, maxData=7.0, desc='音量参数')
  350. volumes.update({'{}-{}'.format(obj['start'], obj['end']): int(obj['volume'])})
  351. setconfig1.update({'volumes': volumes})
  352. if request.POST.get('float_time') or request.POST.get('float_watt') or request.POST.get('check_time'):
  353. float_charge = {}
  354. if request.POST.get('float_time'):
  355. float_charge['float_time'] = int(request.POST.get('float_time'))
  356. if request.POST.get('float_watt'):
  357. float_charge['float_watt'] = int(request.POST.get('float_watt'))
  358. if request.POST.get('check_time'):
  359. float_charge['check_time'] = int(request.POST.get('check_time'))
  360. setconfig1.update({'float_charge': float_charge})
  361. if request.POST.get('port_max_watt'):
  362. setconfig1.update({'port_max_watt': int(request.POST.get('port_max_watt'))})
  363. if request.POST.get('port_max_ampr'):
  364. setconfig1.update({'port_max_ampr': int(request.POST.get('port_max_ampr'))})
  365. if request.POST.get('mach_max_watt'):
  366. setconfig1.update({'mach_max_watt': int(request.POST.get('mach_max_watt'))})
  367. if request.POST.get('mach_max_temp'):
  368. setconfig1.update({'mach_max_temp': int(request.POST.get('mach_max_temp'))})
  369. if request.POST.get('mach_max_volt'):
  370. setconfig1.update({'mach_max_volt': int(request.POST.get('mach_max_volt'))})
  371. if request.POST.get('noload_check_watt') or request.POST.get('noload_check_time'):
  372. noload_check = {}
  373. if request.POST.get('noload_check_watt'):
  374. noload_check['watt'] = int(request.POST.get('noload_check_watt'))
  375. if request.POST.get('noload_check_time'):
  376. noload_check['time'] = int(request.POST.get('noload_check_time'))
  377. setconfig1.update({'noload_check': noload_check})
  378. # 离线卡配置
  379. if request.POST.get('policy'):
  380. policy = request.POST['policy']
  381. _type = policy['type']
  382. money = int(float(policy['money']) * 100) # 离线卡刷一次金额 单位: 分
  383. auto_stop = policy['auto_stop']
  384. rule = policy['rule']
  385. # 时间套餐格式化
  386. prices = rule.get('prices', [])
  387. # 单位准换
  388. for item in prices:
  389. item['price'] = int(float(item['price']) * 100)
  390. item['power'] = int(item['power'])
  391. # 排序
  392. prices = sorted(prices, key=lambda _: _['power'])
  393. # 电量部分格式化(电量的价格)
  394. price = int(float(policy.get('price', 1) * 100.0))
  395. setconfig1['policy'] = {
  396. 'type': _type,
  397. 'auto_stop': True if _type == 'elec' else auto_stop,
  398. 'over_money_stop': True,
  399. 'money': money,
  400. 'rule': {
  401. 'time': 'full_stop',
  402. 'prices': prices,
  403. 'elec': 'full_stop',
  404. 'price': price
  405. }
  406. }
  407. # 先不放出来: 按次的配置
  408. # if _type == 'count':
  409. # elec = rule.get('elec', 1) * 1000000 # 单位 3.6j
  410. # time = rule.get('time', 240) * 60 # 单位: 秒
  411. #
  412. # setconfig1['policy'] = {
  413. # 'type': 'elec',
  414. # 'auto_stop': auto_stop,
  415. # 'money': 100,
  416. # 'over_money_stop': False,
  417. # 'rule': {
  418. # 'elec': elec,
  419. # 'time': time,
  420. # 'price': 100
  421. # }
  422. # }
  423. self.send_mqtt(setconfig1)
  424. if request.POST.get('card_pwd'):
  425. card_pwd = request.POST.get('card_pwd')
  426. card_pwd2 = request.POST.get('card_pwd2')
  427. if card_pwd != card_pwd2:
  428. raise ServiceException({'result': 2, 'description': u'两次密码输入不一致'})
  429. self.check_pwd(card_pwd)
  430. enObj = EncryptDate(cardKey)
  431. setconfig2.update({'card_cur_key': enObj.encrypt(card_pwd)})
  432. if request.POST.get('card_refund', None) is not None:
  433. setconfig2.update({'card_refund': request.POST.get('card_refund')})
  434. if request.POST.get('card_disable', None) is not None:
  435. setconfig2.update({'card_disable': request.POST.get('card_disable')})
  436. if request.POST.get('card_timeout'):
  437. setconfig2.update({'card_timeout': int(request.POST.get('card_timeout'))})
  438. if request.POST.get('card_oncefee'):
  439. setconfig2.update({'card_oncefee': int(float(request.POST.get('card_oncefee')) * 100)})
  440. self.send_mqtt(setconfig2)
  441. def get_dev_setting(self):
  442. """
  443. 获取参数显示在前台
  444. :return:
  445. """
  446. # 获取主板侧的参数
  447. devInfo = self.send_mqtt({'fun_code': 12})
  448. # 参数整合
  449. data = dict()
  450. configs = devInfo['data']
  451. data['mach_max_watt'] = configs.get('mach_max_watt', 0)
  452. data['port_max_ampr'] = configs.get('port_max_ampr', 0)
  453. data['port_max_watt'] = configs.get('port_max_watt', 0)
  454. data['mach_max_volt'] = configs.get('mach_max_volt', 0)
  455. data['mach_max_temp'] = configs.get('mach_max_temp', 0)
  456. # 浮充参数的添加
  457. float_charge = configs.get('float_charge', {})
  458. data.update(float_charge)
  459. # 空载适配
  460. data.update({
  461. 'noload_check_watt': int(configs['noload_check'].get('watt', 0)),
  462. 'noload_check_time': int(configs['noload_check'].get('time', 0)),
  463. })
  464. # 音量适配
  465. volume_list = []
  466. for k, v in configs['volumes'].items():
  467. item = {}
  468. if k == 'default':
  469. continue
  470. if '-' in k:
  471. item['start'], item['end'] = k.split('-')
  472. item['volume'] = v
  473. volume_list.append(item)
  474. data.update({
  475. 'volume': configs['volumes']['default'],
  476. 'volume_list': volume_list
  477. })
  478. # 价格适配
  479. policy = configs['policy']
  480. policy['money'] = round(float(policy.get('money', 100)) * 0.01, 2)
  481. rule = policy.get('rule', {})
  482. # 功率计费部分
  483. prices = rule.get('prices', [])
  484. for item in prices:
  485. item['price'] = round(float(item['price']) * 0.01, 2)
  486. item['power'] = int(item['power'])
  487. prices = sorted(prices, key=lambda _: _['power'])
  488. # 电量计费部分
  489. price = round(float(rule.get('price', 100)) * 0.01, 2)
  490. rule.update({
  491. # 时间部分
  492. 'prices': prices,
  493. # 电量部分
  494. 'price': price
  495. })
  496. policy['rule'] = rule
  497. data.update({'policy': policy})
  498. # 17 指令
  499. devInfo = self.send_mqtt({'fun_code': 17})
  500. configs2 = devInfo.get('data')
  501. data['card_curmode'] = configs2['card_curmode']
  502. data['card_refund'] = configs2['card_refund']
  503. data['card_disable'] = configs2['card_disable']
  504. # data['card_token'] = configs2['card_token']
  505. data['card_timeout'] = configs2['card_timeout']
  506. state = self.get_dev_consume_count()
  507. data.update(state)
  508. return data
  509. def get_dev_consume_count(self):
  510. data = {'fun_code': 8}
  511. devInfo = self.send_mqtt(data)
  512. total_card = round(devInfo.get('data', {}).get('total_card', 0) * 0.01, 2)
  513. return {'total_card': total_card}
  514. def reset_total_card(self):
  515. data = {
  516. 'fun_code': 9
  517. }
  518. self.send_mqtt(data)
  519. def set_max_watt(self, max_watt):
  520. self.send_mqtt({'fun_code': 11, 'max_watt': int(max_watt)})
  521. def lock_unlock_port(self, port, lock=True):
  522. portInfo = self.get_port_info(port)
  523. if portInfo and portInfo['status'] == Const.DEV_WORK_STATUS_WORKING and lock:
  524. raise ServiceException({'result': 2, 'description': u'端口正忙,请先关闭端口后,再禁止端口'})
  525. typeStr = not lock
  526. self.send_mqtt({'port': int(port), 'enable': typeStr, 'fun_code': 13})
  527. @staticmethod
  528. def check_pwd(pwd):
  529. if len(pwd) != 6:
  530. raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'})
  531. for char in pwd:
  532. if not (char >= '0' and char <= '9'):
  533. raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'})
  534. return
  535. def get_card_mode(self):
  536. devInfo = self.send_mqtt({'fun_code': 17})
  537. MAP_MODE = {
  538. 'NORMAL': 0,
  539. 'ISSUE': 1,
  540. 'MODKEY': 2,
  541. }
  542. result = {}
  543. result['card_mode'] = MAP_MODE.get(devInfo['data']['card_curmode'])
  544. return result
  545. def set_card_mode(self, setConf):
  546. cardMode = int(setConf.get('card_mode'))
  547. data = {'fun_code': 16}
  548. if cardMode == 0:
  549. data.update({'card_curmode': {'mod': 'NORMAL'}})
  550. elif cardMode == 1: # 格式化为离线卡
  551. self.check_pwd(setConf['new_pwd'])
  552. newPwd = setConf['new_pwd']
  553. if not str(setConf['balance']).isdigit():
  554. raise ServiceException({'result': 2, 'description': u'余额必须是数字'})
  555. balance = int(setConf['balance'])
  556. if not (balance >= 0 and balance <= 5000):
  557. raise ServiceException({'result': 2, 'description': u'余额必须在0和5000元之间'})
  558. card_dft_val = balance * 100 # 硬件模块记录的单位是角
  559. enObj = EncryptDate(cardKey)
  560. data.update({'card_curmode': {'mod': 'ISSUE', 'cfg': {'card_new_key': enObj.encrypt(str(newPwd)),
  561. 'card_dft_val': card_dft_val}}})
  562. elif cardMode == 2:
  563. self.check_pwd(setConf['new_pwd'])
  564. oldPwd = setConf.get('old_pwd', '')
  565. newPwd = setConf.get('new_pwd', '')
  566. enObj = EncryptDate(cardKey)
  567. data.update({'card_curmode': {'mod': 'MODKEY', 'cfg': {'card_old_key': enObj.encrypt(str(oldPwd)),
  568. 'card_new_key': enObj.encrypt(str(newPwd))}}})
  569. self.send_mqtt(data)
  570. def response_card_charge_result(self, cardNo, result):
  571. self.send_mqtt({'fun_code': 36, 'card_no': cardNo, 'result': result})
  572. def recharge_card(self, cardNo, money, orderNo=None):
  573. self.send_mqtt(
  574. {'fun_code': 36, 'result': 1, 'card_no': cardNo, 'charge': int(money * 100), 'order_id': orderNo})
  575. card = Card.objects.filter(cardNo=cardNo, dealerId=self.device.ownerId).first()
  576. balance = card.balance + money
  577. return {
  578. 'result': ErrorCode.SUCCESS,
  579. 'description': ''
  580. }, balance
  581. def get_current_use(self, **kw):
  582. base_data = kw.get('base_data')
  583. spDict = kw.get('spDict')
  584. sp = ServiceProgress.objects.filter(device_imei=self.device.devNo, port=spDict['port']).first()
  585. data = {'fun_code': 2, 'port': spDict.get('port')}
  586. devInfo = self.send_mqtt(data)
  587. portInfo = devInfo.get('data', {})
  588. exec_orders = portInfo.get('exec_orders', [])
  589. running_order = None
  590. waiting_order = []
  591. for exec_order in exec_orders: # 第一层筛选
  592. if exec_order['id'] not in sp.consumes:
  593. if exec_order['id'] in sp.consumes:
  594. sp.consumes.remove(exec_order['id'])
  595. continue
  596. if exec_order['status'] == 'running':
  597. running_order = exec_order
  598. elif exec_order['status'] == 'waiting':
  599. waiting_order.append(exec_order)
  600. if len(sp.consumes) == 0: # 上一单没有正常结束 刷新此单的状态
  601. if running_order:
  602. sp.consumes.append(running_order['id'])
  603. sp.start_time = running_order['exec_time']
  604. sp.isFinished = False
  605. sp.finished_time = sp.start_time + 12 * 60 * 60
  606. if waiting_order:
  607. for wait_one in waiting_order:
  608. sp.consumes.append(wait_one['id'])
  609. sp.finished_time = sp.start_time + 12 * 60 * 60
  610. sp.save()
  611. pay_unit = self.show_pay_unit
  612. result_list = [] # 数据整理返回
  613. for exec_order in exec_orders:
  614. item = {}
  615. item.update(base_data)
  616. item['orderNo'] = exec_order['id']
  617. item['port'] = exec_order['port']
  618. order = ConsumeRecord.objects.filter(orderNo=exec_order['id']).first()
  619. if exec_order['status'] == 'running':
  620. item['voltage'] = round(portInfo.get('volt', 0), 2)
  621. item['power'] = round(portInfo.get('watt', 0), 2)
  622. item['ampere'] = round((portInfo.get('ampr', 0) * 0.001), 2)
  623. item['usedTime'] = round(exec_order.get('time', 0) / 60.0, 1)
  624. # item['elec'] = round(exec_order.get('elec', 0) * 0.000001, 4)
  625. if exec_order['order_type'] == 'apps_start':
  626. try:
  627. item['consumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), pay_unit)
  628. item['leftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2), pay_unit)
  629. item['order'] = {
  630. 'orderNo': exec_order['id'], # 停止按钮传订单停单用
  631. 'coin': '{}{}'.format(round(order.coin, 2), pay_unit),
  632. 'port': exec_order['port'],
  633. 'consumeType': 'mobile',
  634. }
  635. except:
  636. pass
  637. elif exec_order['order_type'] == 'card_start':
  638. try:
  639. item['cardNo'] = exec_order['card_no']
  640. item['cardConsumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), pay_unit)
  641. item['cardLeftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2),
  642. pay_unit)
  643. item['order'] = {
  644. 'orderNo': exec_order['id'], # 停止按钮传订单停单用
  645. 'coin': '{}{}'.format(round(exec_order.get('amount', 0) * 0.01, 2), pay_unit),
  646. 'port': exec_order['port'],
  647. 'consumeType': 'card',
  648. }
  649. except:
  650. pass
  651. else:
  652. pass
  653. elif exec_order['status'] == 'waiting':
  654. if exec_order['chrmt'] == 'TIME':
  655. item['needTime'] = '{}分钟'.format(round(exec_order.get('amount_time', 0) / 60.0, 1))
  656. item['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1)
  657. elif exec_order['chrmt'] == 'ELEC':
  658. item['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2)
  659. item['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 2)
  660. item['desc'] = '此订单已经下发到设备上,上一单运行完毕就会自动运行此订单'
  661. item['order'] = {
  662. 'orderNo': exec_order['id'], # 停止按钮传订单停单用
  663. 'coin': '{}币'.format(round(exec_order.get('amount', 0) * 0.01, 2)),
  664. 'port': exec_order['port'],
  665. 'consumeType': 'card' if 'cardNo' in exec_order else 'mobile',
  666. }
  667. if order.monthlyPackageId: # 包月卡抵扣
  668. item.pop('cardConsumeMoney', None)
  669. item.pop('cardLeftMoney', None)
  670. item.pop('needTime', None)
  671. # item.pop('usedTime', None)
  672. item.pop('leftTime', None)
  673. if 'cardNo' in exec_order:
  674. item['cardNo'] = exec_order['card_no']
  675. item.update(DeviceType.get_services_button(self.device['devType']['id']))
  676. result_list.append(item)
  677. return result_list
  678. def isHaveStopEvent(self):
  679. return True
  680. def stop_by_order(self, port, orderNo):
  681. data = {'fun_code': 4, 'order_id': orderNo, 'operator': 'user'}
  682. self.send_mqtt(data)
  683. def clear_dev_feecount(self):
  684. data = {'fun_code': 0x09, 'total_coin': True, 'total_card': True}
  685. self.send_mqtt(data)
  686. def reboot_device(self):
  687. # 重启单片机
  688. MessageSender.send(self.device, DeviceCmdCode.SET_DEVINFO, {'reset_mcu': True})
  689. # 重启模块
  690. MessageSender.send(self.device, DeviceCmdCode.SET_DEVINFO, {'restart': True})
  691. @property
  692. def show_pay_unit(self):
  693. """
  694. 前台显示付费的时候,目前有不同的客户希望 显示不同的单位 有的显示金币 有的显示元, 这个地方处理下
  695. :return:
  696. """
  697. return u'元'
  698. def get_port_using_detail(self, port, ctrInfo, isLazy=False):
  699. return self.get_port_info(port)
  700. def stop(self, port=None):
  701. return self.stop_charging_port(int(port))
  702. def __translate_status_from_str(self, status):
  703. dictConf = {
  704. 'idle': Const.DEV_WORK_STATUS_IDLE,
  705. 'busy': Const.DEV_WORK_STATUS_WORKING,
  706. 'forbid': Const.DEV_WORK_STATUS_FORBIDDEN,
  707. 'fault': Const.DEV_WORK_STATUS_FAULT,
  708. 'running': Const.DEV_WORK_STATUS_WORKING
  709. }
  710. return dictConf.get(status, Const.DEV_WORK_STATUS_IDLE)
  711. def update_show_pg(self, data):
  712. for k, v in data.items():
  713. v['showPG'] = True
  714. # @SmartBox.life_cycle(after=update_show_pg)
  715. def get_many_port_info(self, portList):
  716. data = {'fun_code': 1, 'all': True}
  717. devInfo = self.send_mqtt(data)
  718. portInfo = devInfo['data']
  719. portParam = portInfo.get('port_param', {})
  720. exec_queue = portInfo.get('exec_queue', {})
  721. pay_unit = self.show_pay_unit
  722. resultDict = {}
  723. for port, exec_orders in exec_queue.items():
  724. if port not in portList:
  725. continue
  726. result = {'index': port}
  727. onePortParam = portParam.get(port, {})
  728. _wait = []
  729. for exec_order in exec_orders:
  730. order = ConsumeRecord.objects.filter(orderNo=exec_order['id']).first() # type: ConsumeRecord
  731. if exec_order['status'] == 'running':
  732. result['voltage'] = round(onePortParam.get('volt', 0), 2)
  733. result['power'] = round(onePortParam.get('watt', 0), 2)
  734. result['ampere'] = round((onePortParam.get('ampr', 0) * 0.001), 2)
  735. result['devTemp'] = round((portInfo.get('mach_temp', 0)), 2)
  736. result['status'] = self.__translate_status_from_str(exec_order['status'])
  737. result['usedTime'] = round(exec_order.get('time', 0) / 60.0, 2)
  738. result['usedElec'] = round(exec_order.get('elec', 0) * 0.000001, 4)
  739. result['coins'] = order.coin if order else RMB(
  740. (exec_order.get('policy', {}).get('money', 0)) * 0.01)
  741. result['startTime'] = order.dateTimeAdded.strftime(
  742. '%m-%d %H:%M:%S') if order else datetime.datetime.fromtimestamp(
  743. exec_order['create_time']).strftime('%m-%d %H:%M:%S')
  744. if exec_order['order_type'] == 'apps_start':
  745. if not order:
  746. result['nickName'] = '经销商上分'
  747. else:
  748. result['nickName'] = order.user.nickname
  749. result['openId'] = order.openId
  750. result['consumeType'] = 'mobile'
  751. result['consumeMoney'] = '{}{}'.format(RMB.fen_to_yuan(exec_order['money']), pay_unit)
  752. policy = exec_order.get('policy', {})
  753. rule = exec_order.get('policy', {}).get('rule', {})
  754. if rule:
  755. if 'time' in rule:
  756. if order:
  757. result['needTime'] = order.servicedInfo['needTime']
  758. else:
  759. result['needTime'] = format(rule['time'] / 60.0, '.1f') + '分钟'
  760. else:
  761. if order:
  762. result['needElec'] = order.servicedInfo['needElec']
  763. else:
  764. result['needElec'] = format(rule['elec'] / 1000000.0, '.1f')
  765. if policy.get('billingMethod') == 'postpaid':
  766. result['consumeType'] = 'postpaid'
  767. if exec_order['order_type'] == 'card_start':
  768. result['consumeType'] = 'card'
  769. if order:
  770. result['nickName'] = order.user.nickname
  771. result['openId'] = order.openId
  772. result['cardNo'] = exec_order['card_no']
  773. result['cardConsumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2),
  774. pay_unit)
  775. result['cardBalance'] = '{}{}'.format(round(exec_order['balance'] * 0.01, 2), pay_unit)
  776. elif exec_order['status'] == 'waiting':
  777. _one = {}
  778. if 'amount_time' in exec_order:
  779. _one['needTime'] = '{}分钟'.format(round(exec_order['amount_time'] / 60.0, 1))
  780. if 'amount_elec' in exec_order:
  781. _one['needElec'] = '{}'.format(round(exec_order['amount_elec'] / 1000000.0, 2))
  782. if 'amount' in exec_order:
  783. _one['coins'] = '{}{}'.format(round(exec_order['amount'] / 100.0, 2), pay_unit)
  784. if 'create_time' in exec_order:
  785. _one['createTime'] = datetime.datetime.fromtimestamp(
  786. int(exec_order['create_time'])).strftime('%m-%d %H:%M:%S')
  787. if exec_order['order_type'] == 'apps_start':
  788. _one['consumeType'] = 'mobile'
  789. if not order:
  790. _one['nickName'] = '经销商上分'
  791. else:
  792. _one['nickName'] = order.user.nickname
  793. elif exec_order['order_type'] == 'card_start':
  794. _one['consumeType'] = 'card'
  795. _one['cardNo'] = exec_order['card_no']
  796. _one['cardBalance'] = '{}{}'.format(round(exec_order['balance'] * 0.01, 2), pay_unit)
  797. if order:
  798. _one['nickName'] = order.nickname
  799. _wait.append(_one)
  800. if _wait:
  801. result['waittingOrder'] = _wait
  802. resultDict[port] = result
  803. return resultDict
  804. @property
  805. def support_device_package(self):
  806. return True