gaoborui.py 83 KB

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