123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910 |
- # -*- coding: utf-8 -*-
- # !/usr/bin/env python
- import datetime
- import logging
- import time
- from decimal import Decimal
- from django.core.cache import caches
- from apilib.utils_datetime import timestamp_to_dt
- from apps.web.agent.models import Agent
- from apps.web.constant import MQTT_TIMEOUT, DeviceCmdCode, Const, ErrorCode
- from apps.web.core.adapter.base import SmartBox, fill_2_hexByte
- from apps.web.core.exceptions import ServiceException
- from apps.web.core.networking import MessageSender
- from apps.web.dealer.models import Dealer
- from apps.web.device.models import Device, Group, DeviceType
- from apilib.monetary import RMB
- from apps.web.core.device_define.jndz import CMD_CODE
-
- logger = logging.getLogger(__name__)
-
- class ChargingAnxinBox(SmartBox):
- def __init__(self, device):
- super(ChargingAnxinBox, self).__init__(device)
- def translate_funcode(self, funCode):
- funCodeDict = {
- '01': u'获取端口数量',
- '02': u'获取端口数据',
- '14': u'移动支付',
- '07': u'获取刷卡投币统计数据',
- '15': u'获取设备端口详情',
- '0F': u'获取端口状态',
- '0C': u'端口锁操作',
- '0D': u'端口开关',
- '1E': u'获取设备设置',
- '18': u'设置设备参数',
- '10': u'回复卡余额',
- }
- return funCodeDict.get(funCode, '')
- def translate_event_cmdcode(self, cmdCode):
- cmdDict = {
- '06': u'充电结束',
- '16': u'充电结束',
- '0A': u'故障',
- '10': u'刷卡上报',
- '20': u'启动设备',
- }
- return cmdDict.get(cmdCode, '')
- def test(self, coins):
- hexPort = fill_2_hexByte(1, 2)
- hexCoins = fill_2_hexByte(hex(1))
- hexTime = fill_2_hexByte(hex(60))
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'],
- "funCode": '14',
- 'data': hexPort + hexCoins + hexTime
- })
- return devInfo
- def stop(self, port = None):
- infoDict = self.stop_charging_port(port)
- infoDict['remainder_time'] = infoDict['leftTime']
- return infoDict
- def start_device(self, package, openId, attachParas):
- if attachParas is None:
- raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'})
- if not attachParas.has_key('chargeIndex'):
- raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'})
- devConf = caches['devmgr'].get('settingConf_%s' % (self._device['devNo']))
- if devConf is None:
- conf = self.get_dev_setting()
- caches['devmgr'].set('settingConf_%s' % (self._device['devNo']), conf, 24 * 3600)
- coinElec = conf['coinElec']
- refundProtection = conf.get('refundProtection', 0)
- else:
- coinElec = devConf['coinElec']
- refundProtection = devConf.get('refundProtection', 0)
- price = float(package['price'])
- port = hex(int(attachParas['chargeIndex']))
- hexPort = fill_2_hexByte(port, 2)
- coins = float(package['coins'])
- hexCoins = fill_2_hexByte(hex(int(coins * 10))) # 注意单位是角
- needElec = round((coins * coinElec) / 10.0, 2) # 单位是0.01度电(配置中每次投币的最大用电量单位却是0.1度电,这里要乘以10)
- hexElec = fill_2_hexByte(hex(int(needElec * 100)), 4)
- unit = package.get('unit', u'分钟')
- needTime = int(package['time'])
- if unit in [u'分钟', u'小时', u'天']:
- billingType = 'time'
- if unit == u'小时':
- needTime = int(package['time']) * 60
- elif unit == u'天':
- needTime = int(package['time']) * 1440
- hexTime = fill_2_hexByte(hex(needTime))
- elif unit == u'度':
- billingType = 'elec'
- needElec = round((package['time']), 2)
- hexElec = fill_2_hexByte(hex(int(needElec * 100)), 4)
- hexTime = fill_2_hexByte(hex(12 * 60))
- else:
- billingType = 'elec'
- devObj = Device.objects.get(devNo = self._device['devNo'])
- elecFee = float(devObj.otherConf.get('elecFee', 0.9))
- needElec = round(min(float(coins / elecFee), needElec), 2)
- hexElec = fill_2_hexByte(hex(int(needElec * 100)), 4)
- hexTime = fill_2_hexByte(hex(12 * 60))
- # 在启动设备前,如果可能是续充,需要获取下设备端口状态,便于后面核实。防止结束报文丢包导致数据不准确
- # 重新把设备上的状态取回来,可以保证needTime数据不出错,正在服务显示也不会有问题
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- lastPortInfo = ctrInfo.get(str(attachParas['chargeIndex']), None)
- if (lastPortInfo is not None) and lastPortInfo.get('status', '') == Const.DEV_WORK_STATUS_WORKING:
- self.get_port_status_from_dev()
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'],
- "funCode": '14',
- 'data': hexPort + hexCoins + hexTime + hexElec
- }, timeout = MQTT_TIMEOUT.START_DEVICE)
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {
- 'result': 2,
- 'description': u'充电桩正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦'
- }
- )
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {
- 'result': 2,
- 'description': u'充电桩正在忙,无响应,您的金币还在,请试试其他线路,或者请稍后再试哦'
- }
- )
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'获取端口数据失败,请重试看能否解决'})
- usePort = int(attachParas['chargeIndex'])
- result = data[4:6]
- if result == '01': # 成功
- pass
- elif result == '0B':
- newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'充电站故障'}}
- Device.update_dev_control_cache(self._device['devNo'], newValue)
- raise ServiceException({'result': 2, 'description': u'充电站故障'})
- elif result == '0C':
- newValue = {str(usePort): {'status': Const.DEV_WORK_STATUS_WORKING, 'statusInfo': u''}}
- Device.update_dev_control_cache(self._device['devNo'], newValue)
- raise ServiceException({'result': 2, 'description': u'该端口正在使用中'})
- start_ts = int(time.time())
- portDict = {
- 'startTime': timestamp_to_dt(start_ts).strftime('%Y-%m-%d %H:%M:%S'),
- 'status': Const.DEV_WORK_STATUS_WORKING,
- 'coins': float(coins),
- 'isStart': True,
- 'price': price,
- 'openId': openId,
- 'refunded': False,
- 'billingType': billingType,
- 'refundProtection': refundProtection,
- 'vCardId': self._vcard_id
- }
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- lastPortInfo = ctrInfo.get(str(usePort), None)
- if lastPortInfo is not None and lastPortInfo.get('status', '') == Const.DEV_WORK_STATUS_WORKING:
- if lastPortInfo.has_key('coins'):
- portDict['coins'] = float(coins) + lastPortInfo['coins']
- if lastPortInfo.has_key('price'):
- portDict['price'] = price + lastPortInfo['price']
- if unit in [u'分钟', u'小时', u'天']:
- portDict.update({'needTime': needTime, 'needElec': needElec})
- if (lastPortInfo is not None) and lastPortInfo.get('status', '') == Const.DEV_WORK_STATUS_WORKING:
- if lastPortInfo.has_key('needTime'):
- portDict['needTime'] = needTime + lastPortInfo['needTime']
- if lastPortInfo.has_key('needElec'):
- portDict['needElec'] = needElec + lastPortInfo['needElec']
- finishedTime = start_ts + portDict['needTime'] * 60
- else:
- portDict.update({'needElec': needElec})
- if (lastPortInfo is not None) and lastPortInfo.has_key('needElec') and lastPortInfo.get('status','') == Const.DEV_WORK_STATUS_WORKING:
- portDict['needElec'] = needElec + lastPortInfo['needElec']
- finishedTime = start_ts + 12 * 60 * 60
- portDict.update({'finishedTime': finishedTime})
- if 'orderNo' in attachParas:
- portDict.update({'orderNo': attachParas['orderNo']})
- Device.update_dev_control_cache(self._device['devNo'], {str(usePort): portDict})
- devInfo['finishedTime'] = finishedTime
- return devInfo
- def get_card_charge_result_from_data(self, data):
- if data[4:6] != '17':
- logger.info('receive wrong card charge result data = %s' % data)
- return False, RMB(0)
- balance = RMB(1) * (int(data[16:20], 16) / 10.0)
- result = True if data[6:8] == '01' and data[22:24] == '01' else False
- return result, balance
- def get_elec_meter(self):
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'], "funCode": '22', 'data': '00'
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- meter = int(data[2:10], 16) / 100.0
- return {'meter': meter}
- def analyze_event_data(self, data):
- cmdCode = data[4:6]
- if cmdCode == CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_06:
- port = int(data[8:10], 16)
- leftTime = int(data[10:14], 16)
- reasonCode = data[14:16]
- desc_map = {
- '00': u'购买的充电时间或电量用完了。',
- '01': u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。',
- '02': u'恭喜您!电池已经充满电!',
- '0B': u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
- }
- return {
- 'status': Const.DEV_WORK_STATUS_IDLE,
- 'cmdCode': cmdCode,
- 'port': port,
- 'leftTime': leftTime,
- 'reason': desc_map[reasonCode],
- 'reasonCode': reasonCode
- }
- #: (高版本的) 提交充电结束状态 (16)
- elif cmdCode == CMD_CODE.DEVICE_SUBMIT_CHARGE_FINISHED_v2_16:
- port = int(data[8:10], 16)
- leftTime = int(data[10:14], 16)
- elec = int(data[14:18], 16) / 100.0
- reasonCode = data[18:20]
- desc_map = {
- '00': u'购买的充电时间或电量用完了。',
- '01': u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。',
- '02': u'恭喜您!电池已经充满电!',
- '03': u'警告!您的电池超功率,已经停止充电,为了公共安全,不建议您在该充电桩充电!提醒您,为了安全大功率的电池不要放入楼道、室内等位置充电哦',
- '04': u'远程断电。',
- '0B': u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。'
- }
- desc = desc_map.get(reasonCode, u'电池没有充满!原因未知。')
- return {
- 'status': Const.DEV_WORK_STATUS_IDLE,
- 'cmdCode': cmdCode,
- 'port': port,
- 'leftTime': leftTime,
- 'elec': elec,
- 'reason': desc,
- 'reasonCode': reasonCode
- }
- #: 上传设备故障
- elif cmdCode == CMD_CODE.DEVICE_SUBMIT_DEVICE_FAULT_0A:
- port = int(data[8:10], 16)
- errCode = int(data[10:14], 16)
- return {
- 'status': Const.DEV_WORK_STATUS_FAULT,
- 'statusInfo': u'设备故障',
- 'cmdCode': cmdCode,
- 'port': port,
- 'FaultCode': errCode
- }
- # 用户刷卡上报的信息
- #: 在线卡上传卡号,预扣费
- #: 示例:
- #: CARD_ID CARD_CST CARD_OPE
- #: 0x00000000 0x00 0x00
- #: 参数
- #: CARD_ID : IC 卡卡号
- #: CARD_SURP: 卡片需要改变的金额信息(以角为单位)
- #: CARD_OPE: 0x00 是扣费(减少),0x01 是充值(增加)。
- #: 回复
- #: RES: 0x00,表示扣费成功,0x01 表示余额不足,0x02 表示非法卡。
- #: CARD_SURP: 表示卡余额(以角为单位)。
- elif cmdCode == CMD_CODE.SWIPE_CARD_10:
- group = Group.get_group(self._device['groupId'])
- dealer = Dealer.get_dealer(group['ownerId'])
- agent = Agent.objects(id=dealer['agentId']).first()
- device = Device.objects(devNo=self._device['devNo']).first()
- devType = DeviceType.objects(id=device['devType']['id']).first()
- cardNo = str(int(data[8:16], 16))
- # 兼容以前的老代码, 先走以前的老代码, 如果有新代码再走新的.
- if agent is not None and 'cardNoReverse' in agent.features:
- cardData = data[14:16] + data[12:14] + data[10:12] + data[8:10]
- cardNo = str(int(cardData, 16))
- if 'cardNoReverse' in devType.features:
- if devType.features['cardNoReverse'] is True:
- cardData = data[14:16] + data[12:14] + data[10:12] + data[8:10]
- cardNo = str(int(cardData, 16))
- else:
- cardNo = str(int(data[8:16], 16))
- else:
- pass
- #: 卡里的余额,以角为单位
- preFee = int(data[16:18], 16) / 10.0
- #: 操作符 00(增加) | 01(减少)
- oper = data[18:20]
- return {'cardNo': cardNo, 'preFee': preFee, 'cmdCode': cmdCode, 'oper': oper}
- #: 上报投币打开的信息
- elif cmdCode == CMD_CODE.DEVICE_SUBMIT_OFFLINE_COINS_20: # 启动设备
- port = int(data[8:10], 16)
- needTime = int(data[10:14], 16)
- elec = int(data[14:18], 16) / 100.0
- consumeTypeTemp = data[18:20]
- if consumeTypeTemp == '00':
- consumeType = 'coin'
- elif consumeTypeTemp == '01':
- consumeType = 'card'
- elif consumeTypeTemp == '03':
- consumeType = 'server'
- else:
- consumeType = 'other'
- money = int(data[20:22], 16) / 10.0
- return {
- 'cmdCode': cmdCode,
- 'port': port,
- 'needTime': needTime,
- 'elec': elec,
- 'consumeType': consumeType,
- 'coins': money
- }
- elif cmdCode == '11': # IC卡扣费、退费上报事件
- cardNo = str(int(data[8:16], 16))
- preFee = int(data[16:18], 16) / 10.0
- balance = int(data[18:22], 16) / 10.0
- port = int(data[26:28], 16)
- oper = data[28:30]
- return {'cardNo': cardNo, 'preFee': preFee, 'cmdCode': cmdCode, 'balance': balance, 'cardType': 'IC',
- 'port': port, 'oper': oper}
- elif cmdCode == '12': # IC卡圈存
- cardNo = str(int(data[8:16], 16))
- balance = int(data[16:20], 16) * 10.0
- return {'cmdCode': cmdCode, 'balance': balance, 'cardType': 'IC', 'cardNo': cardNo}
- return super(ChargingAnxinBox, self).analyze_event_data(data)
- def get_dev_consume_count(self):
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'], "funCode": '07', 'data': '00'
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
- cardFee = int(data[2:6], 16) / 10.0 # 以角为单位
- coinFee = int(data[6:10], 16) # 以元为单位
- return {'cardFee': cardFee, 'coinFee': coinFee}
- def get_port_info(self, line):
- data = fill_2_hexByte(hex(int(line)), 2)
- devInfo = MessageSender.send(device = self.device,
- cmd = self.make_random_cmdcode(),
- payload = {
- 'IMEI': self._device['devNo'], "funCode": '15', 'data': data
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
- leftTime = int(data[4:8], 16)
- if data[8:12] == 'FFFF':
- power = 0
- else:
- power = int(data[8:12], 16)
- if data[12:16] == 'FFFF':
- elec = 0
- else:
- elec = int(data[12:16], 16)
- if data[16:20] == 'FFFF':
- surp = 0
- else:
- surp = int(data[16:20], 16)
- return {'port': line, 'leftTime': leftTime, 'power': power, 'surp': surp}
- def get_port_status(self, force = False):
- if force:
- return self.get_port_status_from_dev()
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- statusDict = {}
- if not ctrInfo.has_key('allPorts'):
- self.get_port_status_from_dev()
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- allPorts = ctrInfo.get('allPorts', 10)
- for ii in range(allPorts):
- tempDict = ctrInfo.get(str(ii + 1), {})
- if tempDict.has_key('status'):
- statusDict[str(ii + 1)] = {'status': tempDict.get('status')}
- elif tempDict.has_key('isStart'):
- if tempDict['isStart']:
- statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING}
- else:
- statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
- else:
- statusDict[str(ii + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE}
- allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict)
- Device.update_dev_control_cache(self._device['devNo'],
- {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
- return statusDict
- def get_port_status_from_dev(self):
- devInfo = MessageSender.send(device = self.device,
- cmd = self.make_random_cmdcode(),
- payload = {
- 'IMEI': self._device['devNo'], "funCode": '0F', 'data': '00'
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'})
- result = {}
- portNum = int(data[2:4], 16)
- portData = data[4::]
- ii = 0
- while ii < portNum:
- port = int(portData[ii * 4:ii * 4 + 2], 16)
- statusTemp = portData[ii * 4 + 2:ii * 4 + 4]
- if statusTemp == '01':
- status = {'status': Const.DEV_WORK_STATUS_IDLE}
- elif statusTemp == '02':
- status = {'status': Const.DEV_WORK_STATUS_WORKING}
- elif statusTemp == '03':
- status = {'status': Const.DEV_WORK_STATUS_FORBIDDEN}
- elif statusTemp == '04':
- status = {'status': Const.DEV_WORK_STATUS_FAULT}
- ii += 1
- result[str(port)] = status
- allPorts, usedPorts, usePorts = self.get_port_static_info(result)
- Device.update_dev_control_cache(self._device['devNo'],
- {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts})
- # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存
- ctrInfo = Device.get_dev_control_cache(self._device['devNo'])
- for strPort, info in result.items():
- if ctrInfo.has_key(strPort):
- ctrInfo[strPort].update({'status': info['status']})
- else:
- ctrInfo[strPort] = info
- Device.update_dev_control_cache(self._device['devNo'], ctrInfo)
- return result
- def lock_unlock_port(self, port, lock = True):
- lockStr = '00' if lock else '01'
- portStr = fill_2_hexByte(hex(int(port)), 2)
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'],
- "funCode": '0C',
- 'data': portStr + lockStr
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
- if lock:
- Device.update_dev_control_cache(self._device['devNo'],
- {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}})
- else:
- Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}})
- def active_deactive_port(self, port, active):
- if not active:
- self.stop_charging_port(port)
- devInfo = Device.get_dev_control_cache(self._device['devNo'])
- portCtrInfo = devInfo.get(str(port), {})
- portCtrInfo.update({'isStart': False, 'status': Const.DEV_WORK_STATUS_IDLE,
- 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)})
- newValue = {str(port): portCtrInfo}
- Device.update_dev_control_cache(self._device['devNo'], newValue)
- else:
- raise ServiceException({'result': 2, 'description': u'此设备不支持直接打开端口'})
- def stop_charging_port(self, port):
- portStr = fill_2_hexByte(hex(int(port)), 2)
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'], "funCode": '0D', 'data': portStr + '00'
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
- port = int(data[2:4], 16)
- leftTime = int(data[4:8], 16)
- return {'port': port, 'leftTime': leftTime}
- def get_dev_setting(self):
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'], "funCode": '1E', 'data': '00'
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- pass
- else:
- raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
- confData = data[2:-2]
- coinMin = int(confData[0:4], 16)
- cardMin = int(confData[4:8], 16)
- coinElec = int(confData[8:10], 16)
- cardElec = int(confData[10:12], 16)
- cst = int(confData[12:14], 16)
- powerMax1 = int(confData[14:18], 16)
- powerMax2 = int(confData[18:22], 16)
- powerMax3 = int(confData[22:26], 16)
- powerMax4 = int(confData[26:30], 16)
- power2Ti = int(confData[30:32], 16)
- power3Ti = int(confData[32:34], 16)
- power4Ti = int(confData[34:36], 16)
- spRecMon = int(confData[36:38], 16)
- spFullEmpty = int(confData[38:40], 16)
- fullPowerMin = int(confData[40:42], 16)
- fullChargeTime = int(confData[42:44], 16)
- elecTimeFirst = int(confData[44:46], 16)
- dev = Device.objects.get(devNo = self._device['devNo'])
- billingType = dev.otherConf.get('billingType', 'time')
- elecFee = dev.otherConf.get('elecFee', 0.9)
- refundProtection = dev.otherConf.get('refundProtection', 0)
- resultDict = {
- 'coinMin': coinMin,
- 'cardMin': cardMin,
- 'coinElec': coinElec,
- 'cardElec': cardElec,
- 'cst': cst,
- 'powerMax1': powerMax1,
- 'powerMax2': powerMax2,
- 'powerMax3': powerMax3,
- 'powerMax4': powerMax4,
- 'power2Ti': power2Ti,
- 'power3Ti': power3Ti,
- 'power4Ti': power4Ti,
- 'spRecMon': spRecMon,
- 'spFullEmpty': spFullEmpty,
- 'fullPowerMin': fullPowerMin,
- 'fullChargeTime': fullChargeTime,
- 'elecTimeFirst': elecTimeFirst,
- 'billingType': billingType,
- 'elecFee': elecFee,
- 'refundProtection': refundProtection
- }
- consumeInfo = self.get_dev_consume_count()
- resultDict.update(consumeInfo)
- return resultDict
- # 设置设备配置参数
- def set_dev_setting(self, setConf):
- data = ''
- data += fill_2_hexByte(hex(int(setConf['coinMin'])), 4)
- data += fill_2_hexByte(hex(int(setConf['cardMin'])), 4)
- data += fill_2_hexByte(hex(int(setConf['coinElec'])), 2)
- data += fill_2_hexByte(hex(int(setConf['cardElec'])), 2)
- data += fill_2_hexByte(hex(int(setConf['cst'])), 2)
- data += fill_2_hexByte(hex(int(setConf['powerMax1'])), 4)
- data += fill_2_hexByte(hex(int(setConf['powerMax2'])), 4)
- data += fill_2_hexByte(hex(int(setConf['powerMax3'])), 4)
- data += fill_2_hexByte(hex(int(setConf['powerMax4'])), 4)
- data += fill_2_hexByte(hex(int(setConf['power2Ti'])), 2)
- data += fill_2_hexByte(hex(int(setConf['power3Ti'])), 2)
- data += fill_2_hexByte(hex(int(setConf['power4Ti'])), 2)
- data += fill_2_hexByte(hex(int(setConf['spRecMon'])), 2)
- data += fill_2_hexByte(hex(int(setConf['spFullEmpty'])), 2)
- data += fill_2_hexByte(hex(int(setConf['fullPowerMin'])), 2)
- data += fill_2_hexByte(hex(int(setConf['fullChargeTime'])), 2)
- data += fill_2_hexByte(hex(int(setConf['elecTimeFirst'])), 2)
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'], "funCode": '18', 'data': data
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'})
- data = devInfo['data'][6::]
- if data[0:2] == '01': # 表示成功
- dev = Device.objects.get(devNo = self._device['devNo'])
- dev.otherConf.update({'billingType': setConf['billingType']})
- dev.otherConf.update({'elecFee': setConf['elecFee']})
- dev.otherConf.update({'refundProtection': setConf['refundProtection']})
- dev.save()
- else:
- raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'})
- def response_use_card(self, res, balance):
- data = '55061001'
- data = data + res + fill_2_hexByte(hex(int(balance * 10)), 4)
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE,
- payload = {
- 'IMEI': self._device['devNo'], "funCode": '10', 'data': data
- })
- if devInfo.has_key('rst') and devInfo['rst'] != 0:
- if devInfo['rst'] == -1:
- raise ServiceException(
- {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'})
- elif devInfo['rst'] == 1: # 等于1的时候,说明服务器和远程模块通讯OK,响应已经收到,不需要异常处理
- pass
- def set_device_function_param(self, request, lastSetConf):
- coinMin = request.POST.get('coinMin', None)
- cardMin = request.POST.get('cardMin', None)
- coinElec = request.POST.get('coinElec', None)
- cardElec = request.POST.get('cardElec', None)
- cst = request.POST.get('cst', None)
- powerMax1 = request.POST.get('powerMax1', None)
- powerMax2 = request.POST.get('powerMax2', None)
- powerMax3 = request.POST.get('powerMax3', None)
- powerMax4 = request.POST.get('powerMax4', None)
- power2Ti = request.POST.get('power2Ti', None)
- power3Ti = request.POST.get('power3Ti', None)
- power4Ti = request.POST.get('power4Ti', None)
- spRecMon = request.POST.get('spRecMon', None)
- spFullEmpty = request.POST.get('spFullEmpty', None)
- fullPowerMin = request.POST.get('fullPowerMin', None)
- fullChargeTime = request.POST.get('fullChargeTime', None)
- elecTimeFirst = request.POST.get('elecTimeFirst', None)
- billingType = request.POST.get('billingType', 'time')
- elecFee = request.POST.get('elecFee', 0.9)
- refundProtection = request.POST.get('refundProtection', None)
- # 这几个参数是墨小智V3特有的
- stWTime = request.POST.get('stWTime', None)
- temThre = request.POST.get('temThre', None)
- freeUse = request.POST.get('freeUse', None)
- if coinMin:
- lastSetConf.update({'coinMin': int(coinMin)})
- if cardMin:
- lastSetConf.update({'cardMin': int(cardMin)})
- if coinElec:
- lastSetConf.update({'coinElec': int(coinElec)})
- if cardElec:
- lastSetConf.update({'cardElec': int(cardElec)})
- if cst:
- lastSetConf.update({'cst': int(cst)})
- if powerMax1:
- lastSetConf.update({'powerMax1': int(powerMax1)})
- if powerMax2:
- lastSetConf.update({'powerMax2': int(powerMax2)})
- if powerMax3:
- lastSetConf.update({'powerMax3': int(powerMax3)})
- if powerMax4:
- lastSetConf.update({'powerMax4': int(powerMax4)})
- if power2Ti:
- lastSetConf.update({'power2Ti': int(power2Ti)})
- if power3Ti:
- lastSetConf.update({'power3Ti': int(power3Ti)})
- if power4Ti:
- lastSetConf.update({'power4Ti': int(power4Ti)})
- if spRecMon:
- lastSetConf.update({'spRecMon': int(spRecMon)})
- if spFullEmpty:
- lastSetConf.update({'spFullEmpty': int(spFullEmpty)})
- if fullPowerMin:
- lastSetConf.update({'fullPowerMin': int(fullPowerMin)})
- if fullChargeTime:
- lastSetConf.update({'fullChargeTime': int(fullChargeTime)})
- if elecTimeFirst:
- lastSetConf.update({'elecTimeFirst': int(elecTimeFirst)})
- if billingType:
- lastSetConf.update({'billingType': billingType})
- if elecFee:
- lastSetConf.update({'elecFee': elecFee})
- if refundProtection:
- lastSetConf.update({'refundProtection': int(refundProtection)})
- # 这几个参数是墨小智V3特有的
- if stWTime:
- lastSetConf.update({'stWTime': int(stWTime)})
- if temThre:
- lastSetConf.update({'temThre': int(temThre)})
- if freeUse:
- lastSetConf.update({'freeUse': int(freeUse)})
- self.set_dev_setting(lastSetConf)
- # 给实体卡充值
- def recharge_card(self, cardNo, money, orderNo = None):
- try:
- data = '550B1201'
- cardNo = fill_2_hexByte(hex(int(cardNo)), 8)
- data = data + cardNo + fill_2_hexByte(hex(int(money * 10)), 4) + '00CC'
- devInfo = MessageSender.send(device = self.device,
- cmd = DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_SYNC,
- payload = {
- 'IMEI': self._device['devNo'], 'data': data, 'funCode': '12'
- },
- timeout = MQTT_TIMEOUT.LONGEST)
- if devInfo['rst'] != 0:
- if devInfo['rst'] == ErrorCode.DEVICE_CONN_FAIL:
- # 离线无法判断是否成功, 认为充值成功, 走售后解决
- return {
- 'result': ErrorCode.DEVICE_CONN_FAIL,
- 'description': u'当前充电桩正在玩命找网络,请您稍候再试'
- }, None
- elif devInfo['rst'] == ErrorCode.BOARD_UART_TIMEOUT:
- return {
- 'result': ErrorCode.BOARD_UART_TIMEOUT,
- 'description': u'当前充电桩忙,无响应,请您稍候再试'
- }, None
- else:
- return {
- 'result': devInfo['rst'],
- 'description': u'系统异常'
- }, None
- resultData = devInfo['data']
- if resultData[4:6] != '17':
- return {
- 'result': ErrorCode.PARAMETER_ERROR_TO_BOX,
- 'description': u'充值返回报文命令码不为17'
- }, None
- balance = RMB(int(resultData[16:20], 16)) * Decimal('0.1')
- if resultData[6:8] == '01' and resultData[22:24] == '01':
- return {
- 'result': ErrorCode.SUCCESS,
- 'description': ''
- }, balance
- else:
- return {
- 'result': ErrorCode.IC_RECHARGE_FAIL,
- 'description': u'充值失败'
- }, None
- except Exception as e:
- logger.exception(e)
- return {
- 'result': ErrorCode.EXCEPTION,
- 'description': e.message
- }, None
- def apiGetPortStatusFromAx(self, record):
- return self.get_port_status_from_dev()
- def apiStopAxPort(self, record):
- portStr = record['chargeIndex']
- return self.stop_charging_port(portStr)
- @property
- def isHaveStopEvent(self):
- return True
|