# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging import time import uuid import re from decimal import Decimal from apilib.monetary import RMB from apilib.utils_datetime import timestamp_to_dt, to_datetime from bson import ObjectId from apps.web.constant import MQTT_TIMEOUT, DeviceCmdCode, Const from apps.web.common.models import TempValues 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.dealer.models import Dealer from apps.web.device.models import Device, Group from apps.web.user.models import MyUser, Card from taskmanager.mediator import task_caller logger = logging.getLogger(__name__) class ChargingCY6Box(SmartBox): def __init__(self, device): super(ChargingCY6Box, self).__init__(device) @staticmethod def encode_str(data, length=2, ratio=1.0, base=16): # type:(any,int,float,int) -> str if not isinstance(data, Decimal): data = Decimal(data) if not isinstance(length, str): length = str(length) if not isinstance(ratio, Decimal): ratio = Decimal(ratio) end = 'X' if base == 16 else 'd' encodeStr = '%.' + length + end encodeStr = encodeStr % (data * ratio) return encodeStr @staticmethod def transform_password(password): passwordHex = '' while password: passwordHex += fill_2_hexByte(hex(int(password[: 2])), 2) password = password[2:] return passwordHex @staticmethod def check_params_range(params, minData=None, maxData=None, desc=''): # type:(str,float,float,str) -> str ''' 检查参数,返回字符串参数 ''' if params is None: raise ServiceException({'result': 2, 'description': u'参数错误.'}) if not isinstance(params, Decimal): params = Decimal(params) if not minData and maxData: if not isinstance(maxData, Decimal): maxData = Decimal(maxData) if params <= maxData: return '%g' % params else: raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最大值为%g' % (desc, maxData)}) if not maxData and minData: if not isinstance(minData, Decimal): minData = Decimal(minData) if minData <= params: return '%g' % params else: raise ServiceException({'result': 2, 'description': u'%s超出可选范围,可选最小值为%g' % (desc, minData)}) if not minData and not maxData: return '%g' % params else: if not isinstance(minData, Decimal): minData = Decimal(minData) if not isinstance(maxData, Decimal): maxData = Decimal(maxData) if minData <= params <= maxData: return '%g' % params else: raise ServiceException( {'result': 2, 'description': u'%s参数超出可选范围,可取范围为%g-%g' % (desc, minData, maxData)}) def __check_device_uart_status(self, devInfo): if devInfo['rst'] != 0: if devInfo['rst'] == -1: raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请稍候再试'}) elif devInfo['rst'] == 1: raise ServiceException({'result': 2, 'description': u'充电桩主板连接故障'}) else: raise ServiceException({'result': 2, 'description': u'系统错误'}) def _ack(self, ack_id): MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload={ 'IMEI': self.device.devNo, 'funCode': 'AK', 'data': ack_id }, timeout=15) def start_device(self, package, openId, attachParas): if attachParas is None or 'chargeIndex' not in attachParas: raise ServiceException({'result': 2, 'description': u'请您选择合适的端口'}) rechargeRcdId = str(attachParas.get('linkedRechargeRecordId', '')) price = float(package['price']) coins = float(package['coins']) hexCoins = fill_2_hexByte(hex(int(coins * 100)), 4) hexReserveByte = '0000' port = hex(int(attachParas['chargeIndex'])) hexPort = fill_2_hexByte(port, 2) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'D2', 'data': hexCoins + hexReserveByte + hexPort }, timeout=15) self.__check_device_uart_status(devInfo) data = devInfo['data'] if data[6: 8] != '4F': raise ServiceException({'result': 2, 'description': u'启动端口失败,您的金币还在,您重新启动试试看'}) devCache = Device.get_dev_control_cache(self._device["devNo"]) portCache = devCache.get(str(attachParas['chargeIndex'])) start_timestamp = int(time.time()) devInfo['finishedTime'] = start_timestamp + 12 * 60 * 60 if portCache is not None and portCache.get('status', '') == Const.DEV_WORK_STATUS_WORKING and portCache.get('openId') == openId: payInfo = portCache.get("payInfo", list()) if not payInfo: logger.error("miss payInfo! {}-{}".format(self._device["devNo"], str(attachParas['chargeIndex']))) payInfo.append({ "vCardId": self._vcard_id, "coins": float(coins), "price": float(price), "rechargeRcdId": rechargeRcdId, "needTime": 0, }) coins = portCache.get("coins") + float(coins) price = portCache.get("price") + float(price) cacheDict = { "startTime": portCache.get("startTime", ""), "status": Const.DEV_WORK_STATUS_WORKING, 'finishedTime': devInfo['finishedTime'], "coins": coins, "price": price, "openId": openId, 'waitD9': True, 'port': str(attachParas['chargeIndex']), 'payType': '01' } if rechargeRcdId != '': cacheDict.update({'payInfo': payInfo}) else: cacheDict = { "startTime": timestamp_to_dt(start_timestamp).strftime("%Y-%m-%d %H:%M:%S"), "status": Const.DEV_WORK_STATUS_WORKING, 'finishedTime': devInfo['finishedTime'], "coins": float(coins), "price": float(price), "openId": openId, "consumeType": "mobile", 'waitD9': True, 'port': str(attachParas['chargeIndex']), 'payType': '01' } if rechargeRcdId != '': cacheDict.update({'payInfo': [{ "vCardId": self._vcard_id, "coins": float(coins), "price": float(price), "rechargeRcdId": rechargeRcdId, "needTime": 0, }]}) Device.update_dev_control_cache(self._device["devNo"], {str(attachParas['chargeIndex']): cacheDict}) if openId: devInfo['rechargeRcdId'] = rechargeRcdId return devInfo def get_port_status(self, force=False): ''' 获取设备状态 昌原的状态都是被动获取的 :param force: :return: ''' MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, { 'IMEI': self._device['devNo'], 'funCode': 'E1', 'data': '0000' }, timeout=15) # 不修改100267的驱动基础上做延时处理 time.sleep(1) devCache = Device.get_dev_control_cache(self._device['devNo']) statusDict = dict() allPorts = devCache.get('allPorts', 10) for portNum in range(allPorts): tempDict = devCache.get(str(portNum + 1), {}) if 'status' in tempDict: statusDict[str(portNum + 1)] = {'status': tempDict.get('status')} elif 'isStart' in tempDict: if tempDict['isStart']: statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING} else: statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE} else: statusDict[str(portNum + 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): return self.get_port_status(False) def _async_card_balance(self, cardType, cardNo, asyncMoney): """ 同步卡内余额 :param cardType: :param cardNo: :param asyncMoney: :return: """ # 如果是预付费的卡 同步的金额需要变换为分 balance = asyncMoney if cardType == '00' else asyncMoney * 100 # 获取随机流水号 sidKey = '{}-{}'.format(self.device.devNo, cardNo) sid = TempValues.get(sidKey) balanceHex = self.encode_str(int(balance), length=6) sidHex = self.encode_str(sid, length=4) MessageSender.send(device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, payload={ 'IMEI': self.device.devNo, 'funCode': 'D3', 'data': cardType + balanceHex + sidHex + cardNo }) def get_dev_setting(self): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'D0', 'data': '00' }, timeout=15) self.__check_device_uart_status(devInfo) data = devInfo['data'][6:] powerTime1 = str(int(data[0:4], 16)) powerTime2 = str(int(data[4:8], 16)) powerTime3 = str(int(data[8:12], 16)) powerTime4 = str(int(data[12:16], 16)) power1 = str(int(data[16:20], 16)) power2 = str(int(data[20:24], 16)) power3 = str(int(data[24:28], 16)) power4 = str(int(data[28:32], 16)) noloadPower = str(int(data[32:34], 16)) noloadTime = str(int(data[34:36], 16)) volume = str(int(data[36:38], 16)) cardFee = str(float(int(data[38:42], 16)) / 100) floatPower = str(int(data[42:44], 16)) floatTime = str(int(data[44:48], 16)) cardFree = False if data[48:50] == u'00' else True powerTime5 = str(int(data[50:54], 16)) powerTime6 = str(int(data[54:58], 16)) power5 = str(int(data[58:62], 16)) power6 = str(int(data[62:66], 16)) elecPrice = str(float(int(data[66:68], 16)) / 100) consumeTypeStr = data[68:70] cardRefund = False if data[70:72] == u'00' else True if consumeTypeStr == u'00': consumeType = 'elec' elif consumeTypeStr == u'01': consumeType = 'power' elif consumeTypeStr == u'02': consumeType = 'time' else: consumeType = 'free' devCache = Device.get_dev_control_cache(self._device['devNo']) temperature = devCache.get('temperature', '获取中...') disable = self.device.get('otherConf', {}).get('disableDevice', False) needBindCard = self.device.get("otherConf", {}).get('needBindCard', True) vCardTime = self.device.get("otherConf", {}).get('vCardTime', 300) return { 'noloadPower': noloadPower, 'noloadTime': noloadTime, 'cardFee': cardFee, 'temperature': temperature, 'elecPrice': elecPrice, 'power5': power5, 'power6': power6, 'power4': power4, 'power3': power3, 'power2': power2, 'power1': power1, 'vCardTime': vCardTime, 'disable': disable, 'volume': volume, 'needBindCard': needBindCard, 'powerTime1': powerTime1, 'powerTime2': powerTime2, 'powerTime3': powerTime3, 'powerTime4': powerTime4, 'powerTime5': powerTime5, 'powerTime6': powerTime6, 'floatTime': floatTime, 'floatPower': floatPower, 'cardFree': cardFree, 'consumeType': consumeType, 'cardRefund': cardRefund } def _set_password(self, password): """ 设置设备的小区密码 密码是否还需要再校验,以及是否是0开头 """ if not password.isdigit(): raise ServiceException({'result': '2', 'description': u'密码必须必须为0-9数字'}) if len(password) != 10: raise ServiceException({'result': 0, 'description': u'密码长度必须为10位'}) passwordHex = self.transform_password(password) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'DB', 'data': passwordHex }, timeout=15) self.__check_device_uart_status(devInfo) if 'data' not in devInfo: raise ServiceException({'result': '2', 'description': u'设置小区密码失败,请重新试试'}) return devInfo def _set_send_card(self, oldPassword, newPassword, FaKacardType): ''' 设置卡机模式 用于重置 实体卡的小区密码 ''' if not oldPassword.isdigit() or not newPassword.isdigit(): raise ServiceException({'result': '2', 'description': u'密码必须必须为0-9数字'}) if len(oldPassword) != 10 or len(newPassword) != 10: raise ServiceException({'result': 0, 'description': u'密码长度必须为10位'}) if not FaKacardType: raise ServiceException({'result': 0, 'description': u'请选择要发行卡的类型'}) oldPasswordHex = self.transform_password(oldPassword) newPasswordHex = self.transform_password(newPassword) FaKacardType = self.encode_str(FaKacardType) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'DC', 'data': oldPasswordHex + newPasswordHex + FaKacardType }, timeout=15) self.__check_device_uart_status(devInfo) if 'data' not in devInfo: raise ServiceException({'result': '2', 'description': u'设置发卡机模式失败,请重新试试'}) return devInfo def _set_elec_price(self, elecPrice): """ 设置电量单价 这个参数是模块侧的 只下发到模块驱动 不到主板 :param elecPrice: :return: """ elecPriceHex = "{:0>8X}".format(int(3600 * 1000 * float(elecPrice))) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'EP', 'data': elecPriceHex }, timeout=15) self.__check_device_uart_status(devInfo) # 更新参数设置 Device.get_collection().update_one({'devNo': self.device['devNo']}, {'$set': {'otherConf.elecPrice': elecPrice}}) Device.invalid_device_cache(self.device.devNo) def _reboot_device(self): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'D5', 'data': '0000' }, timeout=15) self.__check_device_uart_status(devInfo) if 'data' not in devInfo: raise ServiceException({'result': '2', 'description': u'设备复位错误,请重新试试'}) return devInfo def set_dev_disable(self, disable): if disable: status = '00AA' else: status = '0055' devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'DD', 'data': status }, timeout=15) self.__check_device_uart_status(devInfo) if 'data' not in devInfo: raise ServiceException({'result': '2', 'description': u'设备停用错误,请联系厂商协助解决'}) otherConf = self._device.get('otherConf', {}) otherConf['disableDevice'] = disable Device.objects.filter(devNo=self._device['devNo']).update(otherConf=otherConf) Device.invalid_device_cache(self._device['devNo']) def _set_all_settings(self, settings): powerTime1 = settings.get('powerTime1') powerTime2 = settings.get('powerTime2') powerTime3 = settings.get('powerTime3') powerTime4 = settings.get('powerTime4') power1 = settings.get('power1') power2 = settings.get('power2') power3 = settings.get('power3') power4 = settings.get('power4') noloadPower = settings.get('noloadPower') noloadTime = settings.get('noloadTime') volume = settings.get('volume') cardFee = settings.get('cardFee') floatPower = settings.get('floatPower') floatTime = settings.get('floatTime') cardFree = settings.get('cardFree') powerTime5 = settings.get('powerTime5') powerTime6 = settings.get('powerTime6') power5 = settings.get('power5') power6 = settings.get('power6') elecPrice = settings.get('elecPrice') consumeType = settings.get('consumeType') cardRefund = settings.get('cardRefund') # powerTime1 = self.check_params_range(params=powerTime1, minData=0, maxData=999, desc='第1段功率时间') powerTime2 = self.check_params_range(params=powerTime2, minData=0, maxData=999, desc='第2段功率时间') powerTime3 = self.check_params_range(params=powerTime3, minData=0, maxData=999, desc='第3段功率时间') powerTime4 = self.check_params_range(params=powerTime4, minData=0, maxData=999, desc='第4段功率时间') power1 = self.check_params_range(params=power1, minData=0, maxData=999, desc='第1段功率值') power2 = self.check_params_range(params=power2, minData=0, maxData=999, desc='第2段功率值') power3 = self.check_params_range(params=power3, minData=0, maxData=999, desc='第3段功率值') power4 = self.check_params_range(params=power4, minData=0, maxData=999, desc='第4段功率值') noloadPower = self.check_params_range(params=noloadPower, minData=0, maxData=50, desc='空载检测功率') noloadTime = self.check_params_range(params=noloadTime, minData=0, maxData=255, desc='空载功率检测时间') volume = self.check_params_range(params=volume, minData=0, maxData=8, desc='音量') cardFee = self.check_params_range(params=cardFee, minData=0, maxData=655, desc='预付卡预扣金额') floatPower = self.check_params_range(params=floatPower, minData=0, maxData=50, desc='浮动功率') floatTime = self.check_params_range(params=floatTime, minData=0, maxData=60000, desc='浮动功率延长时间') powerTime5 = self.check_params_range(params=powerTime5, minData=0, maxData=999, desc='第5段功率时间') powerTime6 = self.check_params_range(params=powerTime6, minData=0, maxData=999, desc='第6段功率时间') power5 = self.check_params_range(params=power5, minData=0, maxData=999, desc='第5段功率值') power6 = self.check_params_range(params=power6, minData=0, maxData=999, desc='第6段功率值') elecPrice = self.check_params_range(params=elecPrice, minData=0, maxData=2.5, desc='电价') if consumeType == 'elec': consumeTypeStr = '00' elif consumeType == 'power': consumeTypeStr = '01' elif consumeType == 'time': consumeTypeStr = '02' elif consumeType == 'free': consumeTypeStr = '03' else: consumeTypeStr = '00' data = '' data += self.encode_str(powerTime1, length=4) data += self.encode_str(powerTime2, length=4) data += self.encode_str(powerTime3, length=4) data += self.encode_str(powerTime4, length=4) data += self.encode_str(power1, length=4) data += self.encode_str(power2, length=4) data += self.encode_str(power3, length=4) data += self.encode_str(power4, length=4) data += self.encode_str(noloadPower, length=2) data += self.encode_str(noloadTime, length=2) data += self.encode_str(volume, length=2) data += self.encode_str(cardFee, length=4, ratio=100) data += self.encode_str(floatPower, length=2) data += self.encode_str(floatTime, length=4) data += "AA" if cardFree is True else "00" data += self.encode_str(powerTime5, length=4) data += self.encode_str(powerTime6, length=4) data += self.encode_str(power5, length=4) data += self.encode_str(power6, length=4) data += self.encode_str(elecPrice, length=2, ratio=100) data += consumeTypeStr data += "01" if cardRefund is True else "00" devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'D1', 'data': data }, timeout=15) self.__check_device_uart_status(devInfo) if 'data' not in devInfo: raise ServiceException({'result': '2', 'description': u'设置设备参数错误,请联系经销商协助解决'}) return devInfo def set_device_function_param(self, request, lastSetConf): """设备设备的参数""" if "pwd" in request.POST: return self._set_password(request.POST["pwd"]) if "old_pwd" in request.POST: old_pwd = request.POST["old_pwd"] new_pwd = request.POST["new_pwd"] cardType = request.POST["FaKacardType"] return self._set_send_card(old_pwd, new_pwd, cardType) # 卡券启动时间 if 'vCardTime' in request.POST: vCardTime = int(request.POST.get('vCardTime')) if vCardTime != int(self.device['otherConf'].get('vCardTime', 300)): Device.get_collection().update_one({'devNo': self.device['devNo']}, {'$set': {'otherConf.vCardTime': vCardTime}}) Device.invalid_device_cache(self.device.devNo) # 对一下参数的设置 new_settings = dict() for _paramKey, _paramValue in lastSetConf.items(): if request.POST.get(_paramKey) is not None: _paramValue = request.POST[_paramKey] new_settings[_paramKey] = _paramValue cardFree = "AA" if new_settings["cardFree"] else "00" new_settings.update({"cardFree": cardFree}) self._set_all_settings(new_settings) def set_device_function(self, request, lastSetConf): """开关类参数配置""" if 'disable' in request.POST: return self.set_dev_disable(request.POST.get('disable')) if 'reboot' in request.POST: return self._reboot_device() if 'cardFree' in request.POST: cardFree = request.POST["cardFree"] lastSetConf.update({"cardFree": cardFree}) return self._set_all_settings(lastSetConf) if 'cardRefund' in request.POST: cardRefund = request.POST["cardRefund"] lastSetConf.update({'cardRefund': cardRefund}) return self._set_all_settings(lastSetConf) if 'needBindCard' in request.POST: needBindCard = request.POST.get('needBindCard') otherConf = self.device.get('otherConf', dict()) otherConf.update({'needBindCard': needBindCard}) Device.objects.get(devNo=self.device.devNo).update(otherConf=otherConf) Device.invalid_device_cache(self.device.devNo) def analyze_event_data(self, data): cmdCode = data[2:4] if cmdCode == 'D8': tempData = data[6:170] portStatusData = tempData[0:20] portPowerData = tempData[20:60] portLeftMoneyData = tempData[60:100] portErrorData = tempData[100:120] temperature = tempData[120:124] portSpendElecData = tempData[124:164] portInfo = {} for _ in range(10): currentPortStatusData = portStatusData[(_ * 2):(_ + 1) * 2] if currentPortStatusData == '00': tempPortStatusData = Const.DEV_WORK_STATUS_IDLE elif currentPortStatusData in ['01', '11']: tempPortStatusData = Const.DEV_WORK_STATUS_WORKING else: tempPortStatusData = Const.DEV_WORK_STATUS_FAULT currentPortErrorMessage = portErrorData[(_ * 2):(_ + 1) * 2] if currentPortErrorMessage == '00': tempPortErrorMessage = 'normal' elif currentPortErrorMessage == '01': tempPortErrorMessage = 'elecRelayAdhesion' tempPortStatusData = Const.DEV_WORK_STATUS_FAULT else: tempPortErrorMessage = 'unknownError' tempPortStatusData = Const.DEV_WORK_STATUS_FAULT portInfo[str(_ + 1)] = {'status': tempPortStatusData} portInfo[str(_ + 1)].update({'power': str(int(portPowerData[(_ * 4):(_ + 1) * 4], 16))}) portInfo[str(_ + 1)].update({'leftMoney': str(float(int(portLeftMoneyData[(_ * 4):(_ + 1) * 4], 16)) / 100)}) portInfo[str(_ + 1)].update({'errorMessage': tempPortErrorMessage}) portInfo[str(_ + 1)].update({'spendElec': str(float(int(portSpendElecData[(_ * 4):(_ + 1) * 4], 16)) / 100)}) # 首先依据上报的状态获取已使用未使用端口数量 allPorts, usedPorts, usePorts = self.get_port_static_info(portInfo) devCache = Device.get_dev_control_cache(self.device.devNo) or dict() for portStr, value in devCache.items(): if not portStr.isdigit() or not isinstance(value, dict): continue # 更新每个端口的信息 tempPortInfo = portInfo.get(portStr, dict()) value.update(tempPortInfo) devCache[portStr] = value devCache['temperature'] = ('+' if temperature[0:2] == '00' else '-') + str(int(temperature[2:4], 16)) + ' degrees' devCache['allPorts'] = allPorts devCache['usedPorts'] = usedPorts devCache['usePorts'] = usePorts Device.update_dev_control_cache(self.device.devNo, devCache) return {} elif cmdCode == 'DA': tempData = data[6:18] port = str(int(tempData[0:2], 16)) reasonCode = tempData[2:4] if reasonCode == '01': reason = '设备充满自停或拔掉插头' elif reasonCode == '02': reason = '超功率停止' elif reasonCode == '03': reason = '时间用完停止' elif reasonCode == '04': reason = '远程停止' elif reasonCode == '05': reason = '预付卡的扣费金额用完' else: reason = '电量超限' spendElec = str(float(int(tempData[4:8], 16)) / 100) leftMoney = str(float(int(tempData[8:12], 16)) / 100) return {'cmdCode': cmdCode, 'port': port, 'reason': reason, 'spendElec': spendElec, 'leftMoney': leftMoney} elif cmdCode == 'D9': power = str(int(data[20:24], 16)) coins = float(int(data[24:28], 16)) / 100 port = str(int(data[28:30], 16)) payType = data[30:32] if payType == '00': # 次卡 cardNo = data[6:14] cardType = '00' cardBalance = str(int(data[14:20], 16)) needTime = int(data[32:36], 16) elif payType == '01': # 扫码 needTime = int(data[32:36], 16) elif payType == '02': # 投币 needTime = int(data[32:36], 16) elif payType == '03': # 预付卡 cardNo = data[6:14] cardType = '01' cardBalance = str(float(int(data[14:20], 16)) / 100) leftMoney = str(float(int(data[32:36], 16)) / 100) else: pass return locals() elif cmdCode == 'D4': cardType = data[6:8] cardNo = data[8:16] cardBalance = RMB(int(data[16:22], 16)) if cardType == '01': cardBalance = cardBalance * 0.01 return { "cardType": cardType, "cardNo": cardNo, "cardBalance": cardBalance, 'cmdCode': cmdCode } elif cmdCode == 'D3': cardType = data[6:8] cardNo = data[8:16] cardBalance = RMB(int(data[16:22], 16)) result = True if data[22:24] == 'AA' else False sid = int(data[24:28], 16) if cardType == '01': cardBalance = cardBalance * 0.01 return { "cardType": cardType, "cardNo": cardNo, "cardBalance": cardBalance, "result": result, "sid": sid, 'cmdCode': cmdCode } elif cmdCode == 'D7': return {'data': data[6:8], 'cmdCode': cmdCode} elif cmdCode == 'DE': cardNo = data[6:14] beforeRefund = float(int(data[14:20], 16)) / 100.0 refund = float(int(data[20:24], 16)) / 100.0 afterRefund = float(int(data[24:30], 16)) / 100.0 return {'cardNo': cardNo, 'beforeRefund': beforeRefund, 'refund': refund, 'afterRefund': afterRefund, 'cmdCode': cmdCode} @property def isHaveStopEvent(self): return True def stop(self, port=None): if not port: raise ServiceException({"result": "2", "description": u"请选择停止端口!"}) self.stop_charging_port(port) def stop_charging_port(self, port): portHex = fill_2_hexByte(hex(int(port)), 2) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'D6', 'data': portHex }, timeout=15) self.__check_device_uart_status(devInfo) data = devInfo.get('data') if data[6: 8] != '4F': raise ServiceException({'result': 2, 'description': u'停止充电失败,请重新试试'}) # 这里只下发命令 不清理端口缓存,等上报事件清除 # Device.clear_port_control_cache(self.device.devNo, int(port)) def check_dev_status(self, attachParas = None): pass def get_port_info(self, port): ''' 获取 端口的详细信息 :param port: :return: ''' time.sleep(2) data = fill_2_hexByte(hex(int(port)), 2) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'E0', 'data': '00' + data }, timeout=15) self.__check_device_uart_status(devInfo) data = devInfo['data'][6::] line = str(int(data[0:2], 16)) lineStatus = str(int(data[2:4], 16)) power = str(int(data[4:8], 16)) leftMoney = str(float(int(data[8:12], 16)) / 100) temperatureStr = data[12:16] temperature = ('+' if temperatureStr[0:2] == '00' else '-') + str(int(temperatureStr[2:4], 16)) + ' degrees' spendElec = str(float(int(data[16:20], 16)) / 100) errorCode = data[20:22] return {'port': line, 'portStatus': lineStatus, 'power': power, 'leftMoney': leftMoney, 'temperature': temperature, 'spendElec': spendElec, 'errorCode': errorCode} def active_deactive_port(self, port, active): if not active: self.stop_charging_port(port) else: raise ServiceException({'result': 2, 'description': u'此设备不支持直接打开端口'}) def format_port_using_detail(self, detailDict): portData = {} startTimeStr = detailDict.get('startTime', None) if startTimeStr is not None and "usedTime" not in detailDict: startTime = to_datetime(startTimeStr) usedTime = int(round((datetime.datetime.now() - startTime).total_seconds() / 60.0)) portData['usedTime'] = usedTime elif detailDict.get("usedTime"): usedTime = detailDict.get("usedTime") portData['usedTime'] = usedTime else: usedTime = None if detailDict.has_key('needTime'): if detailDict['needTime'] == 999: portData['needTime'] = u'充满自停' else: portData['needTime'] = detailDict['needTime'] if detailDict.has_key('leftTime') and (usedTime > 0): if detailDict['leftTime'] == 65535: portData['leftTime'] = 65535 detailDict['usedTime'] = 0 detailDict['actualNeedTime'] = 0 else: portData['actualNeedTime'] = int(detailDict['leftTime']) + int(usedTime) if detailDict.has_key('needTime') and portData['actualNeedTime'] > detailDict['needTime']: portData['actualNeedTime'] = portData['needTime'] portData['leftTime'] = detailDict['leftTime'] if detailDict.has_key('coins'): portData['leftMoney'] = detailDict['leftMoney'] portData['consumeMoney'] = str(float(detailDict['price']) - float(detailDict['leftMoney'])) elif detailDict.has_key('leftTime'): portData['leftTime'] = detailDict['leftTime'] if (not detailDict.has_key('leftTime')) and (usedTime is not None): if detailDict.has_key('needTime'): portData['leftTime'] = detailDict['needTime'] - usedTime if detailDict.has_key('coins') and float(detailDict['coins']) != 0: portData['leftMoney'] = detailDict['leftMoney'] portData['consumeMoney'] = str(float(detailDict['price']) - float(detailDict['leftMoney'])) if detailDict.has_key('openId'): user = MyUser.objects(openId=detailDict['openId'], groupId=self.device.groupId).first() if user: portData['nickName'] = user.nickname if detailDict.has_key('cardId'): if not detailDict.has_key('consumeType'): portData['consumeType'] = 'card' card = Card.objects.get(id=ObjectId(detailDict['cardId'])) if card.cardName: portData['cardName'] = card.cardName portData['cardNo'] = card.cardNo # 注意,如果是IC卡,不支持余额回收,这里也不要显示出来 if card.cardType == 'IC' and portData.has_key('leftMoney'): portData.pop('leftMoney') elif detailDict.has_key('openId') and (not detailDict.has_key('consumeType')): if detailDict.get('vCardId'): portData['consumeType'] = 'mobile_vcard' else: portData['consumeType'] = 'mobile' elif detailDict.has_key('consumeType') and detailDict['consumeType'] == 'coin': portData['consumeType'] = 'coin' # 硬币的都无法退费 if portData.has_key('leftMoney'): portData.pop('leftMoney') # 做个特殊处理 if portData.has_key('needTime'): if portData['needTime'] == '999' or portData['needTime'] == '充满自停': portData['needTime'] = u'充满自停' else: portData['needTime'] = u'%s分钟' % portData['needTime'] # 如果剩余时间为65535,表示未接插头 if portData.has_key('leftTime') and portData['leftTime'] == 65535: portData['leftTime'] = u'(线路空载)' portData['usedTime'] = 0 portData['needTime'] = 0 detailDict.update(portData) for k, v in detailDict.items(): if v < 0: detailDict.pop(k) # 因为前台显示的开始时间如果带年,就显示不下,这里做个切割 if detailDict.has_key('startTime') and detailDict['startTime'].count('-') == 2: detailDict['startTime'] = to_datetime(detailDict['startTime']).strftime('%m-%d %H:%M:%S') return detailDict