# -*- coding: utf-8 -*- # !/usr/bin/env python import binascii import datetime import logging import time from apilib.monetary import VirtualCoin from apps.web.core.adapter.base import SmartBox, fill_2_hexByte from apps.web.core.device_define.dianchuan_CarCharging import ChargeMode, StopReason from apps.web.core.networking import MessageSender from apps.web.core.exceptions import ServiceException from apps.web.constant import DeviceCmdCode, Const from apps.web.user.models import ConsumeRecord from apps.web.device.models import Device, DeviceType from apps.web.utils import concat_user_login_entry_url logger = logging.getLogger(__name__) class DianchuanCarCharging(SmartBox): def _send_data(self, funCode, data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, timeout=30): """ 调用MessageSender类中的send方法,向主板发送指令信息,并获得其响应 :param funCode: 功能码,具体内容参考主板协议和驱动 :param data: :param cmd:经典命令码,默认210 命令方向:服务器->驱动->主板,主板->驱动->服务器 :param timeout:访问超时时间 :return:主板收到命令后的响应,具体内容参考主板协议和驱动 """ # result 中的信息有:cmd,ts (发送响应瞬间的时间戳),IMEI,data,rst result = MessageSender.send( device=self.device, cmd=cmd, payload={"IMEI": self.device.devNo, "funCode": funCode, "data": data}, timeout=timeout ) # 检测rst,-1为网络不通,1为串口不同,-1会发生在任何传输过程,1指挥发生在驱动到主板端 if result.get('rst') == -1: raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'}) if result.get('rst') == 1: raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) return result @staticmethod def _suit_package(package): ''' 返回充电模式以及充电参数 ''' unit = package["unit"] coins = VirtualCoin(package['coins']) userAcquire = package["time"] nowTime = int(time.time()) if unit == u"天": mode = ChargeMode.TIME_QUOTA chargeParam = userAcquire * 24 * 60 finishedTime = nowTime + chargeParam * 60 return mode, chargeParam, finishedTime elif unit == u"小时": mode = ChargeMode.TIME_QUOTA chargeParam = userAcquire * 60 finishedTime = nowTime + chargeParam * 60 return mode, chargeParam, finishedTime elif unit == u"分钟": mode = ChargeMode.TIME_QUOTA chargeParam = userAcquire finishedTime = nowTime + chargeParam * 60 return mode, chargeParam, finishedTime elif unit == u"度": mode = ChargeMode.ELEC_QUOTA chargeParam = userAcquire * 100 finishedTime = nowTime + 12 * 60 * 60 return mode, chargeParam, finishedTime elif unit == u"次": # 充满自停 mode = ChargeMode.COIN_QUOTA chargeParam = int((coins * 100).amount) finishedTime = nowTime + 12 * 60 * 60 return mode, chargeParam, finishedTime @staticmethod def _to_ascii(s): ''' 将数据转化为二进制数据的十六进制表示 :param s: :return: ''' return binascii.hexlify(s).upper() @staticmethod def _to_str(h): """ 将 16进制ascii 转换成 字符串 :param h: :return: """ return binascii.unhexlify(h).lower() # 状态查询 def _status_check(self): network_status = fill_2_hexByte(hex(int(1)), 2) network_quality = fill_2_hexByte(hex(int(10)), 2) data = network_status + network_quality + '{:0>12}'.format(0) result = self._send_data("41", data=data) data = result['data'] port_count = data[8:10], port_status = [data[10:14][i:i + 2] for i in range(len(data[12:16])) if i % 2 == 0] pile_status = [str(binascii.hexlify(binascii.unhexlify(fill_2_hexByte(bin(int(data[14:18])), 16))[::-1]))[i] for i in range(-1, -6, -1)] statusInfo = { 'port_count': port_count, 'port_status': port_status, 'pile_status': pile_status } result['statusInfo'] = statusInfo return result # # 生成seqNo def _make_seqNo(self, port, logicNo): """ 生成流水号 :param port:充电端口 :param logicNo:充电桩的设备码 :return:特征码+桩编号后 4 位+ 月日时分秒+端口号+充电计数 """ characteristic_code = '55' # 本地启动特征码为 0x99,远程启动特征码为 0x55 logicNo_four_digits = logicNo[-4:] date_MDHMS = time.strftime('%m%d%H%M%S') portHex = fill_2_hexByte(hex(int(port)), 2) # charge_count = fill_2_hexByte(hex(random.randint(0, 255)),2) charge_count = fill_2_hexByte(logicNo[:2], 2) seqNo = characteristic_code + logicNo_four_digits + date_MDHMS + portHex + charge_count return seqNo # 生成配置表单 def _make_config_list(self, top_price_rate, peak_price_rate, normal_price_rate, valley_price_rate, half_hour_price_list): top_price_rateHex = binascii.hexlify(binascii.unhexlify(fill_2_hexByte(hex(int(top_price_rate)), 4))[::-1]) peak_price_rateHex = binascii.hexlify(binascii.unhexlify(fill_2_hexByte(hex(int(peak_price_rate)), 4))[::-1]) normal_price_rateHex = binascii.hexlify( binascii.unhexlify(fill_2_hexByte(hex(int(normal_price_rate)), 4))[::-1]) valley_price_rateHex = binascii.hexlify( binascii.unhexlify(fill_2_hexByte(hex(int(valley_price_rate)), 4))[::-1]) half_hour_priceHex = ''.join( fill_2_hexByte(hex(int(half_hour_price)), 2) for half_hour_price in half_hour_price_list) data = top_price_rateHex + peak_price_rateHex + normal_price_rateHex + valley_price_rateHex + half_hour_priceHex + '{:0>16}'.format( 0) return data # 查询当前的配置表 def _config_list_check(self): result = self._send_data('48', '55') code = result['data'][8:10] if code == '55': return self._parse_config_change_upload(result['data']) raise ServiceException({'result': 2, 'description': u'信息查询错误'}) # 配置表主动下发 def _config_list_issue(self, top_price_rate, peak_price_rate, normal_price_rate, valley_price_rate, half_hour_price_list): data = self._make_config_list(top_price_rate, peak_price_rate, normal_price_rate, valley_price_rate, half_hour_price_list) result = self._send_data('49', data=data) code = result['data'][8:10] if code == '00': return result else: raise ServiceException({'result': 2, 'description': u'请求失败,请重试'}) # 控制设备 def _control_device(self, pile_instruct, port_instruct): pile_instructHex = binascii.hexlify(binascii.unhexlify(fill_2_hexByte(hex(pile_instruct), 4))[::-1]) port_instructHex = fill_2_hexByte(hex(port_instruct), 4) data = pile_instructHex + port_instructHex + '{:0>16}'.format(0) result = self._send_data('47', data=data) code = result['data'][8:10] if code == "00": return result else: raise ServiceException({'result': 2, 'description': u'设备操作失败'}) # 下发二维码以及模块编号 def _qr_code_devNo_issue(self): deviceNo = self._to_ascii(self.device.devNo) if deviceNo[0:1] == 'G': deviceNo = self._to_ascii(deviceNo[1:]) qr_code_url = self._to_ascii(concat_user_login_entry_url(l=self._device["logicalCode"])).ljust(128, "0") data = qr_code_url + deviceNo self._send_data('89', data=data) # 远程启动 def _start_remote(self, port, seqNo, mode, chargeParam, balance): """ 拼接远程启动指令并发送到主板,获取启动响应 :param port:设备端口号 :param seqNo: 设备logic码 :param mode:停止充电条件 :param chargeParam:充电参数:充电金额,充电时间,充电电量等 :param balance:充电支付的总金额 :return:主板返回的远程启动响应 """ seqNo = seqNo card_No = '00000000' portHex = fill_2_hexByte(hex(int(port)), 2) modeHex = fill_2_hexByte(hex(int(mode)), 2) chargeParamHex = binascii.hexlify(binascii.unhexlify(fill_2_hexByte(hex(int(chargeParam)), 4))[::-1]) balanceHex = binascii.hexlify(binascii.unhexlify(fill_2_hexByte(hex(int(balance)), 8))[::-1]).upper() data = seqNo + card_No + portHex + modeHex + chargeParamHex + balanceHex + '{:0>36}'.format(0) result = self._send_data("42", data=data) code = result["data"][10:-4] if code == "00": return result if code == '11': raise ServiceException({'result': 2, 'description': u'您使用的充电枪已经在充电了,请您换其他空闲的充电枪吧!'}) if code == '12': raise ServiceException({'result': 2, 'description': u'您没有插充电枪,请先插好充电枪,然后再操作哦!'}) if code == '13': raise ServiceException({'result': 2, 'description': u'充电故障,暂时无法使用,您本次操作不会扣费,您可以试试其他可用的设备。'}) if code == '14': raise ServiceException({'result': 2, 'description': u'待机故障,暂时无法使用,您本次操作不会扣费,您可以试试其他可用的设备。'}) if code == '15': raise ServiceException({'result': 2, 'description': u'车辆未连接,请先插好充电枪,然后再操作哦!'}) if code == '16': raise ServiceException({'result': 2, 'description': u'设备紧急按钮已被按下,请确认设备是否正常工作,然后再操作哦!'}) if code == '17': raise ServiceException({'result': 2, 'description': u'正在等待上次充电结算,请您换其他空闲的充电枪吧!'}) if code == '18': raise ServiceException({'result': 2, 'description': u'无此端口,本次操作不会扣费,请您重试看是否能够解决'}) if code == '19': raise ServiceException({'result': 2, 'description': u'设备已暂停服务,请您换其他空闲的充电枪吧!'}) raise ServiceException({'result': 2, 'description': u'设备返回一个未知的错误,本次操作不会扣费,请您重试看是否能够解决'}) # 远程停止 def _stop_remote(self, port, seqNo): """ 远程停止 """ portHex = fill_2_hexByte(hex(int(port)), 2) seqNo = seqNo data = seqNo + portHex result = self._send_data('45', data) if result['data'][30:-4] != "00": if result['data'][30:-4] == "01": raise ServiceException({'result': 2, 'description': u'该充电枪已经空闲,没有充电'}) else: raise ServiceException({'result': 2, 'description': u'断电失败'}) return result # 配置表变化上传 @staticmethod def _parse_config_change_upload(data): top_rate = int(binascii.hexlify(binascii.unhexlify(data[10:14])[::-1]), 16) top_price_rate = str(float(top_rate) / 100) peak_rate = int(binascii.hexlify(binascii.unhexlify(data[14:18])[::-1]), 16) peak_price_rate = str(float(peak_rate) / 100) normal_rate = int(binascii.hexlify(binascii.unhexlify(data[18:22])[::-1]), 16) normal_price_rate = str(float(normal_rate) / 100) valley_rate = int(binascii.hexlify(binascii.unhexlify(data[22:26])[::-1]), 16) valley_price_rate = str(float(valley_rate) / 100) half_hour_price_list = [str(int(i)) for i in [data[26:-20][i:i + 2] for i in range(len(data[26:-20]) - 1) if i % 2 == 0]] return { 'top_price_rate': top_price_rate, 'peak_price_rate': peak_price_rate, 'normal_price_rate': normal_price_rate, 'valley_price_rate': valley_price_rate, 'half_hour_price_list': half_hour_price_list } # 充电实时数据上报 @staticmethod def _charge_data_report(data): current_rate = data[8:10] port_count = data[10:12] # 正在充电的端口数量 port_data = {} tag = 12 for i in range(port_count): port_data[i] = { 'chargeIndex': data[tag:tag + 2], 'output_voltage': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 2:tag + 6])[::-1]), 16)), 'output_current': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 6:tag + 10])[::-1]), 16)), 'output_power': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 10:tag + 14])[::-1]), 16)), 'used_time': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 14:tag + 18])[::-1]), 16)), 'top_elec': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 18:tag + 22])[::-1]), 16)), 'peak_elec': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 22:tag + 26])[::-1]), 16)), 'normal_elec': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 26:tag + 30])[::-1]), 16)), 'vallery_elec': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 30:tag + 34])[::-1]), 16)), 'total_elec': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 34:tag + 38])[::-1]), 16)), 'top_expense': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 38:tag + 42])[::-1]), 16)), 'peak_expense': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 42:tag + 46])[::-1]), 16)), 'normal_expense': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 46:tag + 50])[::-1]), 16)), 'vallery_expense': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 50:tag + 54])[::-1]), 16)), 'total_expense': str(int(binascii.hexlify(binascii.unhexlify(data[tag + 54:tag + 58])[::-1]), 16)), } tag = tag + 58 return { 'current_rate': current_rate, 'port_count': port_count, 'port_data': port_data, } def _response_finished(self, seqNo): seqNo = seqNo self._send_data("AK", seqNo, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE) # 获取二维码以及设备编号 def _parse_get_qr_code_devNo(self, data): time = int(data[8:-4], 16) self._qr_code_devNo_issue() @property def isHaveStopEvent(self): return True # 分析上报事件数据 def analyze_event_data(self, data): cmdcode = data[6:8] if cmdcode == '36': seqNo = data[8:28] port = int(data[28:30], 16) mode = int(data[30:32], 16) startTime = data[40:54] finishTime = data[54:68] eDuration = int(binascii.hexlify(binascii.unhexlify(data[68:72])[::-1]), 16) top_spend_elec = float(int(binascii.hexlify(binascii.unhexlify(data[72:76])[::-1]), 16)) peak_spend_elec = float(int(binascii.hexlify(binascii.unhexlify(data[76:80])[::-1]), 16)) normal_spend_elec = float(int(binascii.hexlify(binascii.unhexlify(data[80:84])[::-1]), 16)) valley_spend_elec = float(int(binascii.hexlify(binascii.unhexlify(data[84:88])[::-1]), 16)) top_spend_money = int(binascii.hexlify(binascii.unhexlify(data[88:92])[::-1]), 16) peak_spend_money = int(binascii.hexlify(binascii.unhexlify(data[92:96])[::-1]), 16) normal_spend_money = int(binascii.hexlify(binascii.unhexlify(data[96:100])[::-1]), 16) valley_spend_money = int(binascii.hexlify(binascii.unhexlify(data[100:104])[::-1]), 16) total_spend_elec = float(int(binascii.hexlify(binascii.unhexlify(data[104:108])[::-1]), 16)) total_spend_money = float(int(binascii.hexlify(binascii.unhexlify(data[108:112])[::-1]), 16)) reason = str(int(data[120:122], 16)) eDuration = eDuration / 60 top_spend_elec = top_spend_elec / 100 peak_spend_elec = peak_spend_elec / 100 normal_spend_elec = normal_spend_elec / 100 valley_spend_elec = valley_spend_elec / 100 top_spend_money = top_spend_money / 100 peak_spend_money = peak_spend_money / 100 normal_spend_money = normal_spend_money / 100 valley_spend_money = valley_spend_money / 100 total_spend_elec = total_spend_elec / 100 total_spend_money = total_spend_money / 100 if reason == StopReason.NO_SUFFICIENT_BALANCE: desc = '余额不足' elif reason == StopReason.CHARGE_TIME_DONE: desc = '已充电到指定时间' elif reason == StopReason.CHARGE_ELEC_DONE: desc = '已充电到指定电量' elif reason == StopReason.CHARGE_MONEY_DONE: desc = '已充电到指定金额' elif reason == StopReason.SCRAM_BUTTON_STOP: desc = '急停按钮被按下,请联系管理员或客服' elif reason == StopReason.CC_DISCONNECT: desc = '枪把断开连接,请稍候再试' elif reason == StopReason.CP_SIGNAL_ABNORMAL: desc = '电压信号异常,请稍候再试' elif reason == StopReason.CHARGE_DONE: desc = '充电已完成' elif reason == StopReason.CURRENT_OVERLOAD: desc = '电流超载,请稍候再试' elif reason == StopReason.ELECTRIC_METER_FAILURE: desc = '电表故障,请联系管理员或客服' elif reason == StopReason.CHARGING_PILE_DISABLE: desc = '充电桩被远程停止已停用' elif reason == StopReason.CP_DISCONNECT: desc = '充电枪断开连接' elif reason == StopReason.USER_CARD_STOP: desc = '刷卡停止' elif reason == StopReason.CHARGING_PILE_POWER_OUTAGES: desc = '充电桩断电,请联系管理员或客服' elif reason == StopReason.ELEC_PRICE_EQUAL_ZERO: desc = '电价设置异常,请联系管理员或客服' else: desc = '' return { 'cmdCode': '36', 'seqNo': seqNo, 'port': port, 'mode': mode, 'startTime': startTime, 'finishTime': finishTime, 'eDuration': eDuration, 'top_spend_elec': top_spend_elec, 'peak_spend_elec': peak_spend_elec, 'normal_spend_elec': normal_spend_elec, 'valley_spend_elec': valley_spend_elec, 'top_spend_money': top_spend_money, 'peak_spend_money': peak_spend_money, 'normal_spend_money': normal_spend_money, 'valley_spend_money': valley_spend_money, 'total_spend_elec': total_spend_elec, 'total_spend_money': total_spend_money, 'reason': desc } if cmdcode == '79': return { 'cmdCode': '79' } if cmdcode == '34': return { 'cmdCode': '34' } # 启动设备 def start_device(self, package, openId, attachParas): chargeIndex = attachParas.get("chargeIndex") if not chargeIndex: raise ServiceException({'result': 2, 'description': u'请您选择合适的充电线路'}) if not openId: raise ServiceException({"result": 2, "description": u"本设备暂不支持上分"}) devStatus = self.get_port_status_from_dev() if devStatus[chargeIndex]['status'] != Const.DEV_WORK_STATUS_CONNECTED: raise ServiceException( {'result': 2, 'description': u'车辆未连接,请先连接车辆!'}) mode, chargeParam, finishedTime = self._suit_package(package) seqNo = str(self._make_seqNo(chargeIndex, self.device.devNo)) order = ConsumeRecord.objects.get(orderNo=attachParas["orderNo"]) # type: ConsumeRecord order.sequanceNo = seqNo order.save() balance = int((VirtualCoin(package['price']) * 100)) result = self._start_remote(chargeIndex, seqNo, mode, chargeParam, balance) portDict = { 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'status': Const.DEV_WORK_STATUS_WORKING, 'finishedTime': finishedTime, 'coins': float(balance) / 100, 'isStart': True, 'sequanceNo': seqNo, 'orderNo': attachParas['orderNo'], 'useType': 'mobile', 'openId': openId, 'refunded': False, 'chargeMode': mode, 'need': chargeParam, } Device.update_dev_control_cache(self._device['devNo'], {str(chargeIndex): portDict}) result["finishedTime"] = finishedTime return result # 停止设备 def stop(self, port=None): if not port: raise ServiceException({"result": 2, "description": u"请选择需要结束的充电端口"}) portCache = Device.get_port_control_cache(self.device.devNo, str(port)) seqNo = portCache.get("sequanceNo") if not seqNo: raise ServiceException({"result": 2, "description": u"当前端口无工作"}) return self._stop_remote(port, seqNo) # 获取端口运行信息 def get_port_info(self, line): ctrInfo = Device.get_dev_control_cache(self._device['devNo']) value = ctrInfo.get(line, {}) data = self.check_real_elec(line) data_list = {'port': line, 'sequanceNo': value['sequanceNo'], 'usedTime': data['eduration'], 'elec': data['total_elec'], 'power': data['output_power'], 'outputVoltage': data['output_voltage'], 'elecFee':data['total_spend']} serviceChargeOn = self.device.bill_as_service_feature.on if serviceChargeOn: serviceFee = self.caculate_consume(data) data_list.update({'serviceFee':serviceFee}) consumeMoney = data['total_spend'] + serviceFee data_list.update({'consumeMoney':consumeMoney}) else: data_list.update({'consumeMoney': data['total_spend']}) return data_list # 获取端口状态 def get_port_status_from_dev(self): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {"IMEI": self.device.devNo, "funCode": '41', "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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) result = {} data = devInfo['data'][8:14] portNum = int(data[0:2], 16) portData = data[2::] ii = 0 portNo = 1 while ii < portNum: port = portNo statusTemp = portData[ii * 2: ii * 2 + 2] if statusTemp == '00': status = {'status': Const.DEV_WORK_STATUS_FAULT} elif statusTemp == '55': status = {'status': Const.DEV_WORK_STATUS_PAUSE} elif statusTemp == '10': status = {'status': Const.DEV_WORK_STATUS_IDLE} elif statusTemp == '11': status = {'status': Const.DEV_WORK_STATUS_CONNECTED} elif statusTemp == '12': status = {'status': Const.DEV_WORK_STATUS_WORKING} elif statusTemp == '13': status = {'status': Const.DEV_WORK_STATUS_FINISHED} elif statusTemp == '14': status = {'status': Const.DEV_WORK_STATUS_FAULT} elif statusTemp == '15': status = {'status': Const.DEV_WORK_STATUS_FAULT} elif statusTemp == '16': status = {'status': Const.DEV_WORK_STATUS_WORKING} else: status = {'status': Const.DEV_WORK_STATUS_FAULT} ii += 1 portNo += 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 set_device_function_param(self, request, lastSetConf): if request.POST.has_key('top_price_rate') and request.POST.has_key('peak_price_rate') and request.POST.has_key( 'normal_price_rate') and request.POST.has_key('valley_price_rate') and request.POST.has_key( 'half_hour_price_list'): if request.POST.has_key('pile_pause'): self._control_device(pile_instruct=1, port_instruct=1) return elif request.POST.has_key('pile_continue'): self._control_device(pile_instruct=0, port_instruct=1) return elif request.POST.has_key('pile_reboot'): self._control_device(pile_instruct=2, port_instruct=1) return lastSetConf.update({'top_price_rate': float(request.POST.get('top_price_rate', 0))}) lastSetConf.update({'peak_price_rate': float(request.POST.get('peak_price_rate', 0))}) lastSetConf.update({'normal_price_rate': float(request.POST.get('normal_price_rate', 0))}) lastSetConf.update({'valley_price_rate': float(request.POST.get('valley_price_rate', 0))}) lastSetConf.update({'half_hour_price_list': request.POST.get('half_hour_price_list', 0)}) self.set_elec_conf(lastSetConf) # self.set_elec_charge_by_device(lastSetConf) def set_elec_conf(self, infoDic): top_price_rateHex = binascii.hexlify( binascii.unhexlify(fill_2_hexByte(hex(int(infoDic['top_price_rate'] * 100)), 4))[::-1]) peak_price_rateHex = binascii.hexlify( binascii.unhexlify(fill_2_hexByte(hex(int(infoDic['peak_price_rate'] * 100)), 4))[::-1]) normal_price_rateHex = binascii.hexlify( binascii.unhexlify(fill_2_hexByte(hex(int(infoDic['normal_price_rate'] * 100)), 4))[::-1]) valley_price_rateHex = binascii.hexlify( binascii.unhexlify(fill_2_hexByte(hex(int(infoDic['valley_price_rate'] * 100)), 4))[::-1]) half_hour_priceHex = ''.join( fill_2_hexByte(hex(int(half_hour_price)), 2) for half_hour_price in infoDic['half_hour_price_list']) data = top_price_rateHex + peak_price_rateHex + normal_price_rateHex + valley_price_rateHex + half_hour_priceHex + '{:0>16}'.format( 0) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '49', '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_dev_setting(self): result = MessageSender.send( device=self.device, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, payload={ "IMEI": self._device["devNo"], "data": "55", "funCode": "48" } ) rst = result.get("rst") if rst == -1: raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'}) elif rst == 1: raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) elif rst == 0: resultDict = self._parse_config_change_upload(result['data']) driverCode = self._device.get("devType", dict()).get("code", "") resultDict.update({'driverCode': driverCode}) return resultDict def get_port_status(self, force=False): if force: return self.get_port_status_from_dev() statusDict = {} # self.async_update_portinfo_from_dev() self.get_port_status_from_dev() ctrInfo = Device.get_dev_control_cache(self._device['devNo']) allPorts = ctrInfo.get('allPorts', 2) 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 active_deactive_port(self, port, active): if not active: self.stop(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 check_real_elec(self, port): data = "{:0>2X}".format(int(port)) result = self._send_data('44', data) rst = result.get("rst") if rst != 1: if rst == -1: raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'}) elif rst == 1: raise ServiceException({'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) elec_info = result.get("data")[8:] ii = 0 port_str = str(int(elec_info[ii:ii + 2])) output_voltage = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 2:ii + 6])[::-1]), 16)) output_current = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 6:ii + 10])[::-1]), 16)) output_power = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 10:ii + 14])[::-1]), 16)) eduration = int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 14:ii + 18])[::-1]), 16) top_elec = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 18:ii + 22])[::-1]), 16)) peak_elec = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 22:ii + 26])[::-1]), 16)) normal_elec = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 26:ii + 30])[::-1]), 16)) valley_elec = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 30:ii + 34])[::-1]), 16)) total_elec = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 34:ii + 38])[::-1]), 16)) top_spend = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 38:ii + 42])[::-1]), 16)) peak_spend = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 42:ii + 46])[::-1]), 16)) normal_spend = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 46:ii + 50])[::-1]), 16)) valley_spend = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 50:ii + 54])[::-1]), 16)) total_spend = float(int(binascii.hexlify(binascii.unhexlify(elec_info[ii + 54:ii + 58])[::-1]), 16)) output_voltage = int(output_voltage * 0.1) output_current = output_current / 100 output_power = output_power eduration = eduration / 60 top_elec = top_elec / 100 peak_elec = peak_elec / 100 normal_elec = normal_elec / 100 valley_elec = valley_elec / 100 total_elec = total_elec / 100 top_spend = top_spend / 100 peak_spend = peak_spend / 100 normal_spend = normal_spend / 100 valley_spend = valley_spend / 100 total_spend = total_spend / 100 new_data = { 'port': port_str, 'output_voltage': output_voltage, 'output_current': output_current, 'output_power': output_power, 'eduration': eduration, 'top_elec': top_elec, 'peak_elec': peak_elec, 'normal_elec': normal_elec, 'valley_elec': valley_elec, 'total_elec': total_elec, 'top_spend': top_spend, 'peak_spend': peak_spend, 'normal_spend': normal_spend, 'valley_spend': valley_spend, 'total_spend': total_spend, } return new_data def get_elec_charge(self): # 从主板获取到各时段费费率 resultDict = self.get_dev_setting() # 查找当前时段的费率 nowTime = datetime.datetime.now().strftime('%H:%M') timeNowList = nowTime.split(':') index = int(timeNowList[0])*2 + 2 if int(timeNowList[1])>30 else 1 - 1 nowElecChargeRate = resultDict['half_hour_price_list'][index] if nowElecChargeRate == '1': nowElecCharge = resultDict['valley_price_rate'] elif nowElecChargeRate == '2': nowElecCharge = resultDict['normal_price_rate'] elif nowElecChargeRate == '3': nowElecCharge = resultDict['peak_price_rate'] elif nowElecChargeRate == '4': nowElecCharge = resultDict['top_price_rate'] return nowElecCharge def set_elec_charge_by_dealer(self,elecCharge): IntElecCharge = float(elecCharge) infoDic = { 'top_price_rate': IntElecCharge, 'peak_price_rate': IntElecCharge, 'normal_price_rate': IntElecCharge, 'valley_price_rate': IntElecCharge, 'half_hour_price_list': [IntElecCharge] * 48 } self.set_elec_conf(infoDic) def set_elec_charge_by_device(self,lastSetConf): half_hour_price_list = lastSetConf['half_hour_price_list'] for i in range(len(half_hour_price_list)): if half_hour_price_list[i] == '01': half_hour_price_list[i] = 'top_price_rate' elif half_hour_price_list[i] == '02': half_hour_price_list[i] = 'peak_price_rate' elif half_hour_price_list[i] == '03': half_hour_price_list[i] = 'normal_price_rate' elif half_hour_price_list[i] == '04': half_hour_price_list[i] = 'valley_price_rate' elecCharge = { 'top_price_rate' :lastSetConf['top_price_rate'], 'peak_price_rate' :lastSetConf['peak_price_rate'], 'normal_price_rate' :lastSetConf['normal_price_rate'], 'valley_price_rate' :lastSetConf['valley_price_rate'], 'half_hour_price_list': half_hour_price_list, } Device.get_collection().update_one({'devNo': self._device['devNo']}, { '$set': { 'devType.features.billAsService.elecCharge':elecCharge } }) Device.invalid_device_cache(self._device['devNo']) def caculate_consume(self,data): serviceCharge = self._device.bill_as_service_feature.service_charge elec = data['total_elec'] serviceFee = round(serviceCharge * elec,2) return serviceFee # def get_current_elec_charge_by_database(self): # device = None # para = device.bill_as_service_feature # half_hour_price_list = para.elecCharge.half_hour_price_list # nowTime = datetime.datetime.now().strftime('%H:%M') # timeNowList = nowTime.split(':') # index = int(timeNowList[0]) * 2 + 2 if int(timeNowList[1]) > 30 else 1 - 1 # currentElecChargeRate = half_hour_price_list['half_hour_price_list'][index] # if currentElecChargeRate == '01': # elecCharge = para.elecCharge.top_price_rate # elif currentElecChargeRate == '02': # elecCharge = para.elecCharge.peak_price_rate # elif currentElecChargeRate == '03': # elecCharge = para.elecCharge.normal_price_rate # elif currentElecChargeRate == '04': # elecCharge = para.elecCharge.valley_price_rate # return elecCharge # 从参数设置中配置电费时电费信息存入数据库 # 获取参数设置时电费信息存入数据库 # 经销商配置充电费时直接下发到设备 # 绑定设备时,默认信息直接下发到设备(避免出bug) # 获取从数据库中拿,不走设备 # 查询当前服务费 # 推送信息