weifule_car_home.py 46 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import re
  6. import threading
  7. import time
  8. from decimal import Decimal
  9. from django.core.cache import cache
  10. from mongoengine import Q
  11. from apilib.monetary import RMB
  12. from apilib.utils_AES import EncryptDate
  13. from apps import serviceCache
  14. from apps.web.common.proxy import ClientConsumeModelProxy
  15. from apps.web.constant import DeviceCmdCode, ErrorCode, Const, MQTT_TIMEOUT
  16. from apps.web.core.adapter.base import SmartBox
  17. from apps.web.core.exceptions import ServiceException, DeviceNetworkTimeoutError, StartDeviceError
  18. from apps.web.core.networking import MessageSender
  19. from apps.web.device.models import Device, DeviceType
  20. from apps.web.user.models import ServiceProgress, Card, MyUser, ConsumeRecord
  21. cardKey = 'FR4e1OFCnDdrYA7u'
  22. logger = logging.getLogger(__name__)
  23. class WeiFuLeCar(SmartBox):
  24. def __init__(self, device):
  25. super(WeiFuLeCar, self).__init__(device)
  26. self.port = '1'
  27. def analyze_event_data(self, device_data):
  28. uart_data = device_data.get('data')
  29. if not uart_data:
  30. return
  31. fun_code = uart_data.get('fun_code')
  32. if not fun_code:
  33. return
  34. billingType = 'elec'
  35. cmd = fun_code
  36. if cmd == '32':
  37. return uart_data.get('order')
  38. def disable_app_device(self, switch=True):
  39. # type:(bool) -> None
  40. otherConf = self.device.get('otherConf', {})
  41. otherConf['disableDevice'] = switch
  42. Device.objects.filter(devNo=self.device['devNo']).update(otherConf=otherConf)
  43. Device.invalid_device_cache(self.device['devNo'])
  44. @staticmethod
  45. def check_params_range(params, minData=None, maxData=None, desc=''):
  46. # type:(str,float,float,str) -> str
  47. """
  48. 检查参数,返回字符串参数
  49. """
  50. if params is None:
  51. raise ServiceException({'result': 2, 'description': u'参数错误.'})
  52. if not isinstance(params, Decimal):
  53. params = Decimal(params)
  54. if not minData and maxData:
  55. if not isinstance(maxData, Decimal):
  56. maxData = Decimal(maxData)
  57. if params <= maxData:
  58. return '%g' % params
  59. else:
  60. raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最大值为%g' % (desc, maxData)})
  61. if not maxData and minData:
  62. if not isinstance(minData, Decimal):
  63. minData = Decimal(minData)
  64. if minData <= params:
  65. return '%g' % params
  66. else:
  67. raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最小值为%g' % (desc, minData)})
  68. if not minData and not maxData:
  69. return '%g' % params
  70. else:
  71. if not isinstance(minData, Decimal):
  72. minData = Decimal(minData)
  73. if not isinstance(maxData, Decimal):
  74. maxData = Decimal(maxData)
  75. if minData <= params <= maxData:
  76. return '%g' % params
  77. else:
  78. raise ServiceException(
  79. {'result': 2, 'description': u'%s参数超出可选范围,可取范围为%g-%g' % (desc, minData, maxData)})
  80. def send_mqtt(self, data=None, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, otherData=None, timeout=5):
  81. """
  82. 发送mqtt 指令默认210 返回data
  83. """
  84. if data:
  85. payload = {'data': data}
  86. else:
  87. payload = otherData
  88. result = MessageSender.send(self.device, cmd,
  89. payload, timeout=timeout)
  90. if 'rst' in result and result['rst'] != 0:
  91. if result['rst'] == -1:
  92. raise ServiceException(
  93. {'result': 2, 'description': u'该设备正在玩命找网络,请您稍候再试', 'rst': -1})
  94. elif result['rst'] == 1:
  95. raise ServiceException(
  96. {'result': 2, 'description': u'该设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1})
  97. else:
  98. if cmd in [DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE]:
  99. return
  100. if result.get('data') == '00':
  101. raise ServiceException({'result': 2, 'description': u'设备操作失败.请重试'})
  102. else:
  103. return result.get('data', 'ok')
  104. def _do_update_configs(self, updateDict):
  105. dev = Device.objects.get(devNo=self.device.devNo)
  106. deviceConfigs = dev.otherConf.get('deviceConfigs', {})
  107. deviceConfigs.update(updateDict)
  108. dev.otherConf['deviceConfigs'] = deviceConfigs
  109. dev.save()
  110. Device.invalid_device_cache(self.device.devNo)
  111. self._device = Device.get_dev(self.device.devNo)
  112. def _get_device_configs(self):
  113. return self.device.otherConf.get('deviceConfigs', {})
  114. def _start(self, port, money, order_id):
  115. amount = int(float(money) * 100)
  116. data = {
  117. 'fun_code': 7,
  118. 'port': port,
  119. 'amount': amount,
  120. 'order_id': order_id
  121. }
  122. payload = {'data': data}
  123. return MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, payload,
  124. timeout=MQTT_TIMEOUT.START_DEVICE)
  125. def do_ack_order_32(self, order_id):
  126. data = {
  127. 'fun_code': 32,
  128. 'order_id': order_id
  129. }
  130. self.send_mqtt(data)
  131. def do_ack_remove_order_from_device_34(self, order_id):
  132. data = {
  133. 'fun_code': 34,
  134. 'order_id': order_id
  135. }
  136. self.send_mqtt(data)
  137. def _check_dev_status(self, port):
  138. data = {
  139. 'fun_code': 2,
  140. 'port': int(port)
  141. }
  142. data = self.send_mqtt(data)
  143. exec_orders = data.get('exec_task') or []
  144. order_list = list(map(lambda x: x['id'], exec_orders))
  145. result = False
  146. status = data.get('status')
  147. if status == 'fault':
  148. raise ServiceException({'result': 2, 'description': u'该充电桩出现故障,请使用其他充电桩'})
  149. elif status == 'idle':
  150. raise ServiceException({'result': 2, 'description': u'请先连接充电枪'})
  151. elif status == 'link':
  152. result = True
  153. elif status == 'estop':
  154. raise ServiceException({'result': 2, 'description': u'该充电桩处于 紧急停止 状态,请确认充电桩安全状态后,再次扫码使用或选择其他充电桩'})
  155. elif status == 'ready':
  156. result = True
  157. elif status == 'busy':
  158. result = True
  159. else:
  160. pass
  161. return {'result': result, 'order_list': order_list}
  162. def _check_package(self, package):
  163. """
  164. 获取设备启动的发送数据 根据设备的当前模式以及套餐获取
  165. :param package:
  166. :return:
  167. """
  168. unit = package.get('unit')
  169. _time = package.get('time')
  170. billingType = 'elec'
  171. if unit != u'度':
  172. raise ServiceException({'result': 2, 'description': u'套餐单位错误,应选取单位(度),请联系经销商'})
  173. else:
  174. _time = _time
  175. return _time, unit, billingType
  176. def _transform_prices(self, prices, mode='send'):
  177. if mode == 'send':
  178. send_list = []
  179. default_price = round(float(prices.get('default_price', 0)), 2)
  180. item = ['default', default_price]
  181. send_list.append(item)
  182. if all([prices.get('time1_start_m'), prices.get('time1_start_h'), prices.get('time1_end_m'),
  183. prices.get('time1_end_h'), prices.get('price1')]):
  184. time1_start_m = '{0:0>2}'.format(prices.get('time1_start_m'))
  185. time1_start_h = '{0:0>2}'.format(prices.get('time1_start_h'))
  186. time1_end_m = '{0:0>2}'.format(prices.get('time1_end_m'))
  187. time1_end_h = '{0:0>2}'.format(prices.get('time1_end_h'))
  188. price1 = round(float(prices.get('price1', 0)), 2)
  189. if time1_end_h + ':' + time1_end_m <= time1_start_h + ':' + time1_start_m:
  190. raise ServiceException({'result': 2, 'description': u'时段1结束时间必须大于起始时间'})
  191. str = time1_start_h + ':' + time1_start_m + '-' + time1_end_h + ':' + time1_end_m
  192. item = [str, price1]
  193. send_list.append(item)
  194. else:
  195. raise ServiceException({'result': 2, 'description': u'时段1参数不完整'})
  196. if all([prices.get('time2_start_m'), prices.get('time2_start_h'), prices.get('time2_end_m'),
  197. prices.get('time2_end_h'), prices.get('price2')]):
  198. time2_start_m = '{0:0>2}'.format(prices.get('time2_start_m'))
  199. time2_start_h = '{0:0>2}'.format(prices.get('time2_start_h'))
  200. time2_end_m = '{0:0>2}'.format(prices.get('time2_end_m'))
  201. time2_end_h = '{0:0>2}'.format(prices.get('time2_end_h'))
  202. price2 = round(float(prices.get('price2', 0)), 2)
  203. if time2_end_h + ':' + time2_end_m <= time2_start_h + ':' + time2_start_m:
  204. raise ServiceException({'result': 2, 'description': u'时段2结束时间必须大于起始时间'})
  205. str = time2_start_h + ':' + time2_start_m + '-' + time2_end_h + ':' + time2_end_m
  206. item = [str, price2]
  207. send_list.append(item)
  208. else:
  209. raise ServiceException({'result': 2, 'description': u'时段2参数不完整'})
  210. if all([prices.get('time3_start_m'), prices.get('time3_start_h'), prices.get('time3_end_m'),
  211. prices.get('time3_end_h'), prices.get('price3')]):
  212. time3_start_m = '{0:0>2}'.format(prices.get('time3_start_m'))
  213. time3_start_h = '{0:0>2}'.format(prices.get('time3_start_h'))
  214. time3_end_m = '{0:0>2}'.format(prices.get('time3_end_m'))
  215. time3_end_h = '{0:0>2}'.format(prices.get('time3_end_h'))
  216. price3 = round(float(prices.get('price3', 0)), 2)
  217. if time3_end_h + ':' + time3_end_m <= time3_start_h + ':' + time3_start_m:
  218. raise ServiceException({'result': 2, 'description': u'时段3结束时间必须大于起始时间'})
  219. str = time3_start_h + ':' + time3_start_m + '-' + time3_end_h + ':' + time3_end_m
  220. item = [str, price3]
  221. send_list.append(item)
  222. else:
  223. raise ServiceException({'result': 2, 'description': u'时段3参数不完整'})
  224. if not (
  225. time3_start_h + ':' + time3_start_m >= time2_end_h + ':' + time2_end_m and time2_start_h + ':' + time2_start_m >= time1_end_h + ':' + time1_end_m):
  226. raise ServiceException({'result': 2, 'description': u'时段的其实时间不能小于上一个时段的结束时间'})
  227. return send_list
  228. else:
  229. price_dict = {}
  230. index = 1
  231. for price in prices:
  232. if price[0] == 'default':
  233. price_dict.update({'default_price': price[1]})
  234. else:
  235. time1_start, time1_end = price[0].split('-')
  236. price_dict.update({
  237. 'time{}_start_h'.format(index): time1_start.split(':')[0],
  238. 'time{}_start_m'.format(index): time1_start.split(':')[1],
  239. 'time{}_end_h'.format(index): time1_end.split(':')[0],
  240. 'time{}_end_m'.format(index): time1_end.split(':')[1],
  241. 'price{}'.format(index): price[1]
  242. })
  243. index += 1
  244. return price_dict
  245. def _reboot_device(self):
  246. data = {
  247. 'fun_code': 11,
  248. 'reset_mcu': True,
  249. }
  250. self.send_mqtt(data)
  251. def _restart_device(self):
  252. data = {
  253. 'restart': True,
  254. }
  255. self.send_mqtt(otherData=data, cmd=DeviceCmdCode.SET_DEVINFO)
  256. def _factory_set_device(self):
  257. data = {
  258. 'factory_set': True,
  259. }
  260. self.send_mqtt(otherData=data, cmd=DeviceCmdCode.SET_DEVINFO)
  261. def _get_current_order(self):
  262. data = {
  263. 'fun_code': 2,
  264. 'exec_orders': True,
  265. }
  266. data = self.send_mqtt(data)
  267. return data.get('exec_orders', [])
  268. def _get_total_card(self):
  269. data = {
  270. 'fun_code': 8
  271. }
  272. data = self.send_mqtt(data)
  273. return {'total_card': int(data.get('total_card', 0)) / 100.0}
  274. def _reset_total_card(self):
  275. data = {
  276. 'fun_code': 9
  277. }
  278. self.send_mqtt(data)
  279. def is_port_can_use(self, port, canAdd=False):
  280. return True, ''
  281. # data = {
  282. # 'fun_code': 2,
  283. # 'status': True,
  284. # 'exec_orders': True,
  285. # 'wait_orders': True,
  286. # }
  287. # data = self.send_mqtt(data)
  288. # exec_orders = data.get('exec_orders')
  289. # wait_orders = data.get('wait_orders')
  290. #
  291. # order_list = []
  292. # if exec_orders:
  293. # order_list.append(exec_orders[0]['id'])
  294. # if wait_orders:
  295. # order_list += list(map(lambda x: x['id'], wait_orders))
  296. #
  297. # status = data.get('status')
  298. # if status == 'fault':
  299. # return False, '该充电桩出现故障,请使用其他充电桩'
  300. # elif status == 'idle':
  301. # return False, '请先连接充电枪'
  302. # elif status == 'link':
  303. # return True, ''
  304. # elif status == 'estop':
  305. # raise False, '该充电桩处于 紧急停止 状态,请确认充电桩安全状态后,再次扫码使用或选择其他充电桩'
  306. # elif status == 'ready':
  307. # return True, ''
  308. # elif status == 'busy':
  309. # return True, ''
  310. # else:
  311. # return False, '该充电桩出现故障,请使用其他充电桩'
  312. def check_dev_status(self, attachParas=None):
  313. if attachParas.get('isTempPackage') == True:
  314. washConfig = self.device.get('tempWashConfig', {})
  315. else:
  316. washConfig = self.device.get('washConfig', {})
  317. packageId = attachParas.get('packageId', '1')
  318. package = washConfig.get(packageId)
  319. # self._check_package(package)
  320. port = attachParas.get('chargeIndex')
  321. if not port:
  322. raise ServiceException({'result': 2, 'description': u'请选择端口后再启动设备'})
  323. data = self._check_dev_status(port)
  324. openId = attachParas.get('openId')
  325. order_list = data.get('order_list')
  326. result = data.get('result')
  327. if not order_list:
  328. return result
  329. else:
  330. consumeRcd = ConsumeRecord.objects.filter(devNo=self.device.devNo, orderNo=order_list[0]).first()
  331. if not consumeRcd: # 没有找到订单 证明是刷卡启动的 或则经销商远程上分
  332. raise ServiceException({'result': 2, 'description': u'当前设备已经有其他人启动充电,请不要操作设备或充电枪, 小心触电!'})
  333. else:
  334. if consumeRcd.openId != openId:
  335. raise ServiceException({'result': 2, 'description': u'当前设备已有人在使用,请您选择空闲的设备进行操作'})
  336. else:
  337. return result
  338. def get_port_status(self, force=False):
  339. return self._get_port_status()
  340. def async_update_portinfo_from_dev(self):
  341. class Sender(threading.Thread):
  342. def __init__(self, smartBox):
  343. super(Sender, self).__init__()
  344. self._smartBox = smartBox
  345. def run(self):
  346. try:
  347. self._smartBox._get_port_status()
  348. except Exception as e:
  349. logger.info('get port stats from dev,e=%s' % e)
  350. sender = Sender(self)
  351. sender.start()
  352. def start_device(self, package, openId, attachParas):
  353. if attachParas is None:
  354. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  355. if not attachParas.has_key('chargeIndex'):
  356. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  357. port = int(attachParas.get('chargeIndex'))
  358. if not port:
  359. raise ServiceException({'result': 2, 'description': u'请选择端口后再启动设备'})
  360. onPoints = attachParas.get('onPoints')
  361. if onPoints: # 远程上分
  362. self._check_dev_status(port)
  363. orderNo = ConsumeRecord.make_no()
  364. logger.info('dealer onPoints package<{}> order<{}>'.format(package, orderNo))
  365. else:
  366. orderNo = str(attachParas.get('orderNo'))
  367. coins = package.get('coins')
  368. result = self._start(port, coins, orderNo)
  369. if result['rst'] == 0:
  370. consumeOrder = {
  371. 'orderNo': orderNo,
  372. 'coin': package.get('coins'),
  373. 'consumeType': 'coin',
  374. }
  375. self.register_service_progress(openId, orderNo, port, consumeOrder, attachParas)
  376. elif result['rst'] == -1: # 网络丢失
  377. raise DeviceNetworkTimeoutError()
  378. elif result['rst'] == 1:
  379. raise StartDeviceError('订单号已存在')
  380. elif result['rst'] == 2:
  381. raise StartDeviceError('订单已满')
  382. elif result['rst'] == 3:
  383. raise StartDeviceError('{}号端口被禁用'.format(port))
  384. elif result['rst'] == 4:
  385. raise StartDeviceError('计量器故障')
  386. elif result['rst'] == 5:
  387. raise StartDeviceError('检查电压异常')
  388. elif result['rst'] == 6:
  389. raise StartDeviceError('设备急停状态')
  390. elif result['rst'] == 7:
  391. raise StartDeviceError('继电器故障')
  392. elif result['rst'] == 8:
  393. raise StartDeviceError('请连接充电器')
  394. elif result['rst'] == 9:
  395. raise StartDeviceError('车辆侧充电器开关未闭合')
  396. event_info = {
  397. 'cmd': 100,
  398. 'data': {
  399. 'fun_code': 32,
  400. 'order': {
  401. 'order_type': 'apps_start',
  402. 'id': orderNo,
  403. 'status': 'running',
  404. 'adapter': True
  405. }
  406. },
  407. 'IMEI': '862167056713559',
  408. 'rst': 0
  409. }
  410. return event_info
  411. def register_service_progress(self, openId, weifuleOrderNo, port, consumeOrder=None, attachParas=None):
  412. return ServiceProgress.objects.create(
  413. open_id=openId,
  414. device_imei=self.device.devNo,
  415. devTypeCode=self.device.devTypeCode,
  416. port=port,
  417. attachParas=attachParas if attachParas else {},
  418. start_time=int(time.time()),
  419. finished_time=int(time.time() + 12 * 60 * 60),
  420. consumeOrder=consumeOrder if consumeOrder else {},
  421. weifuleOrderNo=weifuleOrderNo,
  422. expireAt=datetime.datetime.now() + datetime.timedelta(days=1)
  423. ).id
  424. def get_port_info(self, port):
  425. data = cache.get('port_info_{}_{}'.format(self.device.devNo, port))
  426. if data:
  427. return data
  428. else:
  429. data = {
  430. 'fun_code': 2,
  431. 'all': True
  432. }
  433. data = self.send_mqtt(data)
  434. exec_task = data.get('exec_orders', [])
  435. for task in exec_task:
  436. # 电量
  437. task['elec'] = round((task.pop('elec', 0) / 1000000.0), 4)
  438. # 时间
  439. task['time'] = round((task.pop('time', 0) / 60.0), 1)
  440. # 金额
  441. task['money'] = round((task.pop('money', 0) / 100.0), 2)
  442. task['left_money'] = round((task.pop('left_money', 0) / 100.0), 2)
  443. task['amount'] = round((task.pop('amount', 0) / 100.0), 2)
  444. # 卡余额
  445. if 'balance' in task:
  446. task['balance'] = round((task.pop('balance', 0) / 100.0), 2)
  447. data['power'] = round(data.pop('watt', 0), 2)
  448. data['voltage'] = round(data.pop('volt', 0), 2)
  449. data['ampere'] = round(data.pop('ampr', 0) / 1000.0, 2)
  450. cache.set('port_info_{}_{}'.format(self.device.devNo, port), data, 5)
  451. return data
  452. def lock_unlock_port(self, port, lock=True):
  453. data = {
  454. "fun_code": 13,
  455. "port": int(port),
  456. "enable": not lock
  457. }
  458. self.send_mqtt(data)
  459. def recharge_card(self, cardNo, money, orderNo=None):
  460. data = {
  461. 'card_no': cardNo,
  462. 'fun_code': 37,
  463. 'result': 1,
  464. 'charge': int(money * 100),
  465. 'order_id': orderNo
  466. }
  467. self.send_mqtt(data)
  468. card = Card.objects.filter(cardNo=cardNo, dealerId=self.device.ownerId).first()
  469. balance = card.balance + money
  470. return {
  471. 'result': ErrorCode.SUCCESS,
  472. 'description': ''
  473. }, balance
  474. def set_device_function(self, request, lastSetConf):
  475. update_dict = {'fun_code': 11}
  476. if request.POST.get('pile_disable') == True or request.POST.get('pile_disable') == False:
  477. update_dict.update({'pile_disable': request.POST['pile_disable']})
  478. if request.POST.get('pile_restart') == True:
  479. self._restart_device()
  480. return
  481. if request.POST.get('czskze') == True:
  482. self._reset_total_card()
  483. return
  484. self.send_mqtt(update_dict)
  485. self.get_dev_setting()
  486. def set_device_function_param(self, request, lastSetConf):
  487. update_dict = {'fun_code': 11}
  488. if request.POST.get('volume'):
  489. self.check_params_range(request.POST.get('volume'), minData=0, maxData=7, desc='音量')
  490. update_dict.update({'volume': int(request.POST.get('volume'))})
  491. if request.POST.get('max_ampr'):
  492. self.check_params_range(request.POST.get('max_ampr'), minData=0, maxData=32, desc='最大电流')
  493. update_dict.update({'max_ampr': int(request.POST.get('max_ampr'))})
  494. if request.POST.get('temp_threshold'):
  495. self.check_params_range(request.POST.get('temp_threshold'), minData=0, maxData=150, desc='温度阈值')
  496. update_dict.update({'temp_threshold': int(request.POST.get('temp_threshold'))})
  497. if request.POST.get('card_timeout'):
  498. self.check_params_range(request.POST.get('card_timeout'), minData=0, maxData=20, desc='刷卡超时时间')
  499. update_dict.update({'card_timeout': int(request.POST.get('card_timeout'))})
  500. if request.POST.get('prices'):
  501. prices = []
  502. for i, price in enumerate(request.POST.get('prices', [])):
  503. if i == 0:
  504. prices.append(['default', round(RMB(price['elec_fee']), 2), round(RMB(price['server_fee']), 2)])
  505. else:
  506. prices.append(
  507. ['{}-{}'.format(price['start_time'], price['end_time']), round(RMB(price['elec_fee']), 2),
  508. round(RMB(price['server_fee']), 2)])
  509. update_dict.update({'prices': prices})
  510. if len(update_dict) > 1:
  511. self.send_mqtt(update_dict)
  512. if request.POST.get('sys_old_pwd'):
  513. password = serviceCache.get(self.pwd_cache_key())
  514. if not password:
  515. raise ServiceException({'result': 2, 'description': u'当前页面已过期,请刷新后重试'})
  516. enObj = EncryptDate(cardKey)
  517. password = enObj.decrypt(password)
  518. sys_old_pwd = request.POST.get('sys_old_pwd')
  519. sys_new_pwd = request.POST.get('sys_new_pwd')
  520. if password != sys_old_pwd:
  521. raise ServiceException({'result': 2, 'description': u'旧密码输入错误'})
  522. result = re.findall(r'[0-9]{6}', sys_new_pwd)
  523. if not result or len(result[0]) != len(sys_new_pwd) or len(result[0]) < 6 or len(result[0]) > 10:
  524. raise ServiceException({'result': 2, 'description': u'新密码只能是6位数字'})
  525. update_dict.update({'sys_pwd': enObj.encrypt(sys_new_pwd)})
  526. self.send_mqtt(update_dict)
  527. serviceCache.set(self.pwd_cache_key(), enObj.encrypt(sys_new_pwd), 600)
  528. self.get_dev_setting()
  529. def get_dev_setting(self):
  530. def format_prices(prices):
  531. result = []
  532. for price in prices:
  533. if price[0] == 'default':
  534. result.append({
  535. 'elec_fee': price[1],
  536. 'server_fee': price[2],
  537. })
  538. else:
  539. result.append({
  540. 'start_time': price[0].split('-')[0],
  541. 'end_time': price[0].split('-')[1],
  542. 'elec_fee': price[1],
  543. 'server_fee': price[2],
  544. })
  545. return result
  546. data = {
  547. 'fun_code': 12,
  548. 'all': True,
  549. }
  550. data = self.send_mqtt(data)
  551. result = {}
  552. result['max_ampr'] = data.get('max_ampr', 0)
  553. result['volume'] = data.get('volume', 0)
  554. result['pile_disable'] = data.get('pile_disable', False)
  555. result['card_timeout'] = data.get('card_timeout', 0)
  556. result['temp_threshold'] = data.get('temp_threshold', 0)
  557. result['prices'] = format_prices(data.get('prices', []))
  558. if 'sys_pwd' in data:
  559. serviceCache.set(self.pwd_cache_key(), data['sys_pwd'], 600)
  560. self._do_update_configs(data)
  561. return result
  562. def get_port_status_from_dev(self):
  563. data = {
  564. 'fun_code': 2,
  565. 'all': True
  566. }
  567. data = self.send_mqtt(data)
  568. status = data.get('status')
  569. port = self.port
  570. result = []
  571. item = {
  572. 'index': port,
  573. 'voltage': round(data.get('volt', 0), 2),
  574. 'power': round(data.get('watt', 0), 2),
  575. 'ampere': round(data.get('ampr', 0) * 0.001, 2),
  576. 'devTemp': round(data.get('temp', 0), 2),
  577. }
  578. if status == 'busy' or status == 'ready':
  579. item.update({'status': status})
  580. exec_task = data.get('exec_orders', [])
  581. waittingOrder = []
  582. for task in exec_task:
  583. # 启动方式 个人信息
  584. consumeOrder = ConsumeRecord.objects.filter(Q(orderNo=task['id']) | Q(sequanceNo=task['id']), devNo=self.device.devNo).first()
  585. if task['order_type'] == 'apps_start':
  586. item['consumeType'] = 'mobile'
  587. if not consumeOrder:
  588. people = MyUser(nickname='经销商远程上分')
  589. else:
  590. people = consumeOrder.user
  591. item['nickName'] = people.nickname
  592. else:
  593. item['consumeType'] = 'card'
  594. item['cardNo'] = task['card_no']
  595. if consumeOrder:
  596. card = Card.objects.filter(cardNo=task['card_no'], dealerId=self.device.ownerId).first()
  597. card and item.update({'nickName': card.nickName or card.cardName})
  598. else:
  599. item.update({'nickName': '匿名用户'})
  600. # 订单状态
  601. if task['status'] == 'running':
  602. # 设备参数
  603. # 电量
  604. item['elec'] = round(task['elec'] / 1000000.0, 2)
  605. # 时间
  606. item['usedTime'] = round(task['time'] / 60.0, 1)
  607. # 金额
  608. records = task['records']
  609. item['elecFee'] = round(sum(map(lambda _: _['elec_money'], records)) * 0.01, 2)
  610. item['serviceFee'] = round(sum(map(lambda _: _['serv_money'], records)) * 0.01, 2)
  611. item['consumeMoney'] = '{}{}'.format(item['elecFee'] + item['serviceFee'], self.show_pay_unit)
  612. item['coins'] = '{}{}'.format(RMB.fen_to_yuan(task['amount']), self.show_pay_unit)
  613. # 开始时间
  614. start_time = task.get('create_time')
  615. start_time = datetime.datetime.fromtimestamp(start_time)
  616. item['startTime'] = start_time.strftime('%m-%d %H:%M:%S')
  617. if consumeOrder: # 后付费
  618. payAfterUse = consumeOrder.attachParas.get('payAfterUse')
  619. if payAfterUse:
  620. item['consumeType'] = 'postpaid'
  621. item.pop('leftMoney', None)
  622. item.pop('coins', None)
  623. elif task['status'] == 'waiting':
  624. one = {}
  625. one['coins'] = '{}{}'.format(task['amount'], self.show_pay_unit)
  626. createTime = datetime.datetime.fromtimestamp(task['create_time'])
  627. one['createTime'] = createTime.strftime('%m-%d %H:%M:%S')
  628. if task['order_type'] == 'apps_start':
  629. one['consumeType'] = 'mobile'
  630. if not consumeOrder:
  631. people = MyUser(nickname='经销商远程上分')
  632. else:
  633. people = consumeOrder.user
  634. consumeOne = ConsumeRecord.objects.filter(Q(orderNo=task['id']) | Q(sequanceNo=task['id']), devNo=self.device.devNo).first()
  635. if consumeOne.attachParas.get('payAfterUse'):
  636. one['consumeType'] = 'postpaid'
  637. one['nickName'] = people.nickname
  638. elif task['order_type'] == 'card_start':
  639. one['consumeType'] = 'card'
  640. one['cardNo'] = task.get('card_no')
  641. if consumeOrder:
  642. card = Card.objects.filter(cardNo=task['card_no'], dealerId=self.device.ownerId).first()
  643. one.update({'nickName': card.nickName or card.cardName})
  644. else:
  645. one.update({'nickName': '匿名用户'})
  646. one['cardBalance'] = '{}{}'.format(task['balance'], self.show_pay_unit)
  647. waittingOrder.append(one)
  648. if waittingOrder:
  649. item['waittingOrder'] = waittingOrder
  650. elif status == 'fault':
  651. item.update({'status': status})
  652. elif status == 'estop':
  653. item.update({'status': status})
  654. elif status == 'idle':
  655. item.update({'status': status})
  656. elif status == 'link':
  657. item.update({'status': 'connected'})
  658. elif status == 'forbiden':
  659. item.update({'status': 'ban'})
  660. result.append(item)
  661. return result
  662. def stop(self, port=None):
  663. data = {
  664. 'fun_code': 6,
  665. 'operator': 'dealer',
  666. 'port': int(port)
  667. }
  668. self.send_mqtt(data)
  669. def active_deactive_port(self, port, active):
  670. if active == False:
  671. self.stop(port)
  672. def stop_by_order(self, port=None, orderNo=''):
  673. order = ConsumeRecord.objects.filter(orderNo=orderNo, isNormal=True).first()
  674. if not order:
  675. logger.info('no this order <{}>'.format(orderNo))
  676. return
  677. people = MyUser.objects.filter(openId=order.openId, groupId=self.device['groupId']).first()
  678. data = {
  679. 'fun_code': 4,
  680. 'operator': 'user',
  681. 'operator_id': str(people.id),
  682. 'order_id': orderNo
  683. }
  684. self.send_mqtt(data)
  685. @property
  686. def isHaveStopEvent(self):
  687. return True
  688. def pwd_cache_key(self):
  689. return 'sys_pwd_{}'.format(self.device.devNo)
  690. def _get_port_status(self):
  691. data = {
  692. 'fun_code': 2,
  693. 'all': True
  694. }
  695. data = self.send_mqtt(data)
  696. status = data.get('status')
  697. result = {}
  698. if status == 'fault':
  699. result[self.port] = {'status': Const.DEV_WORK_STATUS_FAULT, 'port': self.port}
  700. elif status == 'idle':
  701. result[self.port] = {'status': Const.DEV_WORK_STATUS_IDLE, 'port': self.port}
  702. elif status == 'link':
  703. result[self.port] = {'status': Const.DEV_WORK_STATUS_CONNECTED, 'port': self.port}
  704. elif status == 'estop':
  705. result[self.port] = {'status': Const.DEV_WORK_STATUS_ESTOP, 'port': self.port}
  706. elif status == 'ready':
  707. result[self.port] = {'status': Const.DEV_WORK_STATUS_READY, 'port': self.port}
  708. elif status == 'busy':
  709. result[self.port] = {'status': Const.DEV_WORK_STATUS_WORKING, 'port': self.port}
  710. elif status == 'forbiden':
  711. result[self.port] = {'status': Const.DEV_WORK_STATUS_FORBIDDEN, 'port': self.port}
  712. else:
  713. result[self.port] = {'status': Const.DEV_WORK_STATUS_FAULT, 'port': self.port}
  714. Device.update_dev_control_cache(self.device['devNo'], result)
  715. return result
  716. def get_current_use(self, **kw):
  717. base_data = kw.get('base_data')
  718. spDict = kw.get('spDict')
  719. # sp = ServiceProgress.objects.filter(device_imei=self.device.devNo, weifuleOrderNo=spDict.get('weifuleOrderNo')).first()
  720. port = spDict.get('port')
  721. result_list = []
  722. # 订单信息组织
  723. _info = self.get_port_info(port)
  724. exec_task = _info.get('exec_orders', [])
  725. for task in exec_task:
  726. item = base_data
  727. if spDict['weifuleOrderNo'] != task['id']:
  728. continue
  729. # 启动方式
  730. if task['order_type'] == 'apps_start':
  731. consumeType = 'mobile'
  732. else:
  733. consumeType = 'card'
  734. item['cardNo'] = task['card_no']
  735. # 订单状态
  736. if task['status'] == 'running':
  737. # 设备参数
  738. item['voltage'] = _info.get('voltage', 0)
  739. item['power'] = _info.get('power', 0)
  740. item['ampere'] = _info.get('ampere', 0)
  741. # 时间
  742. item['elec'] = task['elec']
  743. # 电量
  744. item['usedTime'] = task['time']
  745. # 金额
  746. records = task['records']
  747. item['elecFee'] = round(sum(map(lambda _: _['elec_money'], records)) * 0.01, 2)
  748. item['serviceFee'] = round(sum(map(lambda _: _['serv_money'], records)) * 0.01, 2)
  749. item['consumeMoney'] = '{}{}'.format(item['elecFee'] + item['serviceFee'], self.show_pay_unit)
  750. # 订单内部信息
  751. item['order'] = {
  752. 'orderNo': task['id'], # 停止按钮传订单停单用
  753. 'coin': '{}{}'.format(task['amount'], self.show_pay_unit),
  754. 'consumeType': consumeType,
  755. }
  756. if 'card_no' in task:
  757. item['cardNo'] = task['card_no']
  758. elif task['status'] == 'waiting':
  759. item['desc'] = '此订单已经下发到设备上,上一单运行完毕就会自动运行此订单'
  760. item['order'] = {
  761. 'orderNo': task['id'], # 停止按钮传订单停单用
  762. 'coin': '{}{}'.format(task['amount'], self.show_pay_unit),
  763. 'consumeType': consumeType,
  764. }
  765. try:
  766. consumeRcd = ConsumeRecord.objects.filter(orderNo=task['id']).first()
  767. if consumeRcd and consumeRcd.attachParas.get('payAfterUse') == True:
  768. item['order'] = {
  769. 'orderNo': task['id'], # 停止按钮传订单停单用
  770. 'coin': '{}{}'.format(0, self.show_pay_unit),
  771. 'consumeType': 'postpaid',
  772. }
  773. item.pop('leftMoney', None)
  774. except:
  775. pass
  776. item.update(DeviceType.get_services_button(self.device['devType']['id']))
  777. result_list.append(item)
  778. if not result_list:
  779. ServiceProgress.objects.filter(device_imei=self.device.devNo,
  780. weifuleOrderNo=spDict.get('weifuleOrderNo')).update(
  781. isFinished=True,
  782. expireAt=datetime.datetime.now())
  783. ConsumeRecord.objects.filter(devNo=self.device.devNo, isNormal=True,
  784. orderNo=spDict.get('weifuleOrderNo')).update(isNormal=False,
  785. errorDesc='异常结束,设备订单丢失 code:4',
  786. finishedTime=datetime.datetime.now())
  787. return result_list
  788. @property
  789. def show_pay_unit(self):
  790. """
  791. 前台显示付费的时候,目前有不同的客户希望 显示不同的单位 有的显示金币 有的显示元, 这个地方处理下
  792. :return:
  793. """
  794. if self.device['otherConf'].get('pay_unit'):
  795. return self.device['otherConf'].get('pay_unit')
  796. return u'元'
  797. def dealer_get_port_status(self):
  798. """
  799. 远程上分的时候获取端口状态
  800. :return:
  801. """
  802. return self.get_port_status(force=True)
  803. def check_order_state(self, openId):
  804. dealerId = self.device.ownerId
  805. return ClientConsumeModelProxy.get_not_finished_record(ownerId=dealerId, openId=openId,
  806. devTypeCode=self._device['devType']['code'],
  807. attachParas__payAfterUse=True)
  808. def force_stop_order(self, order, **kwargs):
  809. if not order.attachParas.get('payAfterUse'):
  810. pass
  811. else:
  812. errorDesc = order.errorDesc + '经销商手动强制关单<{}>'.format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"))
  813. order.update(status='finished', errorDesc=errorDesc, isNormal=False)
  814. def get_policy_infos(self):
  815. data = {
  816. 'fun_code': 12,
  817. 'all': True,
  818. }
  819. data = self.send_mqtt(data)
  820. price = data.pop('prices')
  821. price_dict = self._transform_prices(price, 'get')
  822. return price_dict
  823. def set_policy_infos(self, payload):
  824. update_dict = {'fun_code': 11}
  825. if payload.get('price1'):
  826. prices = self._transform_prices(payload)
  827. update_dict.update({'prices': prices})
  828. return self.send_mqtt(update_dict)
  829. def get_policy_for_user(self):
  830. data = self._get_device_configs()
  831. if not data:
  832. self.get_dev_setting()
  833. data = self._get_device_configs()
  834. prices = data.get('prices')
  835. str_to_datetime = lambda _: datetime.datetime.strptime(_, "%H:%M")
  836. datetime_to_str = lambda _: _.strftime("%H:%M")
  837. # 用默认时间填满缝隙
  838. defaultElecPrice = 0.5
  839. defaultSevicePrice = 0.5
  840. time_points = []
  841. priceList = []
  842. for price in prices:
  843. if price[0] == 'default':
  844. defaultElecPrice = price[1]
  845. defaultSevicePrice = price[2]
  846. # priceList.append([to_datetime('00:00'), to_datetime('23:59'), defaultElecPrice, defaultSevicePrice])
  847. else:
  848. st_point = str_to_datetime(price[0].split('-')[0])
  849. ft_point = str_to_datetime(price[0].split('-')[1])
  850. time_points.extend([st_point, ft_point])
  851. priceList.append([st_point, ft_point, price[1], price[2]])
  852. dst_point = str_to_datetime('00:00')
  853. dft_point = str_to_datetime('23:59')
  854. dst_point not in time_points and time_points.append(dst_point)
  855. dft_point not in time_points and time_points.append(dft_point)
  856. time_points = sorted(time_points)
  857. resultList = []
  858. for point in time_points:
  859. if point == dft_point:
  860. break
  861. price_model = None
  862. for price in priceList:
  863. if point == price[0]:
  864. price_model = price
  865. break
  866. if price_model:
  867. resultList.append(
  868. {"startTime": datetime_to_str(price_model[0]), "elecPrice": price_model[2],
  869. "sevicePrice": price_model[3]})
  870. else:
  871. resultList.append(
  872. {"startTime": datetime_to_str(point), "elecPrice": defaultElecPrice,
  873. "sevicePrice": defaultSevicePrice})
  874. return resultList
  875. def get_customize_score_unit(self):
  876. return u'元'
  877. def start_customize_point(self, pointNum, openId, port):
  878. package = {'name': 'customizePoint', 'price': pointNum, 'coins': pointNum, 'unit': u'次', 'time': 1}
  879. attachParas = {'chargeIndex': port, 'onPoints': True}
  880. return self.start_device(package, openId, attachParas)
  881. def support_device_package(self):
  882. return True
  883. def format_device_package(self, isTemp=False, **kw):
  884. def __generate_id(ids):
  885. i = 1
  886. while True:
  887. if str(i) in ids:
  888. i += 1
  889. else:
  890. return str(i)
  891. def __formart_ruleList():
  892. packageList = kw['serviceData']
  893. ids = [str(rule['id']) for rule in packageList if 'id' in rule]
  894. washConfig = {}
  895. for i, rule in enumerate(packageList):
  896. ruleId = str(rule.get('id', ''))
  897. if not ruleId:
  898. ruleId = __generate_id(ids)
  899. ids.append(ruleId)
  900. washConfig[ruleId] = {}
  901. if 'switch' in rule:
  902. washConfig[ruleId].update({'switch': rule['switch']})
  903. if 'billingMethod' in rule:
  904. washConfig[ruleId].update({'billingMethod': rule['billingMethod']})
  905. if 'price' in rule:
  906. washConfig[ruleId].update(
  907. {'price': round(float(rule['price']), 2) or 0, 'coins': round(float(rule['price']), 2) or 0})
  908. # if 'time' in rule:
  909. # washConfig[ruleId].update({'time': rule['time'] or 0})
  910. if 'name' in rule:
  911. washConfig[ruleId].update({'name': rule['name'] or '套餐{}'.format(i + 1)})
  912. if 'unit' in rule:
  913. washConfig[ruleId].update({'unit': rule['unit']})
  914. if 'sn' in rule:
  915. washConfig[ruleId].update({'sn': rule['sn']})
  916. if 'autoStop' in rule:
  917. washConfig[ruleId]['autoStop'] = rule['autoStop']
  918. if 'autoRefund' in rule:
  919. washConfig[ruleId]['autoRefund'] = rule['autoRefund']
  920. if 'minAfterStartCoins' in rule:
  921. washConfig[ruleId]['minAfterStartCoins'] = rule['minAfterStartCoins']
  922. if 'minFee' in rule:
  923. washConfig[ruleId]['minFee'] = rule['minFee']
  924. if isTemp:
  925. pass
  926. # 检验部分
  927. if RMB(rule.get('price') or 0) > self.device.owner.maxPackagePrice:
  928. raise ServiceException(
  929. {'result': 0, 'description': '套餐( {} )金额超限'.format(rule['name']), 'payload': {}})
  930. return washConfig
  931. def __formart_displaySwitchs():
  932. return {'displayCoinsSwitch': False,
  933. 'displayTimeSwitch': False,
  934. 'displayPriceSwitch': True,
  935. 'setPulseAble': False,
  936. 'setBasePriceAble': False}
  937. washConfig = __formart_ruleList()
  938. displaySwitchs = __formart_displaySwitchs()
  939. return washConfig, displaySwitchs
  940. def dealer_show_package(self, isTemp=False, **kw):
  941. def get_rule_list():
  942. if isTemp:
  943. config = self.device.get('tempWashConfig', {})
  944. else:
  945. config = self.device['washConfig']
  946. ruleList = []
  947. for packageId, rule in config.items():
  948. item = {
  949. 'id': packageId
  950. }
  951. if 'switch' in rule:
  952. item['switch'] = rule['switch']
  953. if 'name' in rule:
  954. item['name'] = rule['name']
  955. if 'coins' in rule:
  956. item['coins'] = rule['coins']
  957. if 'price' in rule:
  958. item['price'] = rule['price']
  959. if 'time' in rule:
  960. item['time'] = rule['time']
  961. if 'description' in rule:
  962. item['description'] = rule['description']
  963. if 'unit' in rule:
  964. item['unit'] = rule['unit']
  965. if 'imgList' in rule:
  966. item['imgList'] = rule['imgList']
  967. if 'sn' in rule:
  968. item['sn'] = rule['sn']
  969. if 'autoStop' in rule:
  970. item['autoStop'] = rule['autoStop']
  971. if 'minAfterStartCoins' in rule:
  972. item['minAfterStartCoins'] = rule['minAfterStartCoins']
  973. if 'minFee' in rule:
  974. item['minFee'] = rule['minFee']
  975. ruleList.append(item)
  976. return sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id')))
  977. def get_display_switchs():
  978. if "displaySwitchs" in self.device["otherConf"]:
  979. displaySwitchs = self.device["otherConf"].get('displaySwitchs')
  980. else:
  981. displaySwitchs = {'displayCoinsSwitch': False,
  982. 'displayTimeSwitch': False,
  983. 'displayPriceSwitch': True,
  984. "setPulseAble": False,
  985. "setBasePriceAble": False}
  986. return displaySwitchs
  987. ruleList = get_rule_list()
  988. displaySwitchs = get_display_switchs()
  989. return {"ruleList": ruleList, 'displaySwitchs': displaySwitchs}
  990. def custom_push_url(self, order, user, **kw):
  991. from apps.web.utils import concat_user_center_entry_url
  992. from apps.web.utils import concat_front_end_url
  993. return concat_user_center_entry_url(agentId=user.productAgentId, redirect=concat_front_end_url(
  994. uri='/user/index.html#/user/deviceStatus'))