dianchuan_ronghe.py 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116
  1. # -*- coding: utf-8 -*-
  2. # !/usr/bin/env python
  3. import datetime
  4. import logging
  5. import time
  6. from decimal import Decimal
  7. from typing import TYPE_CHECKING
  8. from apilib.utils import is_number
  9. from apilib.monetary import RMB
  10. from apilib.utils_string import split_str
  11. from apps.web.constant import Const, DeviceCmdCode, ErrorCode, DeviceErrorCodeDesc, MQTT_TIMEOUT, CONSUMETYPE
  12. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte, make_six_bytes_session_id, make_dianchuan_order_no, \
  13. asc_to_string, hexbyte_2_bin, reverse_hex
  14. from apps.web.core.exceptions import ServiceException, InvalidParameter
  15. from apps.web.core.networking import MessageSender
  16. from apps.web.device.models import Device, DeviceType
  17. from apps.web.south_intf.yuhuan_fire import YuhuanNorther
  18. from apilib.utils_datetime import to_datetime
  19. logger = logging.getLogger(__name__)
  20. if TYPE_CHECKING:
  21. from apps.web.device.models import GroupDict
  22. class ChargingRongheBox(SmartBox):
  23. def __init__(self, device):
  24. super(ChargingRongheBox, self).__init__(device)
  25. def _check_package(self, package):
  26. """
  27. 获取设备启动的发送数据 根据设备的当前模式以及套餐获取
  28. :param package:
  29. :return:
  30. """
  31. unit = package.get("unit", u"分钟")
  32. _time = float(package.get("time", 0))
  33. # 按时间计费
  34. if unit == u"小时":
  35. _time = _time * 60
  36. billingType = "time"
  37. elif unit == u"天":
  38. _time = _time * 24 * 60
  39. billingType = "time"
  40. elif unit == u"秒":
  41. _time = _time / 60
  42. billingType = "time"
  43. elif unit == u"分钟":
  44. _time = _time
  45. billingType = "time"
  46. elif unit == u'度':
  47. _time = _time * 1000
  48. billingType = "elec"
  49. else:
  50. raise ServiceException({"result": 2, "description": u"套餐单位错误,请联系经销商"})
  51. return _time, unit, billingType
  52. def _check_feedback_result(self, cmd, devInfo):
  53. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  54. if devInfo['rst'] == -1:
  55. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  56. elif devInfo['rst'] == 1:
  57. raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  58. if not devInfo.has_key('data'):
  59. return
  60. def translate_funcode(self, funCode):
  61. funCodeDict = {
  62. 'A2': u'远程控制',
  63. 'A9': u'对时请求应答',
  64. 'B0': u'平台读取充电桩所有端口状态',
  65. 'B2': u'平台读取充电桩某一端口状态',
  66. 'B7': u'远程启动',
  67. 'B9': u'远程停止',
  68. 'C3': u'设置本地参数配置表',
  69. 'C5': u'读取本地参数表',
  70. }
  71. return funCodeDict.get(funCode, '')
  72. def translate_event_cmdcode(self, cmdCode):
  73. cmdDict = {
  74. 'A0': u'向平台上传主板模块信息',
  75. 'A8': u'对时请求',
  76. 'B4': u'本地启动上报',
  77. 'B6': u'本地在线卡刷卡上报',
  78. 'BB': u'订单结束上报',
  79. 'C0': u'本地故障、传感器上报',
  80. 'C2': u'本地充电分档上报',
  81. 'C7': u'获取平台参数配置表',
  82. }
  83. return cmdDict.get(cmdCode, '')
  84. def is_port_can_use(self, port, canAdd=False):
  85. # 电川的在启动的时候去判断是否需要续充
  86. return True, ''
  87. def check_dev_status(self, attachParas=None):
  88. """
  89. 如果超过两个心跳周期没有报心跳,并且最后一次更新时间在2个小时内,需要从设备获取状态
  90. 否则以缓存状态为准。
  91. :param attachParas:
  92. :return:
  93. """
  94. if attachParas is None:
  95. raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口、电池类型信息'})
  96. if not attachParas.has_key('chargeIndex'):
  97. raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口'})
  98. if not self.device.need_fetch_online:
  99. raise ServiceException(
  100. {'result': 2, 'description': DeviceErrorCodeDesc.get(ErrorCode.DEVICE_CONN_CHECK_FAIL)})
  101. self.get_port_status_from_dev()
  102. group = self.device.group # type: GroupDict
  103. if group.is_free:
  104. logger.debug('{} is free. no need to check continue pay.'.format(repr(self.device)))
  105. return
  106. # 处理是否能够续充
  107. portDict = self.get_port_status()
  108. port = str(attachParas['chargeIndex'])
  109. if port in portDict:
  110. isCanAdd = self.device['devType'].get('payableWhileBusy', False)
  111. if portDict[port]['status'] == Const.DEV_WORK_STATUS_IDLE:
  112. return
  113. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FAULT:
  114. raise ServiceException({'result': 0, 'description': u'该端口故障,暂时不能使用'})
  115. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_WORKING:
  116. if isCanAdd:
  117. return
  118. else:
  119. raise ServiceException({'result': 0, 'description': u'该端口正在工作不能使用,请您使用其他端口'})
  120. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  121. raise ServiceException({'result': 0, 'description': u'该端口已被禁止使用,请您使用其他端口'})
  122. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_CONNECTED:
  123. return
  124. else:
  125. raise ServiceException({'result': 0, 'description': u'端口状态未知,暂时不能使用'})
  126. else:
  127. raise ServiceException({'result': 0, 'description': u'未知端口,暂时不能使用'})
  128. def test(self, coins):
  129. hexPort = fill_2_hexByte(hex(int(1)), 2)
  130. orderNo = make_dianchuan_order_no(self._device['devNo'])
  131. data = hexPort + orderNo[-16::] + '00' + '02' + '0100' + '00000000' + '0000'
  132. devInfo = self.remote_start_charge(1, data)
  133. return devInfo
  134. def port_is_busy(self, port_dict):
  135. if not port_dict:
  136. return False
  137. if 'billingType' not in port_dict:
  138. return False
  139. if 'status' not in port_dict:
  140. return False
  141. if 'coins' not in port_dict:
  142. return False
  143. if 'price' not in port_dict:
  144. return False
  145. billingType = port_dict['billingType']
  146. if billingType not in ['time', 'elec']:
  147. return False
  148. if billingType == 'time':
  149. if 'needTime' not in port_dict:
  150. return False
  151. else:
  152. if 'needElec' not in port_dict:
  153. return False
  154. if port_dict['status'] == Const.DEV_WORK_STATUS_WORKING:
  155. return True
  156. else:
  157. return False
  158. # 远程启动充电
  159. def remote_start_charge(self, port, data):
  160. devInfo = MessageSender.send(
  161. device=self.device,
  162. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  163. payload={
  164. 'IMEI': self._device['devNo'],
  165. "funCode": 'B7',
  166. 'data': data
  167. }, timeout=MQTT_TIMEOUT.START_DEVICE)
  168. if 'rst' not in devInfo:
  169. raise ServiceException({'result': 2, 'description': u'启动设备失败,您的支付金额已经退还,请重新扫码设备试试(1001)'})
  170. if devInfo['rst'] != 0:
  171. if devInfo['rst'] == -1:
  172. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦'})
  173. elif devInfo['rst'] == 1:
  174. self.check_serial_port_for_startcmd(port)
  175. else:
  176. raise ServiceException({'result': 2, 'description': u'启动设备失败,您的支付金额已经退回,请重新扫码设备({})'.format(devInfo['rst'])})
  177. else:
  178. if 'data' not in devInfo:
  179. logger.warning('no data in success response. result = {}'.format(str(devInfo)))
  180. raise ServiceException({'result': 2, 'description': u'启动设备失败,您的支付金额已经退回,请重试'})
  181. else:
  182. data = devInfo['data'][18::]
  183. result = data[0:2]
  184. if result == '00': # 成功
  185. pass
  186. elif result == '01':
  187. newValue = {str(port): {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'端口故障'}}
  188. Device.update_dev_control_cache(self._device['devNo'], newValue)
  189. raise ServiceException({'result': 2, 'description': u'端口故障,请您换一个插座或者设备,或者联系售后'})
  190. elif result == '02':
  191. raise ServiceException({'result': 2, 'description': u'充电类型或者消费类型不一致'})
  192. elif result == '03':
  193. raise ServiceException({'result': 2, 'description': u'无此端口'})
  194. else:
  195. raise ServiceException({
  196. 'result': 2,
  197. 'description': u'启动设备失败({}),您的支付金额已经退回,请重新扫码设备'.format(result)
  198. })
  199. return devInfo
  200. def start_device(self, package, openId, attachParas):
  201. if attachParas is None:
  202. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  203. if not attachParas.has_key('chargeIndex'):
  204. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  205. price = float(package['price'])
  206. port = int(attachParas['chargeIndex'])
  207. hexPort = fill_2_hexByte(hex(port), 2)
  208. _time, unit, billingType = self._check_package(package)
  209. hexBillingType = '00' if billingType == 'time' else '01'
  210. coins = float(package['coins'])
  211. hexTime = fill_2_hexByte(hex(int(_time)), 4, True)
  212. onPoints = attachParas.get('onPoints')
  213. if onPoints: # 远程上分
  214. orderNo = make_dianchuan_order_no(self._device['devNo'])
  215. logger.info('dealer onPoints package<{}> order<{}>'.format(package, orderNo))
  216. else:
  217. orderNo = str(attachParas.get('orderNo'))
  218. data = hexPort + orderNo[-16::] + hexBillingType + '02' + hexTime + '00000000' + '0000'
  219. devInfo = self.remote_start_charge(port, data)
  220. portDict = {
  221. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  222. 'status': Const.DEV_WORK_STATUS_WORKING,
  223. 'coins': coins,
  224. 'price': price,
  225. 'billingType': billingType,
  226. 'openId': openId,
  227. 'vCardId': self._vcard_id,
  228. 'payInfo': list()
  229. }
  230. ctrInfo = Device.get_dev_control_cache(self._device.devNo)
  231. lastPortInfo = ctrInfo.get(str(port), {})
  232. if self.port_is_busy(lastPortInfo) and \
  233. lastPortInfo.get('billingType') == billingType and \
  234. lastPortInfo.get('openId') == openId:
  235. is_continus = True
  236. portDict['coins'] = float(coins) + lastPortInfo['coins']
  237. portDict['price'] = float(price) + lastPortInfo['price']
  238. else:
  239. is_continus = False
  240. portDict['coins'] = float(coins)
  241. portDict['price'] = float(price)
  242. if attachParas.get('redpackId'):
  243. if is_continus:
  244. redpackInfo = lastPortInfo.get("redpackInfo", list())
  245. if not redpackInfo:
  246. logger.warning("miss redpackInfo! {}-{}".format(self._device["devNo"], port))
  247. else:
  248. redpackInfo = list()
  249. redpackInfo.append({'redpackId': str(attachParas['redpackId'])})
  250. portDict['redpackInfo'] = redpackInfo
  251. else:
  252. if is_continus:
  253. portDict['redpackInfo'] = lastPortInfo.get("redpackInfo", list())
  254. else:
  255. portDict['redpackInfo'] = list()
  256. if 'linkedRechargeRecordId' in attachParas and attachParas.get('isQuickPay', False):
  257. if is_continus:
  258. payInfo = lastPortInfo.get("payInfo", list())
  259. if not payInfo:
  260. logger.warning("miss payInfo! {}-{}".format(self._device["devNo"], port))
  261. else:
  262. payInfo = list()
  263. payInfo.append({'rechargeRcdId': str(attachParas['linkedRechargeRecordId'])})
  264. portDict['payInfo'] = payInfo
  265. else:
  266. if is_continus:
  267. portDict['payInfo'] = lastPortInfo.get("payInfo", list())
  268. else:
  269. portDict['payInfo'] = list()
  270. if billingType == 'time':
  271. if is_continus:
  272. portDict['needTime'] = _time + lastPortInfo['needTime']
  273. else:
  274. portDict['needTime'] = _time
  275. finishedTime = int(time.time()) + int(portDict['needTime'] * 60)
  276. else:
  277. if is_continus:
  278. portDict['needElec'] = _time / 1000.0 + lastPortInfo['needElec']
  279. else:
  280. portDict['needElec'] = _time / 1000.0
  281. finishedTime = int(time.time()) + 60 * 60 * 12
  282. portDict.update({'finishedTime': finishedTime})
  283. if 'orderNo' in attachParas:
  284. portDict.update({'orderNo': attachParas['orderNo']})
  285. Device.update_dev_control_cache(
  286. self._device['devNo'],
  287. {
  288. str(port): portDict
  289. })
  290. devInfo['finishedTime'] = finishedTime
  291. return devInfo
  292. def analyze_event_data(self, data):
  293. cmdCode = data[4:6]
  294. if cmdCode == 'A0': # 启动上报主板信息
  295. boardNo = data[18:34]
  296. hardVersion = asc_to_string(data[34:40])
  297. softId = asc_to_string(data[40:56])
  298. softVersion = int(data[56:60], 16)
  299. return {'cmdCode':cmdCode, 'boardNo':boardNo, 'hardVersion':hardVersion, 'softId':softId, 'softVersion':softVersion}
  300. elif cmdCode == 'A8':
  301. return {'cmdCode':cmdCode}
  302. elif cmdCode == 'B1': # 端口状态
  303. portNum = int(data[26:28], 16)
  304. nextData = data[(28 + 2 * portNum)::]
  305. chargedPortNum = int(nextData[0:2])
  306. result = {'cmdCode':cmdCode}
  307. portDict = {}
  308. for ii in range(chargedPortNum):
  309. portData = nextData[2 + 26 * ii:2 + 26 * ii + 26]
  310. port = int(portData[0:2], 16)
  311. power = int(reverse_hex(portData[22:26]), 16) / 10.0
  312. portDict.update({str(port):power})
  313. result.update({'portDict':portDict})
  314. return result
  315. elif cmdCode == 'B4': # 本地开始充电上报平台
  316. port = int(data[18:20], 16)
  317. status = int(data[20:22], 16)
  318. orderNo = self._device['devNo'] + data[22:38]
  319. startTime = to_datetime('20' + data[38:50], '%Y%m%d%H%M%S').strftime('%Y-%m-%d %H:%M:%S')
  320. leftMinute = int(reverse_hex(data[50:54]), 16)
  321. leftSecond = int(data[54:56], 16)
  322. leftTime = leftMinute * 60 + leftSecond
  323. chargeType = int(data[56:58], 16)
  324. durationMinute = int(reverse_hex(data[58:62]), 16)
  325. durationSecond = int(data[62:64], 16)
  326. duration = durationMinute * 60 + durationSecond
  327. consumeType = int(data[64:66], 16)
  328. leftElec = int(reverse_hex(data[66:70]), 16) / 1000.0
  329. elec = int(reverse_hex(data[70:74]), 16) / 1000.0
  330. gear = int(data[74:76], 16)
  331. chargedMoney = int(data[76:78], 16)
  332. cardNo = int(reverse_hex(data[78:86]), 16)
  333. return {'cmdCode': cmdCode, 'status': status, 'port': port, 'orderNo':orderNo, 'startTime':startTime,
  334. 'leftTime':leftTime, 'chargeType':chargeType, 'duration':duration, 'consumeType':consumeType, 'leftElec':leftElec,
  335. 'elec':elec, 'gear':gear, 'chargedMoney':chargedMoney, 'cardNo':cardNo}
  336. elif cmdCode == 'B6': # 本地刷在线卡上报平台
  337. port = int(data[18:20], 16)
  338. cardNo = int(reverse_hex(data[20:28]), 16)
  339. money = int(data[28:30], 16)
  340. return {'port': port, 'cardNo': cardNo, 'money': money, 'cardNoStr':data[20:28]}
  341. elif cmdCode == 'BB': # 充电订单
  342. port = int(data[20:22], 16)
  343. orderNo = self._device['devNo'] + data[22:38]
  344. startTime = to_datetime('20' + data[38:50], '%Y%m%d%H%M%S').strftime('%Y-%m-%d %H:%M:%S')
  345. endTime = data[50:62]
  346. leftMinute = int(reverse_hex(data[62:66]), 16)
  347. leftSecond = int(data[66:68], 16)
  348. leftTime = leftMinute * 60 + leftSecond
  349. chargeType = int(data[68:70], 16)
  350. durationMinute = int(reverse_hex(data[70:74]), 16)
  351. durationSecond = int(data[74:76], 16)
  352. duration = durationMinute * 60 + durationSecond
  353. consumeType = int(data[76:78], 16)
  354. leftElec = int(reverse_hex(data[78:82]), 16) / 1000.0
  355. elec = int(reverse_hex(data[82:86]), 16) / 1000.0
  356. cardNo = int(reverse_hex(data[86:94]), 16)
  357. chargedMoney = int(reverse_hex(data[94:98]), 16) / 100.0
  358. reasonDict = {'0':u'时间用完', '1':u'移除充电器', '2':u'充满自停', '3':u'故障停止', '4':u'功率过大停止',
  359. '5':u'离线卡退费停止', '6':u'启动充电未连接,充电器停止', '7':u'远程停止', '10':u'电量用完'}
  360. reason = int(data[98:100], 16)
  361. return {'cmdCode':cmdCode, 'port': port, 'orderNo': orderNo, 'startTime': startTime, 'endTime':endTime,
  362. 'leftTime':leftTime, 'chargeType':chargeType, 'duration':duration, 'consumeType':consumeType,
  363. 'leftElec':leftElec, 'elec':elec, 'cardNo':cardNo, 'chargedMoney':chargedMoney,
  364. 'reasonCode':reason, 'reason':reasonDict.get(str(reason), ''), 'uartData':data}
  365. elif cmdCode == 'C0': # 本地故障报警
  366. port = int(data[18:20], 16)
  367. alarmType = int(data[20:22], 16)
  368. temperature = int(data[22:24], 16)
  369. voltage = int(reverse_hex(data[24:28]), 16) / 10.0
  370. infoDict = {'03':u'输出故障', '04':u'粘连故障', 'AA':u'温度高', 'BB':u'烟雾告警', 'CC':u'输入电压异常'}
  371. statusInfo = infoDict.get(data[20:22], '')
  372. return {'cmdCode': cmdCode, 'port': port, 'alarmType':alarmType, 'temperature':temperature,
  373. 'voltage':voltage, 'statusInfo':statusInfo, 'uart':data, 'FaultCode':alarmType}
  374. elif cmdCode == 'C2': # 充电桩充电过程中发送分档上报平台
  375. port = int(data[18:20], 16)
  376. timeBeforeGeared = int(reverse_hex(data[20:24]), 16)
  377. gearBeforeGeared = int(data[24:26], 16)
  378. timeAfterGeared = int(reverse_hex(data[26:30]), 16)
  379. gearAfterGeared = int(data[30:32], 16)
  380. gear = int(reverse_hex(data[32:36]), 16)
  381. return {'cmdCode': cmdCode, 'port': port, 'timeBeforeGeared': timeBeforeGeared, 'gearBeforeGeared': gearBeforeGeared, 'timeAfterGeared': timeAfterGeared,
  382. 'gearAfterGeared':gearAfterGeared, 'gear':gear}
  383. elif cmdCode == 'C7':
  384. return {'cmdCode':cmdCode}
  385. return None
  386. def get_dev_consume_count(self):
  387. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  388. {'IMEI': self._device['devNo'], "funCode": '07', 'data': '00'})
  389. self._check_feedback_result('07', devInfo)
  390. data = devInfo['data'][18::]
  391. cardFee = int(data[2:6], 16) / 10.0 # 以角为单位
  392. coinFee = int(data[6:10], 16) # 以元为单位
  393. return {'cardFee': cardFee, 'coinFee': coinFee}
  394. def get_port_info(self, line):
  395. support_06 = self._device.get('otherConf', {}).get('support_06', True)
  396. if not support_06:
  397. return {'port': line}
  398. data = fill_2_hexByte(hex(int(line)), 2)
  399. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  400. {'IMEI': self._device['devNo'], "funCode": 'B2', 'data': data})
  401. self._check_feedback_result('B2', devInfo)
  402. data = devInfo['data']
  403. port = int(data[18:20], 16)
  404. status = int(data[20:22], 16)
  405. orderNo = self._device['devNo'] + data[22:38]
  406. startTime = to_datetime('20' + data[38:50], '%Y%m%d%H%M%S').strftime('%Y-%m-%d %H:%M:%S')
  407. leftMinute = int(reverse_hex(data[50:54]), 16)
  408. leftSecond = int(data[54:56], 16)
  409. leftTime = leftMinute * 60 + leftSecond
  410. chargeType = int(data[56:58], 16)
  411. durationMinute = int(reverse_hex(data[58:62]), 16)
  412. durationSecond = int(data[62:64], 16)
  413. duration = durationMinute * 60 + durationSecond
  414. consumeType = int(data[64:66], 16)
  415. leftElec = int(reverse_hex(data[66:70]), 16) / 1000.0
  416. elec = int(reverse_hex(data[70:74]), 16) / 1000.0
  417. power = int(reverse_hex(data[74:78]), 16) / 10.0
  418. gear = int(data[78:80], 16)
  419. chargedMoney = int(data[80:82], 16)
  420. cardNo = int(reverse_hex(data[82:90]), 16)
  421. statusDict = {'0':Const.DEV_WORK_STATUS_IDLE, '1':Const.DEV_WORK_STATUS_WORKING, '3':Const.DEV_WORK_STATUS_FAULT, '4':Const.DEV_WORK_STATUS_FAULT_RELAY_CONNECT, '255':Const.DEV_WORK_STATUS_FAULT}
  422. statusDesc = {'3':u'充电故障', '4':u'继电器粘连', '255':u'无此端口'}
  423. if status in [3, 4, 255]: # 故障情况下,直接返回
  424. return {'port':port, 'status':statusDict.get(str(status), Const.DEV_WORK_STATUS_FAULT), 'reason':statusDesc.get(str(status), '')}
  425. elif status == 0: # 空闲也直接返回
  426. return {'port':port, 'status':Const.DEV_WORK_STATUS_IDLE}
  427. result = {'port':port, 'status':Const.DEV_WORK_STATUS_WORKING, 'orderNo':orderNo, 'startTime':startTime, 'usedTime':round(duration / 60.0, 2), 'power':power, 'gear':gear}
  428. # 充电的时候,根据不同类型,返回不同的数据
  429. if chargeType == 0:
  430. result.update({'leftTime':round(leftTime / 60.0, 2)}) # 界面显示的是分钟,这里需要转化单位
  431. else:
  432. result.update({'leftElec':leftElec})
  433. result.update({'elec':elec})
  434. consumeTypeDict = {'0':'coin', '1':'card', '2':'mobile', '3':'card', '4':'free'}
  435. portCache = Device.get_dev_control_cache(self._device['devNo']).get(str(port))
  436. if str(consumeType) != '2':
  437. result.update({'consumeType':consumeTypeDict.get(str(consumeType))})
  438. else:
  439. if portCache['vCardId']:
  440. result.update({'consumeType':'mobile_vcard'})
  441. else:
  442. result.update({'consumeType':'mobile'})
  443. if consumeType in [0, 1]: # 投币和离线卡
  444. result.update({'chargedMoney':chargedMoney})
  445. if consumeType in [1, 3]:
  446. result.update({'cardNo':cardNo})
  447. return result
  448. # 访问设备,获取设备端口信息
  449. def get_port_status_from_dev(self):
  450. devInfo = MessageSender.send(device=self.device,
  451. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  452. payload={
  453. 'IMEI': self._device['devNo'],
  454. 'funCode': 'B0',
  455. 'data': '00'
  456. })
  457. self._check_feedback_result('B0', devInfo)
  458. data = devInfo['data'][18::]
  459. result = {}
  460. portNum = int(data[8:10], 16)
  461. portData = data[10::]
  462. ii = 0
  463. while ii < portNum:
  464. statusTemp = portData[ii * 2:ii * 2 + 2]
  465. if statusTemp == '00':
  466. status = {'status': Const.DEV_WORK_STATUS_IDLE}
  467. elif statusTemp == '01':
  468. status = {'status': Const.DEV_WORK_STATUS_WORKING}
  469. elif statusTemp == '03':
  470. status = {'status': Const.DEV_WORK_STATUS_FAULT}
  471. elif statusTemp == '04':
  472. status = {'status': Const.DEV_WORK_STATUS_FAULT_RELAY_CONNECT}
  473. # 不再上述状态之列的 统一为故障状态
  474. else:
  475. status = {'status': Const.DEV_WORK_STATUS_FAULT}
  476. ii += 1
  477. result[str(ii)] = status
  478. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  479. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  480. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  481. for strPort, info in result.items():
  482. if ctrInfo.has_key(strPort):
  483. if info['status'] == Const.DEV_WORK_STATUS_WORKING:
  484. ctrInfo[strPort].update({'status': info['status']})
  485. else:
  486. ctrInfo[strPort] = info
  487. else:
  488. ctrInfo[strPort] = info
  489. ctrInfo.update({
  490. 'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts
  491. })
  492. Device.update_dev_control_cache(self.device.devNo, ctrInfo)
  493. return result
  494. def get_default_port_nums(self):
  495. default_num = 10
  496. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_DIANCHUAN_HIGH:
  497. default_num = 2
  498. return default_num
  499. def get_port_status(self, force=False):
  500. if force:
  501. return self.get_port_status_from_dev()
  502. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  503. if 'allPorts' in ctrInfo and ctrInfo['allPorts'] > 0:
  504. allPorts = ctrInfo['allPorts']
  505. else:
  506. allPorts = self.get_default_port_nums()
  507. statusDict = {}
  508. for ii in range(allPorts):
  509. tempDict = ctrInfo.get(str(ii + 1), {})
  510. if tempDict.has_key('status'):
  511. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  512. elif tempDict.has_key('isStart'):
  513. if tempDict['isStart']:
  514. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  515. else:
  516. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  517. else:
  518. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  519. return statusDict
  520. def lock_unlock_port(self, port, lock=True):
  521. if lock:
  522. Device.update_dev_control_cache(self._device['devNo'],
  523. {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  524. else:
  525. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  526. def active_deactive_port(self, port, active):
  527. if active:
  528. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  529. self.stop_charging_port(port)
  530. devInfo = Device.get_dev_control_cache(self._device['devNo'])
  531. portCtrInfo = devInfo.get(str(port), {})
  532. portCtrInfo.update({'isStart': False, 'status': Const.DEV_WORK_STATUS_IDLE, 'needTime': 0, 'leftTime': 0,
  533. 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  534. newValue = {str(port): portCtrInfo}
  535. Device.update_dev_control_cache(self._device['devNo'], newValue)
  536. def stop_charging_port(self, port):
  537. portStr = fill_2_hexByte(hex(int(port)), 2)
  538. devInfo = MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  539. payload={'IMEI': self._device['devNo'], "funCode": 'B9', 'data': portStr},
  540. timeout=MQTT_TIMEOUT.SHORT)
  541. self._check_feedback_result('B9', devInfo)
  542. return {"port": int(devInfo['data'][18:20], 16)}
  543. def stop(self, port=None):
  544. return self.stop_charging_port(port)
  545. @property
  546. def isHaveStopEvent(self):
  547. return True
  548. def get_dev_all_settings(self):
  549. devInfo = MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, payload={
  550. "IMEI": self._device["devNo"],
  551. "funCode": "C5",
  552. "data": "00",
  553. }, timeout=MQTT_TIMEOUT.SHORT)
  554. self._check_feedback_result('C5', devInfo)
  555. data = devInfo['data'][18::]
  556. resultDict = {
  557. "runMode": int(data[0:2], 16),
  558. "voice": int(data[2:4], 16),
  559. "coinTime": int(reverse_hex(data[4:8]), 16),
  560. "cardTime": int(reverse_hex(data[8:12]), 16),
  561. "icMoney": int(data[12:14], 16) / 10.0,
  562. "cardRefund": '1',#str(int(data[14:16], 16)),
  563. "power1": int(reverse_hex(data[16:20]), 16) / 10.0,
  564. "power2": int(reverse_hex(data[20:24]), 16) / 10.0,
  565. "power3": int(reverse_hex(data[24:28]), 16) / 10.0,
  566. "power4": int(reverse_hex(data[28:32]), 16) / 10.0,
  567. "power5": int(reverse_hex(data[32:36]), 16) / 10.0,
  568. "power1ratio": 100,
  569. "power2ratio": int(data[38:40], 16),
  570. "power3ratio": int(data[40:42], 16),
  571. "power4ratio": int(data[42:44], 16),
  572. "power5ratio": int(data[44:46], 16),
  573. "autoStop":str(int(data[46:48], 16)),
  574. "fuchongPower": int(reverse_hex(data[48:52]), 16) /10.0,
  575. "fuchongTime": int(int(reverse_hex(data[52:56]), 16) / 60.0),
  576. "noPowerTime": int(int(reverse_hex(data[56:60]), 16) / 60.0),
  577. "password": int(reverse_hex(data[60:64]), 16),
  578. "temperature": int(data[64:66], 16),
  579. }
  580. return resultDict
  581. def reply_C7(self):
  582. devObj = Device.objects.get(devNo=self._device['devNo'])
  583. setConf = devObj.otherConf
  584. data = ''
  585. data += fill_2_hexByte(hex(int(setConf.get('runMode'))), 2)
  586. data += fill_2_hexByte(hex(int(setConf.get('voice'))), 2)
  587. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('coinTime'))), 4))
  588. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('cardTime'))), 4))
  589. data += fill_2_hexByte(hex(int(setConf.get('icMoney'))), 2)
  590. data += fill_2_hexByte(hex(int(setConf.get('cardRefund'))), 2)
  591. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power1'))), 4))
  592. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power2'))), 4))
  593. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power3'))), 4))
  594. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power4'))), 4))
  595. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power5'))), 4))
  596. data += '64'
  597. data += fill_2_hexByte(hex(int(setConf.get('power2ratio'))), 2)
  598. data += fill_2_hexByte(hex(int(setConf.get('power3ratio'))), 2)
  599. data += fill_2_hexByte(hex(int(setConf.get('power4ratio'))), 2)
  600. data += fill_2_hexByte(hex(int(setConf.get('power5ratio'))), 2)
  601. data += fill_2_hexByte(hex(int(setConf.get('autoStop'))), 2)
  602. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('fuchongPower'))), 4))
  603. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('fuchongTime'))), 4))
  604. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('noPowerTime'))), 4))
  605. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('password'))), 4))
  606. data += fill_2_hexByte(hex(int(setConf.get('temperature'))), 2)
  607. data += '00000000000000'
  608. devInfo = MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, payload={
  609. "IMEI": self._device["devNo"],
  610. "funCode": "C3",
  611. "data": data,
  612. }, timeout=MQTT_TIMEOUT.SHORT)
  613. self._check_feedback_result('C3', devInfo)
  614. # 获取设备配置参数
  615. def get_dev_setting(self):
  616. result = self.get_dev_all_settings()
  617. otherConf = self._device.get("otherConf", dict())
  618. result.update({'cardFeeMode':otherConf.get('cardFeeMode', 'time')})
  619. result.update({'cardFeeMode':otherConf.get('cardFeeValue', 180)})
  620. devRcd = Device.get_collection().find({'devNo':self._device['devNo']})[0]
  621. result.update({'boardNo':devRcd.get('boardNo', '')})
  622. result.update({'hardVersion':devRcd.get('hardVersion', '')})
  623. result.update({'softId':devRcd.get('softId', '')})
  624. result.update({'softVersion':devRcd.get('softVersion', '')})
  625. return result
  626. # 获取设备配置参数
  627. def set_dev_setting(self, setConf):
  628. # 先保存到数据库中
  629. confDict = {
  630. 'runMode':int(setConf.get('runMode')), 'voice':int(setConf.get('voice')), 'coinTime':int(setConf.get('coinTime')),
  631. 'cardTime':int(setConf.get('cardTime')), 'icMoney':int(setConf.get('icMoney')), 'cardRefund':int(setConf.get('cardRefund')),
  632. 'power1':int(setConf.get('power1')), 'power2':int(setConf.get('power2')), 'power3':int(setConf.get('power3')), 'power4':int(setConf.get('power4')),
  633. 'power5':int(setConf.get('power5')), 'power1ratio':100, 'power2ratio':int(setConf.get('power2ratio')), 'power3ratio':int(setConf.get('power3ratio')),
  634. 'power4ratio':int(setConf.get('power4ratio')), 'power5ratio':int(setConf.get('power5ratio')), 'autoStop':int(setConf.get('autoStop')),
  635. 'fuchongPower':int(setConf.get('fuchongPower')), 'fuchongTime':int(setConf.get('fuchongTime')), 'noPowerTime':int(setConf.get('noPowerTime')), 'password':int(setConf.get('password')),
  636. 'temperature':int(setConf.get('temperature')), 'cardFeeMode':setConf.get('cardFeeMode', 'time'), 'cardFeeValue':setConf.get('cardFeeValue', 180)
  637. }
  638. devObj = Device.objects.get(devNo=self._device['devNo'])
  639. devObj.otherConf.update(confDict)
  640. devObj.save()
  641. data = ''
  642. data += fill_2_hexByte(hex(int(setConf.get('runMode'))), 2)
  643. data += fill_2_hexByte(hex(int(setConf.get('voice'))), 2)
  644. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('coinTime'))), 4))
  645. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('cardTime'))), 4))
  646. data += fill_2_hexByte(hex(int(setConf.get('icMoney'))), 2)
  647. data += fill_2_hexByte(hex(int(setConf.get('cardRefund'))), 2)
  648. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power1'))), 4))
  649. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power2'))), 4))
  650. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power3'))), 4))
  651. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power4'))), 4))
  652. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power5'))), 4))
  653. data += fill_2_hexByte(0x64, 2)
  654. data += fill_2_hexByte(hex(int(setConf.get('power2ratio'))), 2)
  655. data += fill_2_hexByte(hex(int(setConf.get('power3ratio'))), 2)
  656. data += fill_2_hexByte(hex(int(setConf.get('power4ratio'))), 2)
  657. data += fill_2_hexByte(hex(int(setConf.get('power5ratio'))), 2)
  658. data += fill_2_hexByte(hex(int(setConf.get('autoStop'))), 2)
  659. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('fuchongPower'))), 4))
  660. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('fuchongTime'))), 4))
  661. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('noPowerTime'))), 4))
  662. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('password'))), 4))
  663. data += fill_2_hexByte(hex(int(setConf.get('temperature'))), 2)
  664. data += '00000000000000'
  665. devInfo = MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, payload={
  666. "IMEI": self._device["devNo"],
  667. "funCode": "C3",
  668. "data": data,
  669. }, timeout=MQTT_TIMEOUT.SHORT)
  670. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  671. if devInfo['rst'] == -1:
  672. raise ServiceException({'result': 2, 'description': u'充电桩离线,配置信息没有下发到充电桩,设备重新上电上网后,会将配置下发到设备。建议您设备在线的时候配置'})
  673. elif devInfo['rst'] == 1:
  674. raise ServiceException({'result': 2, 'description': u'充电桩繁忙,配置信息没有下发到充电桩,设备重新上电上网后,会将配置下发到设备。建议您设备在线的时候配置'})
  675. ################ api相关接口
  676. def apiGetPortStatusFromDc(self, record):
  677. return self.get_port_status_from_dev()
  678. def apiGetDevSettingsFromDc(self, record):
  679. return self.get_dev_setting()
  680. def apisetDevSettingsFromDc(self, record):
  681. self.set_dev_setting(record)
  682. return {}
  683. def apiGetPortInfoFromDc(self, record):
  684. return self.get_port_info(record['port'])
  685. def apiStartDeviceForDc(self, record):
  686. coins = float(record['price'])
  687. port = hex(int(record['port']))
  688. data = ''
  689. data += fill_2_hexByte(port, 2)
  690. orderNo = make_dianchuan_order_no(self._device['devNo'])
  691. data += orderNo[-16::]
  692. data += '00' # 按时间方式充电
  693. data += '02' # 在线扫码方式
  694. data += reverse_hex(fill_2_hexByte(hex(int(record['time'])), 4))
  695. data += '00000000'
  696. data += '0000'
  697. devInfo = MessageSender.send(
  698. device=self.device,
  699. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  700. payload={
  701. 'IMEI': self._device['devNo'],
  702. "funCode": 'B7',
  703. 'data': data
  704. }, timeout=MQTT_TIMEOUT.START_DEVICE)
  705. usePort = int(record['port'])
  706. if 'rst' not in devInfo:
  707. raise ServiceException(
  708. {
  709. 'result': 2,
  710. 'description': u'启动设备失败,您的支付金额已经退还,请重新扫码设备试试(1001)'
  711. })
  712. if devInfo['rst'] != 0:
  713. if devInfo['rst'] == -1:
  714. raise ServiceException(
  715. {
  716. 'result': 2,
  717. 'description': u'充电桩正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦'
  718. })
  719. elif devInfo['rst'] == 1:
  720. raise ServiceException(
  721. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  722. else:
  723. raise ServiceException(
  724. {
  725. 'result': 2,
  726. 'description': u'启动设备失败,您的支付金额已经退回,请重新扫码设备({})'.format(devInfo['rst'])
  727. })
  728. portDict = {
  729. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  730. 'status': Const.DEV_WORK_STATUS_WORKING,
  731. 'coins': coins,
  732. 'price': coins,
  733. 'isApi': True
  734. }
  735. Device.update_dev_control_cache(
  736. self._device['devNo'],
  737. {
  738. str(usePort): portDict
  739. })
  740. return devInfo
  741. # 回复设备上报的设备基础信息
  742. def reply_A0(self):
  743. nowTime = datetime.datetime.now()
  744. year = nowTime.year - 2000
  745. strTime = str(year) + nowTime.strftime('%m%d%H%M%S')
  746. devInfo = MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, # 注意这个用OPERATE_DEV_SYNC,故意让服务器这边多等一会,等超时1分钟
  747. payload={'IMEI': self._device['devNo'], "funCode": 'A1', 'data': '00' + strTime},
  748. timeout=MQTT_TIMEOUT.SHORT)
  749. self._check_feedback_result('A1', devInfo)
  750. def control_device(self, controlType, IDSelect='00', newId='0000000000000000'):
  751. devInfo = MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  752. payload={'IMEI': self._device['devNo'], "funCode": 'A2', 'data': controlType + IDSelect + newId},
  753. timeout=MQTT_TIMEOUT.SHORT)
  754. self._check_feedback_result('A2', devInfo)
  755. # 回复对时请求
  756. def reply_A7(self):
  757. nowTime = datetime.datetime.now()
  758. year = nowTime.year - 2000
  759. strTime = str(year) + nowTime.strftime('%m%d%H%M%S')
  760. MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  761. payload={'IMEI': self._device['devNo'], "funCode": 'A9', 'data': strTime},
  762. timeout=MQTT_TIMEOUT.SHORT)
  763. # 回复本地充电上报
  764. def reply_B4(self, port):
  765. data = fill_2_hexByte(hex(int(port)), 2)
  766. MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  767. payload={'IMEI': self._device['devNo'], "funCode": 'B5', 'data': data},
  768. timeout=MQTT_TIMEOUT.SHORT)
  769. def reply_BB(self, port):
  770. data = fill_2_hexByte(hex(int(port)), 2)
  771. MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  772. payload={'IMEI': self._device['devNo'], "funCode": 'BC', 'data': data},
  773. timeout=MQTT_TIMEOUT.SHORT)
  774. def reply_C0(self, port):
  775. data = fill_2_hexByte(hex(int(port)), 2)
  776. MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE,
  777. payload={'IMEI': self._device['devNo'], "funCode": 'C1', 'data': '00' + data},
  778. timeout=MQTT_TIMEOUT.SHORT)
  779. def set_device_function(self, request, lastSetConf):
  780. if request.POST.has_key('reboot'):
  781. reboot = request.POST.get("reboot", False)
  782. if reboot:
  783. self.control_device('01')
  784. if request.POST.has_key('remoteUpgrade'):
  785. remoteUpgrade = request.POST.get("remoteUpgrade", False)
  786. if remoteUpgrade:
  787. self.control_device('02')
  788. def set_device_function_param(self, request, lastSetConf):
  789. devObj = Device.objects.get(devNo=self._device['devNo'])
  790. setConf = devObj.otherConf
  791. if request.POST.has_key('password'):
  792. password = request.POST.get("password","8888")
  793. setConf.update({'password': password})
  794. if request.POST.has_key('cardTime'):
  795. cardTime = request.POST.get("cardTime", '240')
  796. setConf.update({'cardTime': cardTime})
  797. if request.POST.has_key('runMode'):
  798. runMode = request.POST.get("runMode", '1')
  799. setConf.update({'runMode': runMode})
  800. if request.POST.has_key('icMoney'):
  801. icMoney = request.POST.get("icMoney", '1')
  802. setConf.update({'icMoney': icMoney})
  803. if request.POST.has_key('voice'):
  804. voice = request.POST.get("voice", '4')
  805. setConf.update({'voice': voice})
  806. if request.POST.has_key('coinTime'):
  807. coinTime = request.POST.get("coinTime", '240')
  808. setConf.update({'coinTime': coinTime})
  809. if request.POST.has_key('temperature'):
  810. temperature = request.POST.get("temperature", '255')
  811. setConf.update({'temperature': temperature})
  812. if request.POST.has_key('power1'):
  813. power1 = int(request.POST.get("power1", '3000'))
  814. setConf.update({'power1': power1*10})
  815. if request.POST.has_key('power2'):
  816. power2 = int(request.POST.get("power2", '4000'))
  817. setConf.update({'power2': power2*10})
  818. if request.POST.has_key('power3'):
  819. power3 = int(request.POST.get("power3", '5000'))
  820. setConf.update({'power3': power3*10})
  821. if request.POST.has_key('power4'):
  822. power4 = int(request.POST.get("power4", '6000'))
  823. setConf.update({'power4': power4*10})
  824. if request.POST.has_key('power5'):
  825. power5 = int(request.POST.get("power5", '7000'))
  826. setConf.update({'power5': power5*10})
  827. if request.POST.has_key('power2ratio'):
  828. power2ratio = int(request.POST.get("power2ratio", '100'))
  829. setConf.update({'power2ratio': power2ratio})
  830. if request.POST.has_key('power3ratio'):
  831. power3ratio = int(request.POST.get("power3ratio", '100'))
  832. setConf.update({'power3ratio': power3ratio})
  833. if request.POST.has_key('power4ratio'):
  834. power4ratio = int(request.POST.get("power4ratio", '100'))
  835. setConf.update({'power4ratio': power4ratio})
  836. if request.POST.has_key('power5ratio'):
  837. power5ratio = int(request.POST.get("power5ratio", '100'))
  838. setConf.update({'power5ratio': power5ratio})
  839. if request.POST.has_key('fuchongPower'):
  840. fuchongPower = int(request.POST.get("fuchongPower", '30'))
  841. setConf.update({'fuchongPower': fuchongPower*10})
  842. if request.POST.has_key('fuchongTime'):
  843. fuchongTime = int(request.POST.get("fuchongTime", '120'))
  844. setConf.update({'fuchongTime': fuchongTime*60})
  845. if request.POST.has_key('noPowerTime'):
  846. noPowerTime = int(request.POST.get("noPowerTime", '1'))
  847. setConf.update({'noPowerTime': noPowerTime*60})
  848. # 先保存到数据库中
  849. confDict = {
  850. 'runMode':int(setConf.get('runMode')), 'voice':int(setConf.get('voice')), 'coinTime':int(setConf.get('coinTime')),
  851. 'cardTime':int(setConf.get('cardTime')), 'icMoney':int(setConf.get('icMoney')), 'cardRefund':int(setConf.get('cardRefund')),
  852. 'power1':int(setConf.get('power1')), 'power2':int(setConf.get('power2')), 'power3':int(setConf.get('power3')), 'power4':int(setConf.get('power4')),
  853. 'power5':int(setConf.get('power5')), 'power1ratio':100, 'power2ratio':int(setConf.get('power2ratio')), 'power3ratio':int(setConf.get('power3ratio')),
  854. 'power4ratio':int(setConf.get('power4ratio')), 'power5ratio':int(setConf.get('power5ratio')), 'autoStop':int(setConf.get('autoStop')),
  855. 'fuchongPower':int(setConf.get('fuchongPower')), 'fuchongTime':int(setConf.get('fuchongTime')), 'noPowerTime':int(setConf.get('noPowerTime')), 'password':int(setConf.get('password')),
  856. 'temperature':int(setConf.get('temperature')), 'cardFeeMode':setConf.get('cardFeeMode', 'time'), 'cardFeeValue':setConf.get('cardFeeValue', 180)
  857. }
  858. devObj.otherConf.update(confDict)
  859. devObj.save()
  860. data = ''
  861. data += fill_2_hexByte(hex(int(setConf.get('runMode'))), 2)
  862. data += fill_2_hexByte(hex(int(setConf.get('voice'))), 2)
  863. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('coinTime'))), 4))
  864. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('cardTime'))), 4))
  865. data += fill_2_hexByte(hex(int(setConf.get('icMoney'))*10), 2)
  866. data += fill_2_hexByte(hex(int(setConf.get('cardRefund'))), 2)
  867. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power1'))), 4))
  868. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power2'))), 4))
  869. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power3'))), 4))
  870. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power4'))), 4))
  871. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('power5'))), 4))
  872. data += '64'
  873. data += fill_2_hexByte(hex(int(setConf.get('power2ratio'))), 2)
  874. data += fill_2_hexByte(hex(int(setConf.get('power3ratio'))), 2)
  875. data += fill_2_hexByte(hex(int(setConf.get('power4ratio'))), 2)
  876. data += fill_2_hexByte(hex(int(setConf.get('power5ratio'))), 2)
  877. data += fill_2_hexByte(hex(int(setConf.get('autoStop'))), 2)
  878. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('fuchongPower'))), 4))
  879. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('fuchongTime'))), 4))
  880. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('noPowerTime'))), 4))
  881. data += reverse_hex(fill_2_hexByte(hex(int(setConf.get('password'))), 4))
  882. data += fill_2_hexByte(hex(int(setConf.get('temperature'))), 2)
  883. data += '00000000000000'
  884. devInfo = MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, payload={
  885. "IMEI": self._device["devNo"],
  886. "funCode": "C3",
  887. "data": data,
  888. }, timeout=MQTT_TIMEOUT.SHORT)
  889. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  890. if devInfo['rst'] == -1:
  891. raise ServiceException({'result': 2, 'description': u'充电桩离线,配置信息没有下发到充电桩,设备重新上电上网后,会将配置下发到设备。建议您设备在线的时候配置'})
  892. elif devInfo['rst'] == 1:
  893. raise ServiceException({'result': 2, 'description': u'充电桩繁忙,配置信息没有下发到充电桩,设备重新上电上网后,会将配置下发到设备。建议您设备在线的时候配置'})