dianchuan.py 74 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663
  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.monetary import RMB
  9. from apilib.utils_string import split_str, cn
  10. from apps.web.constant import Const, DeviceCmdCode, ErrorCode, DeviceErrorCodeDesc, MQTT_TIMEOUT
  11. from apps.web.core.adapter.base import SmartBox, fill_2_hexByte, make_six_bytes_session_id
  12. from apps.web.core.exceptions import ServiceException
  13. from apps.web.core.networking import MessageSender
  14. from apps.web.device.models import Device
  15. logger = logging.getLogger(__name__)
  16. if TYPE_CHECKING:
  17. from apps.web.device.models import GroupDict
  18. class ChargingDIANCHUANBox(SmartBox):
  19. def __init__(self, device):
  20. super(ChargingDIANCHUANBox, self).__init__(device)
  21. def _check_package(self, package):
  22. """
  23. 获取设备启动的发送数据 根据设备的当前模式以及套餐获取
  24. :param package:
  25. :return:
  26. """
  27. consumeModule = self._device.get("otherConf", dict()).get("consumeModule", 0)
  28. unit = package.get("unit", u"分钟")
  29. _time = float(package.get("time", 0))
  30. # 按时间计费
  31. if consumeModule == 0:
  32. billingType = "time"
  33. if unit == u"小时":
  34. _time = _time * 60
  35. elif unit == u"天":
  36. _time = _time * 24 * 60
  37. elif unit == u"秒":
  38. _time = _time / 60
  39. elif unit == u"分钟":
  40. _time = _time
  41. else:
  42. raise ServiceException({"result": 2, "description": u"套餐单位错误,请联系经销商"})
  43. # 按电量计费
  44. else:
  45. billingType = "elec"
  46. if unit != u"度":
  47. raise ServiceException({"result": 2, "description": u"套餐单位错误,请联系经销商"})
  48. else:
  49. _time = _time * 100
  50. return _time, unit, billingType
  51. def translate_funcode(self, funCode):
  52. funCodeDict = {
  53. '01': u'查询设备每个端口当前的状态',
  54. '02': u'移动支付',
  55. '0C': u'获取设备设置',
  56. '06': u'获取设备端口详情',
  57. '07': u'获取刷卡投币统计数据',
  58. '08': u'设置设备参数',
  59. '09': u'设置刷卡投币使能',
  60. '0A': u'端口使能',
  61. '0B': u'端口关闭',
  62. '16': u'设置设备参数',
  63. '20': u'设备重启',
  64. '13': u'设置卡充满退费',
  65. '15': u'获取功率费率配置',
  66. '14': u'设置功率费率配置',
  67. '12': u'充值',
  68. '22': u'回复卡充值',
  69. '27': u'设置免费充电模式、音量调节',
  70. '29': u'设置刷卡充电时间',
  71. '2B': u'查询软件版本',
  72. '34': u'查询整机所有端口的状态(状态,剩余时间,功率,冲电电量,电流)',
  73. '35': u'查询设备其他动态参数(设备温度,烟雾报警器状态,设备电压)',
  74. '36': u'查询设备所有设置数据',
  75. '37': u'设置浮充功率,浮充时间,充电检测时间',
  76. '38': u'设置消费流程、计费方式',
  77. '40': u'重启主板',
  78. '43': u'温度保护阈值设置',
  79. '45': u'设置充电站3档计费功率、比例',
  80. }
  81. return funCodeDict.get(funCode, '')
  82. def translate_event_cmdcode(self, cmdCode):
  83. cmdDict = {
  84. '03': u'投币上报',
  85. '04': u'刷卡上报',
  86. '05': u'充电结束',
  87. '16': u'充电结束',
  88. '10': u'刷卡上报',
  89. '0D': u'故障',
  90. '20': u'启动设备',
  91. '11': u'刷卡使用',
  92. '12': u'卡充值',
  93. '22': u'ID卡扣费',
  94. '23': u'ID卡扣费状态',
  95. '17': u'IC卡回收余额成功',
  96. }
  97. return cmdDict.get(cmdCode, '')
  98. def is_port_can_use(self, port, canAdd=False):
  99. # 电川的在启动的时候去判断是否需要续充
  100. return True, ''
  101. def check_dev_status(self, attachParas=None):
  102. """
  103. 如果超过两个心跳周期没有报心跳,并且最后一次更新时间在2个小时内,需要从设备获取状态
  104. 否则以缓存状态为准。
  105. :param attachParas:
  106. :return:
  107. """
  108. if attachParas is None:
  109. raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口、电池类型信息'})
  110. if not attachParas.has_key('chargeIndex'):
  111. raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口'})
  112. if not self.device.need_fetch_online:
  113. raise ServiceException(
  114. {'result': 2, 'description': DeviceErrorCodeDesc.get(ErrorCode.DEVICE_CONN_CHECK_FAIL)})
  115. self.get_port_status_from_dev()
  116. group = self.device.group # type: GroupDict
  117. if group.is_free:
  118. logger.debug('{} is free. no need to check continue pay.'.format(repr(self.device)))
  119. return
  120. # 处理是否能够续充
  121. portDict = self.get_port_status()
  122. port = str(attachParas['chargeIndex'])
  123. if port in portDict:
  124. isCanAdd = self.device['devType'].get('payableWhileBusy', False)
  125. if portDict[port]['status'] == Const.DEV_WORK_STATUS_IDLE:
  126. return
  127. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FAULT:
  128. raise ServiceException({'result': 0, 'description': u'该端口故障,暂时不能使用'})
  129. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_WORKING:
  130. if isCanAdd:
  131. return
  132. else:
  133. raise ServiceException({'result': 0, 'description': u'该端口正在工作不能使用,请您使用其他端口'})
  134. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FORBIDDEN:
  135. raise ServiceException({'result': 0, 'description': u'该端口已被禁止使用,请您使用其他端口'})
  136. elif portDict[port]['status'] == Const.DEV_WORK_STATUS_CONNECTED:
  137. return
  138. else:
  139. raise ServiceException({'result': 0, 'description': u'端口状态未知,暂时不能使用'})
  140. else:
  141. raise ServiceException({'result': 0, 'description': u'未知端口,暂时不能使用'})
  142. def test(self, port=1, coins=1):
  143. hexPort = fill_2_hexByte(hex(int(port)), 2)
  144. hexTime = fill_2_hexByte(hex(coins))
  145. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  146. {'IMEI': self._device['devNo'], "funCode": '02',
  147. 'data': hexPort + '0000' + hexTime})
  148. return devInfo
  149. def port_is_busy(self, port_dict):
  150. if not port_dict:
  151. return False
  152. if 'billingType' not in port_dict:
  153. return False
  154. if 'status' not in port_dict:
  155. return False
  156. if 'coins' not in port_dict:
  157. return False
  158. if 'price' not in port_dict:
  159. return False
  160. if port_dict['billingType'] not in ['time', 'elec']:
  161. return False
  162. if port_dict['billingType'] == 'time':
  163. if 'needTime' not in port_dict:
  164. return False
  165. else:
  166. if 'needElec' not in port_dict:
  167. return False
  168. if port_dict['status'] == Const.DEV_WORK_STATUS_WORKING:
  169. return True
  170. else:
  171. return False
  172. def start_device(self, package, openId, attachParas):
  173. if attachParas is None:
  174. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
  175. if not attachParas.has_key('chargeIndex'):
  176. raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
  177. price = float(package['price'])
  178. dev = Device.objects.get(devNo=self._device['devNo'])
  179. refundProtection = dev.otherConf.get('refundProtection', 0)
  180. refundProtectionTime = dev.otherConf.get('refundProtectionTime', 5)
  181. port = hex(int(attachParas['chargeIndex']))
  182. hexPort = fill_2_hexByte(port, 2)
  183. _time, unit, billingType = self._check_package(package)
  184. coins = float(package['coins'])
  185. hexTime = fill_2_hexByte(hex(int(_time)))
  186. unit = package['unit']
  187. if unit == '度':
  188. hexTime = fill_2_hexByte(hex(int(_time)))
  189. orderNo = attachParas.get('orderNo')
  190. devInfo = MessageSender.send(
  191. device=self.device,
  192. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  193. payload={
  194. 'IMEI': self._device['devNo'],
  195. "funCode": '02',
  196. 'data': hexPort + '0000' + hexTime
  197. }, timeout=MQTT_TIMEOUT.START_DEVICE)
  198. usePort = int(attachParas['chargeIndex'])
  199. if 'rst' not in devInfo:
  200. raise ServiceException(
  201. {
  202. 'result': 2,
  203. 'description': u'启动设备失败,您的支付金额已经退还,请重新扫码设备试试(1001)'
  204. })
  205. if devInfo['rst'] != 0:
  206. if devInfo['rst'] == -1:
  207. raise ServiceException(
  208. {
  209. 'result': 2,
  210. 'description': u'充电桩正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦'
  211. })
  212. elif devInfo['rst'] == 1:
  213. self.check_serial_port_for_startcmd(attachParas['chargeIndex'])
  214. else:
  215. raise ServiceException(
  216. {
  217. 'result': 2,
  218. 'description': u'启动设备失败,您的支付金额已经退回,请重新扫码设备({})'.format(devInfo['rst'])
  219. })
  220. else:
  221. if 'data' not in devInfo:
  222. logger.warning('no data in success response. result = {}'.format(str(devInfo)))
  223. raise ServiceException(
  224. {
  225. 'result': 2,
  226. 'description': u'启动设备失败,您的支付金额已经退回,请重试'
  227. })
  228. else:
  229. data = devInfo['data'][18::]
  230. result = data[2:4]
  231. if result == '01': # 成功
  232. pass
  233. elif result == '02':
  234. newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'充电站故障'}}
  235. Device.update_dev_control_cache(self._device['devNo'], newValue)
  236. raise ServiceException({'result': 2, 'description': u'充电站故障'})
  237. elif result == '03':
  238. newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_WORKING, 'statusInfo': u''}}
  239. Device.update_dev_control_cache(self._device['devNo'], newValue)
  240. raise ServiceException({'result': 2, 'description': u'该端口正在使用中'})
  241. else:
  242. raise ServiceException({
  243. 'result': 2,
  244. 'description': u'启动设备失败({}),您的支付金额已经退回,请重新扫码设备'.format(result)
  245. })
  246. portDict = {
  247. 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
  248. 'status': Const.DEV_WORK_STATUS_WORKING,
  249. 'coins': coins,
  250. 'price': price,
  251. 'billingType': billingType,
  252. 'isStart': True,
  253. 'openId': openId,
  254. 'refunded': False,
  255. 'vCardId': self._vcard_id,
  256. 'refundProtection': refundProtection,
  257. 'refundProtectionTime': refundProtectionTime,
  258. 'doPowerLevel': False,
  259. 'payInfo': list()
  260. }
  261. ctrInfo = Device.get_dev_control_cache(self._device.devNo)
  262. lastPortInfo = ctrInfo.get(str(usePort), {})
  263. if self.port_is_busy(lastPortInfo) and \
  264. lastPortInfo.get('billingType') == billingType and \
  265. lastPortInfo.get('openId') == openId:
  266. is_continus = True
  267. portDict['coins'] = float(coins) + lastPortInfo['coins']
  268. portDict['price'] = float(price) + lastPortInfo['price']
  269. else:
  270. is_continus = False
  271. portDict['coins'] = float(coins)
  272. portDict['price'] = float(price)
  273. if 'linkedRechargeRecordId' in attachParas and attachParas.get('isQuickPay', False):
  274. if is_continus:
  275. payInfo = lastPortInfo.get("payInfo", list())
  276. if not payInfo:
  277. logger.warning("miss payInfo! {}-{}".format(self._device["devNo"], usePort))
  278. else:
  279. payInfo = list()
  280. payInfo.append({'rechargeRcdId': str(attachParas['linkedRechargeRecordId'])})
  281. portDict['payInfo'] = payInfo
  282. else:
  283. if is_continus:
  284. portDict['payInfo'] = lastPortInfo.get("payInfo", list())
  285. else:
  286. portDict['payInfo'] = list()
  287. if billingType == 'time':
  288. if is_continus:
  289. portDict['needTime'] = _time + lastPortInfo['needTime']
  290. else:
  291. portDict['needTime'] = _time
  292. finishedTime = int(time.time()) + int(portDict['needTime'] * 60)
  293. else:
  294. if is_continus:
  295. portDict['needElec'] = _time / 100.0 + lastPortInfo['needElec']
  296. else:
  297. portDict['needElec'] = _time / 100.0
  298. finishedTime = int(time.time()) + 60 * 60 * 12
  299. portDict.update({'finishedTime': finishedTime})
  300. if 'orderNo' in attachParas:
  301. portDict.update({'orderNo': attachParas['orderNo']})
  302. Device.update_dev_control_cache(
  303. self._device['devNo'],
  304. {
  305. str(usePort): portDict
  306. })
  307. devInfo['finishedTime'] = finishedTime
  308. return devInfo
  309. def analyze_event_data(self, data):
  310. cmdCode = data[4:6]
  311. if cmdCode == '05':
  312. port = int(data[18:20], 16)
  313. leftTime = int(data[20:24], 16)
  314. reason = data[24:26]
  315. if reason == '00':
  316. desc = u'购买的充电时间或者电量已经用完'
  317. elif reason == '01':
  318. desc = u'系统判断为异常断电(插头被拔或者松动,或者电瓶已经充满),电瓶车充电器种类繁多,可能存在误差'
  319. elif reason == '02':
  320. desc = u'电池已经充满'
  321. elif reason == '03':
  322. desc = u'设备或者端口故障。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电'
  323. elif reason == '04':
  324. desc = u'警告!您的电池功率超过本机最大限制。为了公共安全,不建议您在该充电桩充电'
  325. elif reason == '05':
  326. desc = u'刷卡退费结束'
  327. elif reason == '06':
  328. desc = u'可能是插头被拔掉或者未连接充电器。如果不是自己操作,建议您到现场检查是否有人误操作'
  329. elif reason == '07':
  330. desc = u'远程方式停止充电。如果不是自己操作,建议到现场尽快恢复充电'
  331. elif reason == '08':
  332. desc = u'远烟雾报警停止'
  333. else:
  334. desc = u''
  335. # 刷卡充电的结束
  336. if len(data) > 34:
  337. cardNo = str(int(data[26:34], 16))
  338. backMoney = int(data[34:36], 16) / 10.0
  339. cardType = 'ID' if data[36:40] == 'AA33' else 'IC'
  340. if cardNo != str(0):
  341. return {'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port,
  342. 'leftTime': leftTime, 'reason': desc, 'isStart': False, 'cardNo': cardNo,
  343. 'backMoney': backMoney, 'cardType': cardType, 'endType': reason,
  344. 'reasonCode': reason, 'uartData': data}
  345. else:
  346. return {'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port,
  347. 'leftTime': leftTime, 'reason': desc, 'isStart': False, 'endType': reason,
  348. 'reasonCode': reason, 'uartData': data}
  349. # 非刷卡充电的结束
  350. else:
  351. return {'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port,
  352. 'leftTime': leftTime, 'reason': desc, 'isStart': False, 'endType': reason,
  353. 'reasonCode': reason, 'uartData': data}
  354. elif cmdCode == '0D':
  355. port = int(data[18:20], 16)
  356. errCode = data[20:22]
  357. if errCode == '01':
  358. return {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'端口输出故障,保险丝熔断', 'cmdCode': cmdCode,
  359. 'port': port, 'FaultCode': errCode}
  360. elif errCode == '02':
  361. return {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'继电器黏连', 'cmdCode': cmdCode,
  362. 'port': port, 'FaultCode': errCode}
  363. elif cmdCode == '03': # 投币上报
  364. coin = int(data[18:20], 16)
  365. port = int(data[20:22], 16)
  366. return {'cmdCode': cmdCode, 'coins': coin, 'port': port}
  367. elif cmdCode == '11': # 刷卡后,按下端口,上报的报文
  368. cardNo = int(data[18:26], 16)
  369. cardNo = str(cardNo)
  370. fee = int(data[26:28], 16) / 10.0
  371. balance = int(data[28:32], 16) / 10.0
  372. cardType = 'ID' if data[32:36] == 'AA33' else 'IC'
  373. port = int(data[36:38], 16)
  374. status = data[38:40]
  375. return {'cardNo': cardNo, 'fee': fee, 'balance': balance, 'cardType': cardType, 'port': port,
  376. 'status': status, 'cmdCode': cmdCode}
  377. elif cmdCode == '12':
  378. cardNo = data[18:26]
  379. cardNo = str(int(cardNo, 16))
  380. balance = int(data[26:30], 16) / 10.0
  381. cardType = data[30:34]
  382. return {'cmdCode': cmdCode, 'balance': balance, 'cardType': cardType, 'cardNo': cardNo}
  383. elif cmdCode == '17':
  384. """
  385. IC卡回收余额成功,上报回收的数目
  386. 样例 660F170048614800052DDA5A0D000001DD
  387. """
  388. cardNo = int(data[18:26], 16)
  389. cardNo = str(cardNo)
  390. backMoney = int(data[26:30], 16) / 10.0
  391. return {'cmdCode': cmdCode, 'cardNo': cardNo, 'backMoney': backMoney}
  392. elif cmdCode == '22': # ID卡,上报上来扣费
  393. cardNo = int(data[18:26], 16)
  394. cardNo = str(cardNo)
  395. fee = int(data[26:28], 16) / 10.0
  396. cardType = 'ID' if data[28:32] == 'AA33' else 'IC'
  397. port = int(data[32:34], 16) or -1
  398. return {'cmdCode': cmdCode, 'cardNo': cardNo, 'fee': fee, 'cardType': cardType, 'port': port}
  399. elif cmdCode == '23': # ID卡,上报上来扣费
  400. cardNo = int(data[18:26], 16)
  401. cardNo = str(cardNo)
  402. status = data[26:28]
  403. return {'cmdCode': cmdCode, 'cardNo': cardNo, 'status': status}
  404. elif cmdCode == '41': # 烟感报警
  405. smokeWarning = True if data[18:20] == '01' else False
  406. return {'cmdCode': cmdCode, 'smokeWarning': smokeWarning, "faultCode": cmdCode}
  407. elif cmdCode == '47': # 温度超过阀值
  408. temperatureLast = str(int(data[18:20], 16))
  409. return {'cmdCode': cmdCode, 'temperatureLast': temperatureLast, "faultCode": cmdCode}
  410. elif cmdCode == '48':
  411. data = data
  412. nowPowerRatio = int(data[18:20], 16)
  413. leftTime = int(data[20:24], 16)
  414. nowPower = int(data[24:28], 16) / 10.0
  415. return {'cmdCode': cmdCode, 'nowPowerRatio': nowPowerRatio, 'leftTime': leftTime, 'nowPower': nowPower}
  416. def get_dev_consume_count(self):
  417. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  418. {'IMEI': self._device['devNo'], "funCode": '07', 'data': '00'})
  419. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  420. if devInfo['rst'] == -1:
  421. raise ServiceException(
  422. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  423. elif devInfo['rst'] == 1:
  424. raise ServiceException(
  425. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  426. data = devInfo['data'][18::]
  427. cardFee = int(data[2:6], 16) / 10.0 # 以角为单位
  428. coinFee = int(data[6:10], 16) # 以元为单位
  429. return {'cardFee': cardFee, 'coinFee': coinFee}
  430. # 查询单个充电状态
  431. def get_port_info(self, port):
  432. data = fill_2_hexByte(hex(int(port)), 2)
  433. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  434. {'IMEI': self._device['devNo'], "funCode": '06', 'data': data})
  435. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  436. if devInfo['rst'] == -1:
  437. raise ServiceException(
  438. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  439. elif devInfo['rst'] == 1:
  440. raise ServiceException(
  441. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  442. data = devInfo['data'][18::]
  443. leftTime = int(data[2:6], 16)
  444. if data[6:10] == 'FFFF':
  445. power = 0
  446. else:
  447. power = int(data[6:10], 16) / 10.0
  448. data = {"port": port, "power": power}
  449. # 电量计费模式
  450. if not self._device.get("otherConf", dict()).get("consumeModule", 0):
  451. data.update({"leftTime": leftTime})
  452. else:
  453. data.update({"leftElec": leftTime / 100.0})
  454. return data
  455. def __get_all_port_status_detail(self, returnType='list'):
  456. """
  457. 查询所有端口的详细(状态,剩余时间,功率,冲电电量,电流)
  458. returnType : list dict
  459. """
  460. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  461. {'IMEI': self._device['devNo'], "funCode": '34', 'data': '00'})
  462. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  463. if devInfo['rst'] == -1:
  464. raise ServiceException(
  465. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试', 'rst': -1})
  466. elif devInfo['rst'] == 1:
  467. raise ServiceException(
  468. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1})
  469. data = devInfo['data'][18:]
  470. import re
  471. portStatus = map(lambda d: d, re.findall(r'..', data[:20]))
  472. portLeftTime = map(lambda d: int(d, 16), re.findall(r'....', data[20:60]))
  473. portPower = map(lambda d: int(d, 16) / 10.0, re.findall(r'....', data[60:100]))
  474. portUsedElec = map(lambda d: int(d, 16) / 100.0, re.findall(r'....', data[100:140]))
  475. ampere = map(lambda d: int(d, 16) / 10.0, re.findall(r'..', data[140:160]))
  476. if returnType == 'list':
  477. lis = []
  478. for i, x in enumerate(portStatus):
  479. item = {
  480. 'index': str(i + 1),
  481. 'portStatus': str(x),
  482. 'leftTime': str(portLeftTime[i]),
  483. 'power': str(portPower[i]),
  484. 'usedElec': str(portUsedElec[i]),
  485. 'ampere': str(ampere[i]),
  486. }
  487. lis.append(item)
  488. return lis
  489. if returnType == 'dict':
  490. lis = []
  491. for i, x in enumerate(portStatus):
  492. item = (str(i + 1), {
  493. 'index': str(i + 1),
  494. 'portStatus': str(x),
  495. 'leftTime': str(portLeftTime[i]),
  496. 'power': str(portPower[i]),
  497. 'usedElec': str(portUsedElec[i]),
  498. 'ampere': str(ampere[i]),
  499. })
  500. lis.append(item)
  501. result = dict(lis)
  502. return result
  503. def dealer_get_device_port(self):
  504. port_detail_dict = self.__get_all_port_status_detail()
  505. parse_status_code = {
  506. '00': u'端口正常',
  507. '01': u'端口无输出',
  508. '02': u'端口粘连',
  509. }
  510. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  511. lis = []
  512. for item in port_detail_dict:
  513. if float(item['ampere']) == 0 and float(item['power']) == 0:
  514. item = {
  515. 'index': item['index'],
  516. 'status': 'idle',
  517. 'desc': parse_status_code[item['portStatus']]
  518. }
  519. elif item['portStatus'] != '00':
  520. item = {
  521. 'index': item['index'],
  522. 'status': 'fault',
  523. 'desc': parse_status_code[item['portStatus']]
  524. }
  525. else:
  526. item['status'] = 'busy'
  527. item['desc'] = parse_status_code[item['portStatus']]
  528. lineInfo = ctrInfo.get(str(item['index']), {})
  529. if not lineInfo:
  530. lineInfo = {}
  531. lineInfo.update(item)
  532. item = self.format_port_using_detail(lineInfo)
  533. lis.append(item)
  534. return lis
  535. def get_port_status_from_dev(self):
  536. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  537. {'IMEI': self._device['devNo'], "funCode": '01', 'data': '00'})
  538. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  539. if devInfo['rst'] == -1:
  540. raise ServiceException(
  541. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试', 'rst': -1})
  542. elif devInfo['rst'] == 1:
  543. raise ServiceException(
  544. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1})
  545. data = devInfo['data'][18::]
  546. result = {}
  547. portNum = int(data[:2], 16)
  548. portData = data[2:-2]
  549. ii = 0
  550. while ii < portNum:
  551. statusTemp = portData[ii * 2:ii * 2 + 2]
  552. if statusTemp == '01':
  553. status = {'status': Const.DEV_WORK_STATUS_IDLE}
  554. elif statusTemp == '02':
  555. status = {'status': Const.DEV_WORK_STATUS_WORKING}
  556. elif statusTemp == '03':
  557. status = {'status': Const.DEV_WORK_STATUS_FORBIDDEN}
  558. elif statusTemp == '04':
  559. status = {'status': Const.DEV_WORK_STATUS_FAULT}
  560. # 不再上述状态之列的 统一为故障状态
  561. else:
  562. status = {'status': Const.DEV_WORK_STATUS_FAULT}
  563. ii += 1
  564. result[str(ii)] = status
  565. allPorts, usedPorts, usePorts = self.get_port_static_info(result)
  566. # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
  567. ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
  568. for strPort, info in result.items():
  569. if ctrInfo.has_key(strPort):
  570. ctrInfo[strPort].update({'status': info['status']})
  571. else:
  572. ctrInfo[strPort] = info
  573. ctrInfo.update({
  574. 'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts
  575. })
  576. Device.update_dev_control_cache(self.device.devNo, ctrInfo)
  577. return result
  578. def get_default_port_nums(self):
  579. default_num = 10
  580. return default_num
  581. def get_port_status(self, force=False):
  582. if force:
  583. return self.get_port_status_from_dev()
  584. ctrInfo = Device.get_dev_control_cache(self.device.devNo)
  585. if 'allPorts' in ctrInfo and ctrInfo['allPorts'] > 0:
  586. allPorts = ctrInfo['allPorts']
  587. else:
  588. allPorts = self.get_default_port_nums()
  589. statusDict = {}
  590. for ii in range(allPorts):
  591. tempDict = ctrInfo.get(str(ii + 1), {})
  592. if tempDict.has_key('status'):
  593. statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
  594. elif tempDict.has_key('isStart'):
  595. if tempDict['isStart']:
  596. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
  597. else:
  598. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  599. else:
  600. statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
  601. return statusDict
  602. def lock_unlock_port(self, port, lock=True):
  603. lockStr = '00' if lock else '01'
  604. portStr = fill_2_hexByte(hex(int(port)), 2)
  605. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  606. {'IMEI': self._device['devNo'], "funCode": '0A', 'data': portStr + lockStr})
  607. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  608. if devInfo['rst'] == -1:
  609. raise ServiceException(
  610. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  611. elif devInfo['rst'] == 1:
  612. raise ServiceException(
  613. {'result': 2, 'description': u'端口禁用功能只有带保险丝版本的才有。可能是您的设备版本过低,暂时不支持此功能,也可能是设备繁忙无响应。'})
  614. data = devInfo['data'][18::]
  615. if data[0:2] == '01': # 表示成功
  616. pass
  617. else:
  618. raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
  619. if lock:
  620. Device.update_dev_control_cache(self._device['devNo'],
  621. {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
  622. else:
  623. Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
  624. def active_deactive_port(self, port, active):
  625. if active:
  626. raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'})
  627. self.stop_charging_port(port)
  628. devInfo = Device.get_dev_control_cache(self._device['devNo'])
  629. portCtrInfo = devInfo.get(str(port), {})
  630. portCtrInfo.update({'isStart': False, 'status': Const.DEV_WORK_STATUS_IDLE, 'needTime': 0, 'leftTime': 0,
  631. 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
  632. newValue = {str(port): portCtrInfo}
  633. Device.update_dev_control_cache(self._device['devNo'], newValue)
  634. def stop_charging_port(self, port):
  635. portStr = fill_2_hexByte(hex(int(port)), 2)
  636. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  637. {'IMEI': self._device['devNo'], "funCode": '0B', 'data': portStr})
  638. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  639. if devInfo['rst'] == -1:
  640. raise ServiceException(
  641. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  642. elif devInfo['rst'] == 1:
  643. raise ServiceException(
  644. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  645. data = devInfo['data'][18::]
  646. port = int(data[2:4], 16)
  647. leftTime = int(data[4:8], 16)
  648. data = {"port": port}
  649. # 电量计费模式
  650. if not self._device.get("otherConf", dict()).get("consumeModule", 0):
  651. data.update({"remainder_time": leftTime})
  652. else:
  653. data.update({"remainder_time": leftTime / 100.0})
  654. return data
  655. def stop(self, port=None):
  656. return self.stop_charging_port(port)
  657. @property
  658. def isHaveStopEvent(self):
  659. return True
  660. # 获取IC卡、投币、最大功率设置
  661. def get_IC_coin_power_config(self):
  662. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  663. {'IMEI': self._device['devNo'], "funCode": '0C', 'data': '00'})
  664. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  665. if devInfo['rst'] == -1:
  666. raise ServiceException(
  667. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  668. elif devInfo['rst'] == 1:
  669. raise ServiceException(
  670. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  671. confData = devInfo['data'][18::]
  672. # maxPower = int(confData[0:4], 16) # 新版本移除maxPower
  673. icMoney = int(confData[4:6], 16)
  674. if len(confData) > 6:
  675. time1 = int(confData[6:10], 16)
  676. time2 = int(confData[10:14], 16)
  677. time3 = int(confData[14:18], 16)
  678. else:
  679. time1, time2, time3 = 0, 0, 0
  680. return {'icMoney': icMoney, 'time1': time1,
  681. 'time2': time2, 'time3': time3}
  682. def set_IC_coin_power_config(self, infoDict):
  683. data = '0000'
  684. # data += fill_2_hexByte(hex(int(infoDict['maxPower'])), 4) # 新协议移除maxPower 用0000填充
  685. data += fill_2_hexByte(hex(int(infoDict['icMoney'])), 2)
  686. data += fill_2_hexByte(hex(int(infoDict['time1'])), 4)
  687. data += fill_2_hexByte(hex(int(infoDict['time2'])), 4)
  688. data += fill_2_hexByte(hex(int(infoDict['time3'])), 4)
  689. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  690. {'IMEI': self._device['devNo'], "funCode": '08', 'data': data})
  691. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  692. if devInfo['rst'] == -1:
  693. raise ServiceException(
  694. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  695. elif devInfo['rst'] == 1:
  696. raise ServiceException(
  697. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  698. def set_IC_coin_power_config_elec(self, infoDict):
  699. data = '0000'
  700. # data += fill_2_hexByte(hex(int(infoDict['maxPower'])), 4) # 新协议移除maxPower 用0000填充
  701. data += fill_2_hexByte(hex(int(infoDict['icMoney'])), 2)
  702. data += fill_2_hexByte(hex(int(infoDict['elec1'])), 4)
  703. data += fill_2_hexByte(hex(int(infoDict['elec2'])), 4)
  704. data += fill_2_hexByte(hex(int(infoDict['elec3'])), 4)
  705. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  706. {'IMEI': self._device['devNo'], "funCode": '08', 'data': data})
  707. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  708. if devInfo['rst'] == -1:
  709. raise ServiceException(
  710. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  711. elif devInfo['rst'] == 1:
  712. raise ServiceException(
  713. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  714. def get_coin_card_enable(self):
  715. devs = Device.get_collection().find({'devNo': self._device['devNo']})
  716. if devs.count == 0:
  717. raise ServiceException(
  718. {'result': 2, 'description': u'没有找到设备哦'})
  719. return {'putCoins': devs[0].get('otherConf', {}).get('putCoins', False),
  720. 'icCard': devs[0].get('otherConf', {}).get('icCard', False)}
  721. def set_coin_card_enable(self, infoDict):
  722. data = ''
  723. if infoDict['putCoins']:
  724. data += '01'
  725. else:
  726. data += '00'
  727. if infoDict['icCard']:
  728. data += '01'
  729. else:
  730. data += '00'
  731. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  732. {'IMEI': self._device['devNo'], "funCode": '09', 'data': data})
  733. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  734. if devInfo['rst'] == -1:
  735. raise ServiceException(
  736. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  737. elif devInfo['rst'] == 1:
  738. raise ServiceException(
  739. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  740. try:
  741. conf = Device.objects.get(devNo=self._device['devNo']).otherConf
  742. conf.update({'putCoins': infoDict['putCoins'], 'icCard': infoDict['icCard']})
  743. Device.get_collection().update_one({'devNo': self._device['devNo']}, {'$set': {'otherConf': conf}})
  744. except Exception, e:
  745. logger.error('update dev=%s coin enable ic enable e=%s' % (self._device['devNo'], e))
  746. def get_dev_all_settings(self):
  747. """
  748. 电川PCB- DC_Crg_10L_C4.0及以上版本 支持全部参数一起查询 多参数消费流程 消费方式
  749. :return:
  750. """
  751. result = MessageSender.send(
  752. device=self.device,
  753. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  754. payload={
  755. "IMEI": self._device["devNo"],
  756. "data": "00",
  757. "funCode": "36"
  758. }
  759. )
  760. rst = result.get("rst")
  761. if rst == -1:
  762. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  763. elif rst == 1:
  764. raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  765. elif rst == 0:
  766. data = split_str(result.get('data'), lens="4444444242424224442222", startIndex=18, toInt=True)
  767. resultDict = {
  768. "time1": data[0],
  769. "time2": data[1],
  770. "time3": data[2],
  771. "card1Time": data[3],
  772. "card2Time": data[4],
  773. "card3Time": data[5],
  774. "icMoney": data[6], # 前台单位为角
  775. "cardRefund": bool(data[7]),
  776. "power1": data[8],
  777. "power1ratio": data[9],
  778. "power2": data[10],
  779. "power2ratio": data[11],
  780. "power3": data[12],
  781. "temperatureMax": data[13],
  782. "autoStop": bool(data[14]),
  783. "fuchongPower": data[15] * 0.1,
  784. "fuchongTime": data[16],
  785. "noPowerTime": data[17],
  786. "chargeFree": data[18],
  787. "volume": data[19],
  788. "consumeProcess": data[20],
  789. "consumeModule": data[21]
  790. }
  791. try:
  792. sensorParam = self.get_sensor_status()
  793. resultDict.update(sensorParam)
  794. except Exception:
  795. pass
  796. resultDict['maxPower'] = resultDict['power3']
  797. # 温度开关
  798. if int(resultDict['temperatureMax']) == 255:
  799. resultDict['temperatureMaxSwitch'] = '0'
  800. resultDict['temperatureMax'] = '--'
  801. else:
  802. resultDict['temperatureMaxSwitch'] = '1'
  803. else:
  804. raise ServiceException({'result': 2, 'description': u"数据读取失败,请您稍后再试"})
  805. # 协议上没有不显示
  806. # coinCardEnable = self.get_coin_card_enable()
  807. # resultDict['putCoins'] = coinCardEnable['putCoins']
  808. # resultDict['icCard'] = coinCardEnable['icCard']
  809. return resultDict
  810. # 获取设备配置参数
  811. def get_dev_setting(self):
  812. driverCode = self._device.get("devType", dict()).get("code", "")
  813. resultDict = self.get_dev_all_settings()
  814. dev = Device.objects.get(devNo=self._device['devNo'])
  815. refundProtection = dev.otherConf.get('refundProtection', 0)
  816. refundProtectionTime = dev.otherConf.get('refundProtectionTime', 5)
  817. cardNoRangeStart = dev.otherConf.get('cardNoRangeStart', '')
  818. cardNoRangeEnd = dev.otherConf.get('cardNoRangeEnd', '')
  819. # resultDict.update({'volume': volume})
  820. # resultDict.update({'fuchongPower': fuchongPower})
  821. # resultDict.update({'fuchongTime': fuchongTime})
  822. resultDict.update({'driverCode': driverCode})
  823. resultDict.update({'refundProtection': refundProtection})
  824. resultDict.update({'refundProtectionTime': refundProtectionTime})
  825. resultDict.update({'cardNoRangeStart': cardNoRangeStart})
  826. resultDict.update({'cardNoRangeEnd': cardNoRangeEnd})
  827. if resultDict['consumeModule'] == 1:
  828. resultDict['elec1'] = round(float(resultDict['time1']) / 100,2)
  829. resultDict['elec2'] = round(float(resultDict['time2']) / 100,2)
  830. resultDict['elec3'] = round(float(resultDict['time3']) / 100,2)
  831. resultDict['card1Elec'] = round(float(resultDict['card1Time']) / 100,2)
  832. resultDict['card2Elec'] = round(float(resultDict['card2Time']) / 100,2)
  833. resultDict['card3Elec'] = round(float(resultDict['card3Time']) / 100,2)
  834. return resultDict
  835. # 获取设备配置参数
  836. def set_dev_setting(self, setConf):
  837. keys = setConf.keys()
  838. if 'putCoins' in keys or 'icCard' in keys:
  839. self.set_coin_card_enable(setConf)
  840. if 'maxPower' in keys or 'icMoney' in keys or 'time1' in keys or 'time2' in keys or 'time3' in keys:
  841. self.set_IC_coin_power_config(setConf)
  842. # 暂无此功能
  843. def get_IC_card_password(self):
  844. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  845. {'IMEI': self._device['devNo'], "funCode": '1A', 'data': '00'}, timeout=8)
  846. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  847. if devInfo['rst'] == -1:
  848. raise ServiceException(
  849. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  850. elif devInfo['rst'] == 1:
  851. raise ServiceException(
  852. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  853. confData = devInfo['data'][18::]
  854. print confData
  855. result = confData[0:2]
  856. if result == '00':
  857. cardPassword = ''
  858. else:
  859. cardPassword = str(int(confData[2:12]))
  860. return {'cardPassword': cardPassword}
  861. def get_fullstop_cardrefund(self):
  862. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  863. {'IMEI': self._device['devNo'], "funCode": '0C', 'data': '00'})
  864. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  865. if devInfo['rst'] == -1:
  866. raise ServiceException(
  867. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  868. elif devInfo['rst'] == 1:
  869. raise ServiceException(
  870. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  871. confData = devInfo['data'][18::]
  872. maxPower = int(confData[0:4], 16)
  873. icMoney = int(confData[4:6], 16)
  874. if len(confData) > 6:
  875. time1 = int(confData[6:10], 16)
  876. time2 = int(confData[10:14], 16)
  877. time3 = int(confData[14:18], 16)
  878. else:
  879. time1, time2, time3 = 0, 0, 0
  880. return {'autoStop': True if confData[20:22] == u'01' else False,
  881. 'cardRefund': True if confData[18:20] == u'01' else False}
  882. def set_fullstop_cardrefund(self, infoDict):
  883. data = ''
  884. if infoDict['autoStop']:
  885. data += '01'
  886. else:
  887. data += '00'
  888. if infoDict['cardRefund']:
  889. data += '01'
  890. else:
  891. data += '00'
  892. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  893. {'IMEI': self._device['devNo'], "funCode": '13', 'data': data})
  894. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  895. if devInfo['rst'] == -1:
  896. raise ServiceException(
  897. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  898. elif devInfo['rst'] == 1:
  899. raise ServiceException(
  900. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  901. try:
  902. conf = Device.objects.get(devNo=self._device['devNo']).otherConf
  903. conf.update({'autoStop': infoDict['autoStop'], 'cardRefund': infoDict['cardRefund']})
  904. Device.get_collection().update({'devNo': self._device['devNo']}, {'$set': {'otherConf': conf}})
  905. except Exception, e:
  906. logger.error('update dev=%s coin enable ic enable e=%s' % (self._device['devNo'], e))
  907. def recharge_ic_card_realiable(self, cardNo, money, order_no):
  908. # type:(str,RMB,str)->dict
  909. data = 'EE1012{}'.format(make_six_bytes_session_id())
  910. cardNo = fill_2_hexByte(hex(int(cardNo)), 8)
  911. data += cardNo + fill_2_hexByte(hex(int(money * 10)), 4) + '0001'
  912. payload = {
  913. 'IMEI': self.device.devNo, 'data': data,
  914. 'funCode': '12', 'order_id': order_no, 'order_type': 'ic_recharge'}
  915. MessageSender.send_no_wait(device=self.device,
  916. cmd=DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC,
  917. payload=payload,
  918. timeout=180)
  919. # 给实体卡充值
  920. def recharge_card(self, cardNo, money, orderNo=None):
  921. # type:(str,RMB)->(dict, RMB)
  922. try:
  923. data = 'EE1012{}'.format(make_six_bytes_session_id())
  924. cardNo = fill_2_hexByte(hex(int(cardNo)), 8)
  925. data += cardNo + fill_2_hexByte(hex(int(money * 10)), 4) + '0001'
  926. devInfo = MessageSender.send(device=self.device,
  927. cmd=DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC,
  928. payload={'IMEI': self._device['devNo'], 'data': data, 'funCode': '12'},
  929. timeout=180)
  930. if devInfo['rst'] != 0:
  931. if devInfo['rst'] == ErrorCode.DEVICE_CONN_FAIL:
  932. # 离线无法判断是否成功, 认为充值成功, 走售后解决
  933. return {
  934. 'result': ErrorCode.DEVICE_CONN_FAIL,
  935. 'description': u'当前充电桩正在玩命找网络,请您稍候再试'
  936. }, None
  937. elif devInfo['rst'] == ErrorCode.BOARD_UART_TIMEOUT:
  938. return {
  939. 'result': ErrorCode.BOARD_UART_TIMEOUT,
  940. 'description': u'当前充电桩忙,无响应,请您稍候再试'
  941. }, None
  942. else:
  943. return {
  944. 'result': devInfo['rst'],
  945. 'description': u'系统异常'
  946. }, None
  947. resultData = devInfo['data']
  948. if resultData[4:6] != '16':
  949. return {
  950. 'result': ErrorCode.PARAMETER_ERROR_TO_BOX,
  951. 'description': u'充值返回报文命令码不为16'
  952. }, None
  953. balance = RMB(int(resultData[26:30], 16)) * Decimal('0.1')
  954. result = True if resultData[34:36] == '01' else False
  955. if result:
  956. return {
  957. 'result': ErrorCode.SUCCESS,
  958. 'description': ''
  959. }, balance
  960. else:
  961. return {
  962. 'result': ErrorCode.IC_RECHARGE_FAIL,
  963. 'description': u'充值失败'
  964. }, balance
  965. except Exception as e:
  966. logger.exception(e)
  967. return {
  968. 'result': ErrorCode.EXCEPTION,
  969. 'description': e.message
  970. }, None
  971. def get_mcu_version(self):
  972. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  973. {'IMEI': self._device['devNo'], "funCode": '25', 'data': '00'})
  974. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  975. if devInfo['rst'] == -1:
  976. raise ServiceException(
  977. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  978. elif devInfo['rst'] == 1:
  979. raise ServiceException(
  980. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  981. confData = devInfo['data'][18::]
  982. mcuVersion = int(confData[0:4], 16)
  983. return {'mcuVersion': mcuVersion}
  984. def set_freemode_volume_config(self, infoDict):
  985. data = '01' if infoDict['chargeFree'] == '1' else '00'
  986. data += fill_2_hexByte(hex(int(infoDict.get('volume', 5))), 2)
  987. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  988. {'IMEI': self._device['devNo'], "funCode": '27', 'data': data})
  989. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  990. if devInfo['rst'] == -1:
  991. raise ServiceException(
  992. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  993. elif devInfo['rst'] == 1:
  994. raise ServiceException(
  995. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  996. def set_card_time_config(self, infoDict):
  997. data = fill_2_hexByte(hex(int(infoDict['card1Time'])), 4)
  998. data += fill_2_hexByte(hex(int(infoDict['card2Time'])), 4)
  999. data += fill_2_hexByte(hex(int(infoDict['card3Time'])), 4)
  1000. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  1001. {'IMEI': self._device['devNo'], "funCode": '29', 'data': data})
  1002. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  1003. if devInfo['rst'] == -1:
  1004. raise ServiceException(
  1005. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1006. elif devInfo['rst'] == 1:
  1007. raise ServiceException(
  1008. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  1009. def set_card_elec_config(self, infoDict):
  1010. data = fill_2_hexByte(hex(int(infoDict['card1Elec'])), 4)
  1011. data += fill_2_hexByte(hex(int(infoDict['card2Elec'])), 4)
  1012. data += fill_2_hexByte(hex(int(infoDict['card3Elec'])), 4)
  1013. devInfo = MessageSender.send(self.device, self.make_random_cmdcode(),
  1014. {'IMEI': self._device['devNo'], "funCode": '29', 'data': data})
  1015. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  1016. if devInfo['rst'] == -1:
  1017. raise ServiceException(
  1018. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1019. elif devInfo['rst'] == 1:
  1020. raise ServiceException(
  1021. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  1022. # 暂无此功能
  1023. def set_IC_card_password(self, infoDict):
  1024. passwordStr = str(infoDict['cardPassword'])
  1025. if len(passwordStr) < 6 or len(passwordStr) > 12:
  1026. raise ServiceException({'result': 2, 'description': u'密码长度不合法, 请重新设置'})
  1027. data = passwordStr.rjust(12, '0')
  1028. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  1029. {'IMEI': self._device['devNo'], 'funCode': '18',
  1030. 'data': data}, timeout=120)
  1031. # 暂无此功能
  1032. def set_IC_card_range(self, infoDict):
  1033. cardNoRangeStart = str(infoDict['cardNoRangeStart'])
  1034. cardNoRangeEnd = str(infoDict['cardNoRangeEnd'])
  1035. if int(cardNoRangeStart) > 4294967295 or int(cardNoRangeEnd) > 4294967295 or int(cardNoRangeStart) > int(
  1036. cardNoRangeEnd):
  1037. raise ServiceException({'result': 2, 'description': u'卡号设置不合法, 请重新设置'})
  1038. cardNoRangeStart = cardNoRangeStart.rjust(10, '0')
  1039. cardNoRangeEnd = cardNoRangeEnd.rjust(10, '0')
  1040. data = cardNoRangeStart + cardNoRangeEnd
  1041. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  1042. {'IMEI': self._device['devNo'], 'funCode': '19',
  1043. 'data': data}, timeout=120)
  1044. dev = Device.objects.get(devNo=self._device['devNo'])
  1045. dev.otherConf.update({'cardNoRangeStart': str(infoDict['cardNoRangeStart'])})
  1046. dev.otherConf.update({'cardNoRangeEnd': str(infoDict['cardNoRangeEnd'])})
  1047. dev.save()
  1048. def set_device_function(self, request, lastSetConf):
  1049. if request.POST.has_key('putCoins'):
  1050. # putCoins = True if request.POST.get('putCoins') == 'true' else False
  1051. putCoins = request.POST.get("putCoins", False)
  1052. lastSetConf.update({'putCoins': putCoins})
  1053. self.set_coin_card_enable(lastSetConf)
  1054. if request.POST.has_key('icCard'):
  1055. # icCard = True if request.POST.get('icCard') == 'true' else False
  1056. icCard = request.POST.get("icCard", False)
  1057. lastSetConf.update({'icCard': icCard})
  1058. self.set_coin_card_enable(lastSetConf)
  1059. if request.POST.has_key('autoStop'):
  1060. # autoStop = True if request.POST.get('autoStop') == 'true' else False
  1061. autoStop = request.POST.get("autoStop", False)
  1062. lastSetConf.update({'autoStop': autoStop})
  1063. self.set_fullstop_cardrefund(lastSetConf)
  1064. if request.POST.has_key('cardRefund'):
  1065. # cardRefund = True if request.POST.get('cardRefund') == 'true' else False
  1066. cardRefund = request.POST.get("cardRefund", False)
  1067. lastSetConf.update({'cardRefund': cardRefund})
  1068. self.set_fullstop_cardrefund(lastSetConf)
  1069. if request.POST.has_key('chargeFree'):
  1070. # chargeFree = True if request.POST.get('chargeFree') == 'true' else False
  1071. chargeFree = request.POST.get("chargeFree", False)
  1072. lastSetConf.update({'chargeFree': chargeFree})
  1073. self.set_freemode_volume_config(lastSetConf)
  1074. if request.POST.has_key('reboot'):
  1075. reboot = request.POST.get("reboot", False)
  1076. if reboot:
  1077. self.reboot_device()
  1078. def set_device_function_param(self, request, lastSetConf):
  1079. if request.POST.has_key('time1') and request.POST.has_key('time2') and request.POST.has_key('time3'):
  1080. lastSetConf.update({'icMoney': int(request.POST.get('icMoney', 0))})
  1081. lastSetConf.update({'time1': int(request.POST.get('time1', 0))})
  1082. lastSetConf.update({'time2': int(request.POST.get('time2', 0))})
  1083. lastSetConf.update({'time3': int(request.POST.get('time3', 0))})
  1084. self.set_IC_coin_power_config(lastSetConf)
  1085. if 'elec1' in request.POST and 'elec2' in request.POST and 'elec3' in request.POST:
  1086. lastSetConf.update({'icMoney': int(request.POST.get('icMoney', 0))})
  1087. lastSetConf.update({'elec1': int(float(request.POST.get('elec1', 0)) * 100)})
  1088. lastSetConf.update({'elec2': int(float(request.POST.get('elec2', 0)) * 100)})
  1089. lastSetConf.update({'elec3': int(float(request.POST.get('elec3', 0)) * 100)})
  1090. self.set_IC_coin_power_config_elec(lastSetConf)
  1091. if request.POST.has_key('power1') and request.POST.has_key('power1ratio'):
  1092. lastSetConf.update({'power1': int(request.POST.get('power1', 0))})
  1093. lastSetConf.update({'power1ratio': int(request.POST.get('power1ratio', 0))})
  1094. lastSetConf.update({'power2': int(request.POST.get('power2', 0))})
  1095. lastSetConf.update({'power2ratio': int(request.POST.get('power2ratio', 0))})
  1096. lastSetConf.update({'power3': int(request.POST.get('power3', 0))})
  1097. lastSetConf.update({'power3ratio': int(request.POST.get('power3ratio', 0))})
  1098. self.set_power_level(lastSetConf)
  1099. # TODO 最大功率就是三档的功率
  1100. if request.POST.has_key('maxPower'):
  1101. if int(lastSetConf.get('maxPower', 0)) != int(request.POST.get('maxPower', 0)):
  1102. lastSetConf.update({'power3': int(request.POST.get('maxPower', 0))})
  1103. self.set_power_level(lastSetConf)
  1104. if request.POST.has_key('card1Time') and request.POST.has_key('card2Time') and request.POST.has_key(
  1105. 'card3Time'):
  1106. lastSetConf.update({'card1Time': int(request.POST.get('card1Time', 0))})
  1107. lastSetConf.update({'card2Time': int(request.POST.get('card2Time', 0))})
  1108. lastSetConf.update({'card3Time': int(request.POST.get('card3Time', 0))})
  1109. self.set_card_time_config(lastSetConf)
  1110. if 'card1Elec' in request.POST and 'card2Elec' in request.POST and 'card3Elec' in request.POST:
  1111. lastSetConf.update({'card1Elec': int(float(request.POST.get('card1Elec', 0)) * 100)})
  1112. lastSetConf.update({'card2Elec': int(float(request.POST.get('card2Elec', 0)) * 100)})
  1113. lastSetConf.update({'card3Elec': int(float(request.POST.get('card3Elec', 0)) * 100)})
  1114. self.set_card_elec_config(lastSetConf)
  1115. if 'fuchongPower' in request.POST and 'fuchongTime' in request.POST:
  1116. fuchongPower = 0 if request.POST.get('fuchongPower') == '' else int(request.POST.get('fuchongPower'))
  1117. fuchongTime = 0 if request.POST.get('fuchongTime') == '' else int(request.POST.get('fuchongTime'))
  1118. noPowerTime = 0 if request.POST.get('noPowerTime') == '' else int(request.POST.get('noPowerTime'))
  1119. lastSetConf.update({'fuchongPower': fuchongPower})
  1120. lastSetConf.update({'fuchongTime': fuchongTime})
  1121. lastSetConf.update({'noPowerTime': noPowerTime})
  1122. self.set_float_charge_settings(lastSetConf)
  1123. if "consumeProcess" in request.POST and "consumeModule" in request.POST:
  1124. lastSetConf.update({"consumeProcess": request.POST.get("consumeProcess")})
  1125. lastSetConf.update({"consumeModule": request.POST.get("consumeModule")})
  1126. self.set_consume_module(lastSetConf)
  1127. if request.POST.has_key('refundProtection'):
  1128. lastSetConf.update({'refundProtection': int(request.POST.get('refundProtection', 0))})
  1129. dev = Device.objects.get(devNo=self._device['devNo'])
  1130. dev.otherConf.update({'refundProtection': lastSetConf['refundProtection']})
  1131. dev.save()
  1132. if request.POST.has_key('refundProtectionTime'):
  1133. lastSetConf.update({'refundProtectionTime': int(request.POST.get('refundProtectionTime', 5))})
  1134. dev = Device.objects.get(devNo=self._device['devNo'])
  1135. dev.otherConf.update({'refundProtectionTime': lastSetConf['refundProtectionTime']})
  1136. dev.save()
  1137. if request.POST.has_key('volume'):
  1138. if request.POST.get('volume') != lastSetConf['volume']:
  1139. lastSetConf.update({'volume': int(request.POST.get('volume', 0))})
  1140. self.set_freemode_volume_config(lastSetConf)
  1141. if request.POST.has_key('temperatureMax') and request.POST.has_key('temperatureMaxSwitch'):
  1142. temperatureMaxSwitch = request.POST.get('temperatureMaxSwitch')
  1143. temperatureMax = request.POST.get('temperatureMax')
  1144. s1 = temperatureMaxSwitch != str(lastSetConf['temperatureMaxSwitch'])
  1145. s2 = temperatureMax != str(lastSetConf['temperatureMax'])
  1146. if s1:
  1147. lastSetConf.update({'temperatureMaxSwitch': int(request.POST.get('temperatureMaxSwitch', 0))})
  1148. lastSetConf.update({'temperatureMax': int(request.POST.get('temperatureMax', 0))})
  1149. self.set_warning_temperature(lastSetConf)
  1150. else:
  1151. if s2:
  1152. if temperatureMaxSwitch == '0':
  1153. raise ServiceException({'result': 2, 'description': u'温控阀值开关需要打开'})
  1154. else:
  1155. lastSetConf.update({'temperatureMaxSwitch': int(request.POST.get('temperatureMaxSwitch', 0))})
  1156. lastSetConf.update({'temperatureMax': int(request.POST.get('temperatureMax', 0))})
  1157. self.set_warning_temperature(lastSetConf)
  1158. if 'cardPassword' in request.POST:
  1159. lastSetConf.update({'cardPassword': int(request.POST.get('cardPassword', 0))})
  1160. self.set_IC_card_password(lastSetConf)
  1161. if 'cardNoRangeStart' in request.POST and 'cardNoRangeEnd' in request.POST:
  1162. lastSetConf.update({'cardNoRangeStart': int(request.POST.get('cardNoRangeStart', 0))})
  1163. lastSetConf.update({'cardNoRangeEnd': int(request.POST.get('cardNoRangeEnd', 0))})
  1164. self.set_IC_card_range(lastSetConf)
  1165. def response_card_status(self, cardNo, balance, status):
  1166. data = 'EE1123{}'.format(make_six_bytes_session_id()) + fill_2_hexByte(hex(int(cardNo)), 4) + fill_2_hexByte(
  1167. hex(int(balance * 10)), 4) + 'AA33' + status
  1168. devInfo = MessageSender.send(self.device, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC,
  1169. {'IMEI': self._device['devNo'], "funCode": '23', 'data': data})
  1170. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  1171. if devInfo['rst'] == -1:
  1172. raise ServiceException(
  1173. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1174. elif devInfo['rst'] == 1: # 等于1的时候,说明服务器和远程模块通讯OK,响应已经收到,不需要异常处理
  1175. raise ServiceException(
  1176. {'result': 2, 'description': u'充电桩没有响应,可能是版本不对或者串口接线不良'})
  1177. resultData = devInfo['data']
  1178. if resultData[4:6] != '23':
  1179. return {'status': '00'}
  1180. backCardNo = int(resultData[18:26], 16)
  1181. if backCardNo != int(cardNo):
  1182. return {'status': '00'}
  1183. return {'status': resultData[26:28]}
  1184. def set_consume_module(self, infoDict):
  1185. """
  1186. 设置消费模式以及消费流程
  1187. 包含两个参数 consumeProcess 消费流程 consumeModule 消费方式
  1188. :param infoDict:
  1189. :return:
  1190. """
  1191. consumeProcess = infoDict.get("consumeProcess", 0)
  1192. consumeModule = infoDict.get("consumeModule", 0)
  1193. consumeProcessHex = fill_2_hexByte(hex(int(consumeProcess)), 2)
  1194. consumeModuleHex = fill_2_hexByte(hex(int(consumeModule)), 2)
  1195. result = MessageSender.send(
  1196. device=self.device,
  1197. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  1198. payload={
  1199. "IMEI": self._device["devNo"],
  1200. "funCode": "38",
  1201. "data": consumeProcessHex + consumeModuleHex
  1202. }
  1203. )
  1204. rst = result.get("rst")
  1205. data = result.get("data")
  1206. if rst == 0 and data[-4:-2] == "01":
  1207. # OtherConf中也保留一份 方便启动的时候随时查询
  1208. otherConf = self._device.get("otherConf", dict())
  1209. otherConf.update({
  1210. "consumeProcess": int(consumeProcess),
  1211. "consumeModule": int(consumeModule)
  1212. })
  1213. Device.objects.filter(devNo=self._device["devNo"]).update(otherConf=otherConf)
  1214. Device.invalid_device_cache(self._device["devNo"])
  1215. return
  1216. elif data[-4: -2] != "01":
  1217. raise ServiceException({'result': 2, 'description': u'设置失败,请重新试试'})
  1218. elif rst == -1:
  1219. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1220. elif rst == 1:
  1221. raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  1222. else:
  1223. raise ServiceException({'result': 2, 'description': u'未知错误'})
  1224. def reboot_device(self):
  1225. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  1226. {'IMEI': self._device['devNo'], "funCode": '40', 'data': '00'})
  1227. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  1228. if devInfo['rst'] == -1:
  1229. raise ServiceException(
  1230. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1231. elif devInfo['rst'] == 1:
  1232. raise ServiceException(
  1233. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  1234. # 查询设备温度 烟雾报警器状态 设备电压
  1235. def get_sensor_status(self):
  1236. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  1237. {'IMEI': self._device['devNo'], "funCode": '35', 'data': '00'})
  1238. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  1239. if devInfo['rst'] == -1:
  1240. raise ServiceException(
  1241. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1242. elif devInfo['rst'] == 1:
  1243. raise ServiceException(
  1244. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  1245. temperature = '%s' % int(devInfo['data'][18:20], 16)
  1246. smoke = '%s' % int(devInfo['data'][20:22], 16)
  1247. voltage = '%s' % int(devInfo['data'][22:26], 16)
  1248. isYangan = True if smoke == '1' else False
  1249. return {'temperature': temperature, 'isYangan': isYangan, 'voltage': voltage}
  1250. # 查看版本
  1251. def get_versions(self):
  1252. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  1253. {'IMEI': self._device['devNo'], "funCode": '2B', 'data': '00'})
  1254. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  1255. if devInfo['rst'] == -1:
  1256. raise ServiceException(
  1257. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1258. elif devInfo['rst'] == 1:
  1259. raise ServiceException(
  1260. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  1261. data = devInfo['data'][20:-2]
  1262. import re
  1263. data = re.findall(r'..', data)
  1264. data = map(lambda x: chr(int(x, 16)), data)
  1265. versions = ''.join(data)
  1266. return {'versions': versions}
  1267. # 浮充功率,浮充时间,充电检测时间
  1268. def set_float_charge_settings(self, infoDict):
  1269. fuchongPower = infoDict.get('fuchongPower', None)
  1270. fuchongTime = infoDict.get('fuchongTime', None)
  1271. noPowerTime = infoDict.get('noPowerTime', None)
  1272. if not fuchongPower or not fuchongTime or not noPowerTime:
  1273. raise ServiceException({'result': 2, 'description': u'参数不完整'})
  1274. if float(fuchongTime) < 120:
  1275. raise ServiceException({'result': 2, 'description': u'浮充检测时间最小值为120'})
  1276. if float(fuchongPower) < 0 or float(fuchongPower) > 99:
  1277. raise ServiceException({'result': 2, 'description': u'浮充功率检为0-99W'})
  1278. if float(noPowerTime) < 5 or float(noPowerTime) > 999:
  1279. raise ServiceException({'result': 2, 'description': u'充电拔出检测时间未5-999秒'})
  1280. floatPowerHex = fill_2_hexByte(hex(int(fuchongPower) * 10), 4)
  1281. floatTimeHex = fill_2_hexByte(hex(int(fuchongTime)), 4)
  1282. noPowerTimeHex = fill_2_hexByte(hex(int(noPowerTime)), 4)
  1283. result = MessageSender.send(
  1284. device=self.device,
  1285. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  1286. payload={
  1287. "IMEI": self._device["devNo"],
  1288. "funCode": "37",
  1289. "data": floatPowerHex + floatTimeHex + noPowerTimeHex
  1290. }
  1291. )
  1292. rst = result.get("rst")
  1293. data = result.get("data")
  1294. if rst == 0 and data[-4:-2] == "01":
  1295. dev = Device.objects.get(devNo=self._device['devNo'])
  1296. dev.otherConf.update({'fuchongPower': fuchongPower})
  1297. dev.otherConf.update({'fuchongTime': fuchongTime})
  1298. dev.otherConf.update({'noPowerTime': noPowerTime})
  1299. dev.save()
  1300. return
  1301. elif data[-4: -2] != "01":
  1302. raise ServiceException({'result': 2, 'description': u'设置失败,请重新试试'})
  1303. elif rst == -1:
  1304. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1305. elif rst == 1:
  1306. raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  1307. else:
  1308. raise ServiceException({'result': 2, 'description': u'未知错误'})
  1309. # 设置温度阀值
  1310. def set_warning_temperature(self, infoDict):
  1311. temperatureMaxSwitch = infoDict.get('temperatureMaxSwitch')
  1312. if temperatureMaxSwitch == 0:
  1313. temperatureMax = 255
  1314. else:
  1315. temperatureMax = infoDict.get('temperatureMax', 60)
  1316. if float(temperatureMax) < 0 or float(temperatureMax) > 254:
  1317. raise ServiceException({'result': 2, 'description': u'报警温度范围为0-254'})
  1318. temperatureHex = fill_2_hexByte(hex(int(temperatureMax)), 2)
  1319. result = MessageSender.send(
  1320. device=self.device,
  1321. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  1322. payload={
  1323. "IMEI": self._device["devNo"],
  1324. "funCode": "43",
  1325. "data": temperatureHex
  1326. }
  1327. )
  1328. rst = result.get("rst")
  1329. data = result.get("data")
  1330. if rst == 0 and data[-4:-2] == "01":
  1331. return
  1332. elif data[-4: -2] != "01":
  1333. raise ServiceException({'result': 2, 'description': u'设置失败,请重新试试'})
  1334. elif rst == -1:
  1335. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1336. elif rst == 1:
  1337. raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  1338. else:
  1339. raise ServiceException({'result': 2, 'description': u'未知错误'})
  1340. # 设置3档计费功率、比例
  1341. def set_power_level(self, infoDict):
  1342. power1 = infoDict.get('power1')
  1343. power1ratio = infoDict.get('power1ratio')
  1344. power2 = infoDict.get('power2')
  1345. power2ratio = infoDict.get('power2ratio')
  1346. power3 = infoDict.get('power3')
  1347. if float(power1) < 0 or float(power2) < float(power1) or float(power3) < float(power2):
  1348. raise ServiceException({'result': 2, 'description': u'功率参数填写错误'})
  1349. power1Hex = fill_2_hexByte(hex(int(power1)), 4)
  1350. power1ratioHex = fill_2_hexByte(hex(int(power1ratio)), 2)
  1351. power2Hex = fill_2_hexByte(hex(int(power2)), 4)
  1352. power2ratioHex = fill_2_hexByte(hex(int(power2ratio)), 2)
  1353. power3Hex = fill_2_hexByte(hex(int(power3)), 4)
  1354. result = MessageSender.send(
  1355. device=self.device,
  1356. cmd=DeviceCmdCode.OPERATE_DEV_SYNC,
  1357. payload={
  1358. "IMEI": self._device["devNo"],
  1359. "funCode": "45",
  1360. "data": power1Hex + power1ratioHex + power2Hex + power2ratioHex + power3Hex
  1361. }
  1362. )
  1363. rst = result.get("rst")
  1364. data = result.get("data")
  1365. if rst == 0 and data[-4:-2] == "01":
  1366. return
  1367. elif data[-4: -2] != "01":
  1368. raise ServiceException({'result': 2, 'description': u'设置失败,请重新试试'})
  1369. elif rst == -1:
  1370. raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1371. elif rst == 1:
  1372. raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试'})
  1373. else:
  1374. raise ServiceException({'result': 2, 'description': u'未知错误'})
  1375. # 进入升级模式 ## 禁用
  1376. def set_update_model(self):
  1377. devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,
  1378. {'IMEI': self._device['devNo'], "funCode": '26', 'data': '01'})
  1379. if devInfo.has_key('rst') and devInfo['rst'] != 0:
  1380. if devInfo['rst'] == -1:
  1381. raise ServiceException(
  1382. {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
  1383. elif devInfo['rst'] == 1:
  1384. raise ServiceException(
  1385. {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
  1386. data = devInfo['data'][18:]
  1387. print data
  1388. verNum = data[:4]
  1389. updateStatus = data[4:]
  1390. return {'verNum': verNum, 'updateStatus': updateStatus}
  1391. def format_upload_power(self, power):
  1392. return float(power / 10)
  1393. def get_server_setting(self):
  1394. if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHARGING_DIANCHUAN_HIGH:
  1395. default_refund_protection_time = 3
  1396. else:
  1397. default_refund_protection_time = 5
  1398. return {
  1399. 'refundProtectionTime': int(
  1400. self.device.get_other_conf_item('refundProtectionTime', default_refund_protection_time)),
  1401. }
  1402. def set_server_setting(self, payload):
  1403. refundProtectionTime = int(payload['refundProtectionTime'])
  1404. self.device.update_other_conf(refundProtectionTime=refundProtectionTime)