# -*- 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