# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging import random import time from typing import TYPE_CHECKING from apilib.utils_datetime import timestamp_to_dt from apilib.utils_string import cn from apps.web.constant import DeviceCmdCode, Const, ErrorCode, MQTT_TIMEOUT, DeviceErrorCodeDesc from apps.web.core.adapter.base import SmartBox, fill_2_hexByte, start_error_timer from apps.web.core.exceptions import ServiceException from apps.web.core.networking import MessageSender from apps.web.device.models import Device, GroupDict if TYPE_CHECKING: pass logger = logging.getLogger(__name__) class ChargingYUNCHONGBox(SmartBox): """ 协议格式和电川一致, 功能少很多 """ def __init__(self, device): super(ChargingYUNCHONGBox, self).__init__(device) def _check_package(self, package): """ 获取设备启动的发送数据 根据设备的当前模式以及套餐获取 :param package: :return: """ unit = package.get('unit', u'分钟') needTime = int(package['time']) if unit in [u'分钟', u'小时', u'天', u'秒']: billingType = 'time' if unit == u'小时': needTime = int(package['time']) * 60 elif unit == u'天': needTime = int(package['time']) * 1440 elif unit == u'秒': needTime = int(package['time']) / 60 hexTime = fill_2_hexByte(hex(needTime), 4) else: raise ServiceException( { 'result': 2, 'description': u'充电桩只支持按时间计费的方式,不支持其他方式' } ) return needTime, unit, billingType def translate_funcode(self, funCode): funCodeDict = { '01': u'获取端口数量', '02': u'用户付款', '06': u'获取端口状态', '07': u'查询消费总额数据', '08': u'IC卡、投币、最大功率设置', '09': u'设置IC卡、投币器是否可用', '0A': u'锁定、解锁某一个端口', '0B': u'远程停止某个端口的充电', '0C': u'读取设备IC卡、投币、最大功率设置', '0D': u'上传设备故障', '14': u'设置充电站5档计费功率、比例', '15': u'读取设备5档计费功率、比例' } return funCodeDict.get(funCode, '') def translate_event_cmdcode(self, cmdCode): cmdDict = { '03': u'投币上报', '04': u'刷卡上报', '25': u'功率上报', } return cmdDict.get(cmdCode, '') def check_dev_status(self, attachParas=None): """ 如果超过两个心跳周期没有报心跳,并且最后一次更新时间在2个小时内,需要从设备获取状态 否则以缓存状态为准。 :param attachParas: :return: """ if attachParas is None: raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口、电池类型信息'}) if not attachParas.has_key('chargeIndex'): raise ServiceException({'result': 0, 'description': u'请您选择合适的充电端口'}) if not self.device.need_fetch_online: raise ServiceException( {'result': 2, 'description': DeviceErrorCodeDesc.get(ErrorCode.DEVICE_CONN_CHECK_FAIL)}) self.get_port_status_from_dev() group = self.device.group # type: GroupDict if group.is_free: logger.debug('{} is free. no need to check continue pay.'.format(repr(self.device))) return # 处理是否能够续充 portDict = self.get_port_status() port = str(attachParas['chargeIndex']) if port in portDict: isCanAdd = self.device['devType'].get('payableWhileBusy', False) if portDict[port]['status'] == Const.DEV_WORK_STATUS_IDLE: return elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FAULT: raise ServiceException({'result': 0, 'description': u'该端口故障,暂时不能使用'}) elif portDict[port]['status'] == Const.DEV_WORK_STATUS_WORKING: if isCanAdd: return else: raise ServiceException({'result': 0, 'description': u'该端口正在工作不能使用,请您使用其他端口'}) elif portDict[port]['status'] == Const.DEV_WORK_STATUS_FORBIDDEN: raise ServiceException({'result': 0, 'description': u'该端口已被禁止使用,请您使用其他端口'}) elif portDict[port]['status'] == Const.DEV_WORK_STATUS_CONNECTED: return else: raise ServiceException({'result': 0, 'description': u'端口状态未知,暂时不能使用'}) else: raise ServiceException({'result': 0, 'description': u'未知端口,暂时不能使用'}) def test(self, coins): hexPort = fill_2_hexByte(hex(1), 2) hexGear = '00' hexTime = '01' devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '02', 'data': hexPort + hexGear + hexTime}) return devInfo def port_is_busy(self, port_dict): if not port_dict: return False if 'billingType' not in port_dict: return False if 'status' not in port_dict: return False if 'coins' not in port_dict: return False if 'price' not in port_dict: return False if port_dict['billingType'] not in ['time']: return False if port_dict['billingType'] == 'time': if 'needTime' not in port_dict: return False else: return False if port_dict['status'] == Const.DEV_WORK_STATUS_WORKING: return True else: return False @start_error_timer(missMessages=[u"请您选择合适的充电线路、电池类型信息", u"请您选择合适的充电线路", u"该端口正在使用中"]) def start_device(self, package, openId, attachParas): if attachParas is None: raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'}) if 'chargeIndex' not in attachParas: raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'}) price = float(package['price']) coins = float(package['coins']) port = hex(int(attachParas['chargeIndex'])) hexPort = fill_2_hexByte(port, 2) gear = hex(int(attachParas['powerGear'])) hexGear = fill_2_hexByte(gear, 4) unit = package.get('unit', u'分钟') needTime = int(package['time']) if unit in [u'分钟', u'小时', u'天', u'秒']: billingType = 'time' if unit == u'小时': needTime = int(package['time']) * 60 elif unit == u'天': needTime = int(package['time']) * 1440 elif unit == u'秒': needTime = int(package['time']) / 60 hexTime = fill_2_hexByte(hex(needTime), 4) else: raise ServiceException( { 'result': 2, 'description': u'充电桩只支持按时间计费的方式,不支持其他方式' } ) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], "funCode": '02', 'data': hexPort + hexGear + hexTime }, timeout=MQTT_TIMEOUT.START_DEVICE) if devInfo['rst'] != 0: if devInfo['rst'] == -1: raise ServiceException( { 'result': 2, 'description': u'充电桩正在玩命找网络,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦' }) elif devInfo['rst'] == 1: self.check_serial_port_for_startcmd(attachParas['chargeIndex']) else: raise ServiceException( { 'result': 2, 'description': u'充电失败,您的金币还在,重试不需要重新付款,建议您试试旁边其他设备,或者稍后再试哦' }) data = devInfo['data'][18::] usePort = int(attachParas['chargeIndex']) result = data[2:4] if result == '01': # 成功 pass elif result == '02': 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 == '03': 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_timestamp = int(time.time()) portDict = { 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'), 'status': Const.DEV_WORK_STATUS_WORKING, 'coins': float(coins), 'price': price, 'billingType': billingType, 'isStart': True, 'openId': openId, 'refunded': False, 'vCardId': self._vcard_id, 'payInfo': list() } # type: dict ctrInfo = Device.get_dev_control_cache(self.device.devNo) lastPortInfo = ctrInfo.get(str(usePort), {}) is_continus = False if self.port_is_busy(lastPortInfo): if 'cardId' in lastPortInfo and lastPortInfo['cardId']: is_continus = False else: if lastPortInfo.get('billingType') == billingType and lastPortInfo.get('openId') == openId: is_continus = True else: is_continus = False if is_continus: portDict['coins'] = float(coins) + lastPortInfo['coins'] portDict['price'] = float(price) + lastPortInfo['price'] portDict['needTime'] = needTime + lastPortInfo['needTime'] else: portDict['coins'] = float(coins) portDict['price'] = float(price) portDict.update({'needTime': needTime}) if attachParas.get('redpackId'): if is_continus: redpackInfo = lastPortInfo.get("redpackInfo", list()) if not redpackInfo: logger.warning("miss redpackInfo! {}-{}".format(self._device["devNo"], usePort)) else: redpackInfo = list() redpackInfo.append({'redpackId': str(attachParas['redpackId'])}) portDict['redpackInfo'] = redpackInfo else: if is_continus: portDict['redpackInfo'] = lastPortInfo.get("redpackInfo", list()) else: portDict['redpackInfo'] = list() if 'linkedRechargeRecordId' in attachParas and attachParas.get('isQuickPay', False): if is_continus: payInfo = lastPortInfo.get("payInfo", list()) if not payInfo: logger.warning("miss payInfo! {}-{}".format(self._device["devNo"], usePort)) else: payInfo = list() payInfo.append({'rechargeRcdId': str(attachParas['linkedRechargeRecordId'])}) portDict['payInfo'] = payInfo else: if is_continus: portDict['payInfo'] = lastPortInfo.get("payInfo", list()) else: portDict['payInfo'] = list() finishedTime = int(time.time()) + int(portDict['needTime'] * 60) portDict.update({'finishedTime': finishedTime}) if 'orderNo' in attachParas: portDict.update({'orderNo': attachParas['orderNo']}) if 'extOrderNo' in attachParas: portDict.update({'extOrderNo': attachParas['extOrderNo']}) Device.overwrite_port_control_cache(self.device.devNo, str(usePort), portDict) devInfo['finishedTime'] = finishedTime return devInfo def analyze_event_data(self, data): cmdCode = data[4:6] if cmdCode == '05': port = int(data[18:20], 16) leftTime = int(data[20:24], 16) reason = data[24:26] power = int(data[26:30], 16) desc_map = { '00': u'购买的充电时间或电量用完了。', '01': u'可能是插头被拔掉,或者电瓶已经充满。系统判断为异常断电,由于电瓶车充电器种类繁多,可能存在误差。如有问题,请您及时联系商家协助解决问题并恢复充电。', '02': u'恭喜您!电池已经充满电!', '03': u'设备或端口出现问题,为了安全起见,被迫停止工作。建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。', '04': u'充电器功率超过充电站的单路最大输出功率,为了安全,系统强制停止充电。', '05': u'刷卡退费结束。' } return { 'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port, 'leftTime': leftTime, 'power': power, 'reason': desc_map[reason], 'reasonCode': reason } elif cmdCode == '0D': port = int(data[16:18], 16) errCode = data[18:20] if errCode == '01': return {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'端口输出故障', 'cmdCode': cmdCode, 'port': port, 'FaultCode': errCode} elif errCode == '02': return {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'机器整体充电功率过大', 'cmdCode': cmdCode, 'port': port, 'FaultCode': errCode} elif errCode == '03': return {'status': Const.DEV_WORK_STATUS_FAULT, 'statusInfo': u'电源故障', 'cmdCode': cmdCode, 'port': port, 'FaultCode': errCode} elif cmdCode == '28': # 用户刷卡上报的信息 cardNo = data[18:26] cardNo = str(int(cardNo, 16)) preFee = int(data[26:28], 16) / 10.0 port = int(data[28:30], 16) randomCode = int(data[30:38], 16) return {'cardNo': cardNo, 'coins': preFee, 'cmdCode': cmdCode, 'port': port, 'randomCode': randomCode} elif cmdCode == '25': # 充电功率自动上报 port = int(data[8:10], 16) leftTime = int(data[10:14], 16) power = int(data[14:18], 16) return {'cmdCode': cmdCode, 'port': port, 'leftTime': leftTime, 'power': power} elif cmdCode == '26': # 刷卡向模块发送卡号 cardNo = data[18:26] cardNo = str(int(cardNo, 16)) return {'cardNo': cardNo, 'cmdCode': cmdCode} elif cmdCode == '03': # 投币上报 coin = int(data[18:20], 16) return {'cmdCode': cmdCode, 'coins': coin} elif cmdCode == '04': # 刷卡报文 money = int(data[18:20], 16) return {'cmdCode': cmdCode, 'money': money} def get_dev_consume_count(self): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { "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'][16::] 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(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { "funCode": '06', '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'][16::] leftTime = int(data[4:8], 16) if data[8:12] == 'FFFF': power = 0 else: power = int(data[8:12], 16) return {'port': line, 'leftTime': leftTime, 'power': power} def get_port_status_from_dev(self): """ 访问设备,获取设备端口信息 :return: """ devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { "funCode": '01', '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'][16::] result = {} portNum = int(data[2:4], 16) portData = data[4::] ii = 0 while ii < portNum: statusTemp = portData[ii * 2:ii * 2 + 2] 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} elif statusTemp == '05': status = {'status': Const.DEV_WORK_STATUS_FAULT_OVERLOAD} else: status = Const.DEV_WORK_STATUS_IDLE ii += 1 result[str(ii)] = status # 随便把功率配置数据拉上来 gearConf = self.get_gear_conf() allPorts, usedPorts, usePorts = self.get_port_static_info(result) Device.update_dev_control_cache(self._device['devNo'], {'allPorts': allPorts, 'usedPorts': usedPorts, 'usePorts': usePorts, 'gearConf': gearConf}) # 这里存在多线程更新缓存的场景,可能性比较低,但是必须先取出来,然后逐个更新状态,然后再记录缓存 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 get_default_port_nums(self): return 10 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) if 'allPorts' in ctrInfo and ctrInfo['allPorts'] > 0: allPorts = ctrInfo['allPorts'] else: allPorts = self.get_default_port_nums() statusDict = {} 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 lock_unlock_port(self, port, lock=True): lockStr = '00' if lock else '01' portStr = fill_2_hexByte(hex(int(port)), 2) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '0A', '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'][18::] 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 active: raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'}) 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, 'needTime': 0, 'leftTime': 0, 'endTime': datetime.datetime.now().strftime(Const.DATETIME_FMT)}) newValue = {str(port): portCtrInfo} Device.update_dev_control_cache(self._device['devNo'], newValue) def stop_charging_port(self, port): portStr = fill_2_hexByte(hex(int(port)), 2) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '0B', 'data': portStr}) 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'][16::] port = int(data[2:4], 16) return {'port': port} def stop(self, port=None): infoDict = self.stop_charging_port(port) return infoDict @property def isHaveStopEvent(self): return True def response_card_balance(self, cardNo, balance): data = '' data += fill_2_hexByte(hex(int(cardNo)), 8) data += fill_2_hexByte(hex(int(balance) * 10), 4) data += fill_2_hexByte(hex(int(random.randint(0, 1000))), 8) data += '00' devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'], "funCode": '27', '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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) # 获取IC卡、投币、最大功率设置 def get_IC_coin_power_config(self): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '0C', '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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) confData = devInfo['data'][18::] maxPower = int(confData[0:4], 16) icMoney = int(confData[4:6], 16) if len(confData) > 6: time1 = int(confData[6:10], 16) time2 = int(confData[10:14], 16) time3 = int(confData[14:18], 16) time4 = int(confData[18:22], 16) time5 = int(confData[22:26], 16) else: time1, time2, time3, time4, time5 = 0, 0, 0, 0, 0 return {'maxPower': maxPower, 'icMoney': icMoney, 'time1': time1, 'time2': time2, 'time3': time3, 'time4': time4, 'time5': time5} def set_IC_coin_power_config(self, infoDict): data = '' data += fill_2_hexByte(hex(int(infoDict['maxPower'])), 4) data += fill_2_hexByte(hex(int(infoDict['icMoney'])), 2) data += fill_2_hexByte(hex(int(infoDict['time1'])), 4) data += fill_2_hexByte(hex(int(infoDict['time2'])), 4) data += fill_2_hexByte(hex(int(infoDict['time3'])), 4) data += fill_2_hexByte(hex(int(infoDict['time4'])), 4) data += fill_2_hexByte(hex(int(infoDict['time5'])), 4) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '08', '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'充电桩忙,无响应,请您稍候再试'}) def get_coin_card_enable(self): devs = Device.get_collection().find({'devNo': self._device['devNo']}) if devs.count == 0: raise ServiceException( {'result': 2, 'description': u'没有找到设备哦'}) return {'putCoins': devs[0].get('otherConf', {}).get('putCoins', False), 'icCard': devs[0].get('otherConf', {}).get('icCard', False)} def set_coin_card_enable(self, infoDict): data = '' if infoDict['putCoins']: data += '01' else: data += '00' if infoDict['icCard']: data += '01' else: data += '00' devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '09', '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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) try: conf = Device.objects.get(devNo=self._device['devNo']).otherConf conf.update({'putCoins': infoDict['putCoins'], 'icCard': infoDict['icCard']}) Device.get_collection().update_one({'devNo': self._device['devNo']}, {'$set': {'otherConf': conf}}) except Exception, e: logger.error('update dev=%s coin enable ic enable e=%s' % (self._device['devNo'], e)) # 获取设备配置参数 def get_dev_setting(self): resultDict = self.get_IC_coin_power_config() tempDict = self.get_coin_card_enable() resultDict.update(tempDict) tempDict = self.get_gear_conf() resultDict.update(tempDict) resultDict.update(tempDict) return resultDict # 获取设备配置参数 def set_dev_setting(self, setConf): keys = setConf.keys() if 'putCoins' in keys or 'icCard' in keys: self.set_coin_card_enable(setConf) if 'maxPower' in keys or 'icMoney' in keys or 'time1' in keys or 'time2' in keys or 'time3' in keys: self.set_IC_coin_power_config(setConf) def get_gear_conf_from_cache(self): controlCache = Device.get_dev_control_cache(self._device['devNo']) gearConf = controlCache.get('gearConf', None) if gearConf is None: gearConf = self.get_gear_conf() Device.update_dev_control_cache(self._device['devNo'], {'gearConf': gearConf}) return gearConf def get_gear_conf(self): resultDict = {'power1': 0, 'power1ratio': 0, 'power2': 0, 'power2ratio': 0, 'power3': 0, 'power3ratio': 0, 'power4': 0, 'power4ratio': 0, 'power5': 0, 'power5ratio': 0} devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '15', '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: return resultDict confData = devInfo['data'][18::] power1 = int(confData[0:4], 16) power1ratio = int(confData[4:6], 16) power2 = int(confData[6:10], 16) power2ratio = int(confData[10:12], 16) power3 = int(confData[12:16], 16) power3ratio = int(confData[16:18], 16) power4 = int(confData[18:22], 16) power4ratio = int(confData[22:24], 16) power5 = int(confData[24:28], 16) power5ratio = int(confData[28:30], 16) result = { 'power1': power1, 'power1ratio': power1ratio, 'power2': power2, 'power2ratio': power2ratio, 'power3': power3, 'power3ratio': power3ratio, 'power4': power4, 'power4ratio': power4ratio, 'power5': power5, 'power5ratio': power5ratio } return result def set_gear_conf(self, infoDict): data = '' data += fill_2_hexByte(hex(int(infoDict['power1'])), 4) data += fill_2_hexByte(hex(int(infoDict['power1ratio'])), 2) data += fill_2_hexByte(hex(int(infoDict['power2'])), 4) data += fill_2_hexByte(hex(int(infoDict['power2ratio'])), 2) data += fill_2_hexByte(hex(int(infoDict['power3'])), 4) data += fill_2_hexByte(hex(int(infoDict['power3ratio'])), 2) data += fill_2_hexByte(hex(int(infoDict['power4'])), 4) data += fill_2_hexByte(hex(int(infoDict['power4ratio'])), 2) data += fill_2_hexByte(hex(int(infoDict['power5'])), 4) data += fill_2_hexByte(hex(int(infoDict['power5ratio'])), 2) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '14', '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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) def set_device_function(self, request, lastSetConf): if request.POST.has_key('putCoins'): putCoins = request.POST.get("putCoins", False) lastSetConf.update({'putCoins': putCoins}) self.set_coin_card_enable(lastSetConf) if request.POST.has_key('icCard'): # icCard = True if request.POST.get('icCard') == 'true' else False icCard = request.POST.get("icCard", False) lastSetConf.update({'icCard': icCard}) self.set_coin_card_enable(lastSetConf) def set_device_function_param(self, request, lastSetConf): if request.POST.has_key('maxPower') and request.POST.has_key('icMoney'): lastSetConf.update({'maxPower': int(request.POST.get('maxPower', 0))}) lastSetConf.update({'icMoney': int(request.POST.get('icMoney', 0))}) self.set_IC_coin_power_config(lastSetConf) if request.POST.has_key('time1') and request.POST.has_key('time2') and request.POST.has_key('time3'): lastSetConf.update({'time1': int(request.POST.get('time1', 0))}) lastSetConf.update({'time2': int(request.POST.get('time2', 0))}) lastSetConf.update({'time3': int(request.POST.get('time3', 0))}) lastSetConf.update({'time4': int(request.POST.get('time4', 0))}) lastSetConf.update({'time5': int(request.POST.get('time5', 0))}) self.set_IC_coin_power_config(lastSetConf) if request.POST.has_key('power1') and request.POST.has_key('power1ratio'): lastSetConf.update({'power1': int(request.POST.get('power1', 0))}) lastSetConf.update({'power1ratio': int(request.POST.get('power1ratio', 0))}) lastSetConf.update({'power2': int(request.POST.get('power2', 0))}) lastSetConf.update({'power2ratio': int(request.POST.get('power2ratio', 0))}) lastSetConf.update({'power3': int(request.POST.get('power3', 0))}) lastSetConf.update({'power3ratio': int(request.POST.get('power3ratio', 0))}) lastSetConf.update({'power4': int(request.POST.get('power4', 0))}) lastSetConf.update({'power4ratio': int(request.POST.get('power4ratio', 0))}) lastSetConf.update({'power5': int(request.POST.get('power5', 0))}) lastSetConf.update({'power5ratio': int(request.POST.get('power5ratio', 0))}) self.set_gear_conf(lastSetConf) def start_device_realiable(self, order): try: attachParas = order.attachParas package = order.package if attachParas is None: raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路、电池类型信息'}) if not attachParas.has_key('chargeIndex'): raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'}) price = float(package['price']) coins = float(package['coins']) port = hex(int(attachParas['chargeIndex'])) hexPort = fill_2_hexByte(port, 2) gear = hex(int(attachParas['powerGear'])) hexGear = fill_2_hexByte(gear, 4) unit = package.get('unit', u'分钟') needTime = int(package['time']) if unit in [u'分钟', u'小时', u'天', u'秒']: billingType = 'time' if unit == u'小时': needTime = int(package['time']) * 60 elif unit == u'天': needTime = int(package['time']) * 1440 elif unit == u'秒': needTime = int(package['time']) / 60 hexTime = fill_2_hexByte(hex(needTime), 4) else: raise ServiceException( { 'result': 2, 'description': u'充电桩只支持按时间计费的方式,不支持其他方式' } ) return MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, payload={ "funCode": '02', 'order_id': order.orderNo, 'data': hexPort + '0000' + hexTime }, timeout=45, retry=3) except ServiceException as e: logger.exception(e) return { 'rst': ErrorCode.EXCEPTION, 'fts': int(time.time()), 'errorDesc': cn(e.result.get('description')), 'order_type': 'com_start', 'order_id': order.orderNo } except Exception as e: logger.exception(e) return { 'rst': ErrorCode.EXCEPTION, 'fts': int(time.time()), 'order_type': 'com_start', 'order_id': order.orderNo }