weifule_car_21kw.py 42 KB

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