# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import time from decimal import Decimal from apilib.monetary import RMB from apilib.utils_AES import EncryptDate from apps.web.constant import DeviceCmdCode, Const, MQTT_TIMEOUT, ErrorCode from apps.web.core.adapter.base import SmartBox from apps.web.core.exceptions import ServiceException from apps.web.core.networking import MessageSender from apps.web.device.models import Device, DeviceType from apps.web.user.models import Card, ServiceProgress, ConsumeRecord cardKey = 'FR4e1OFCnDdrYA7u' class ChargingSocketBox(SmartBox): def __init__(self, device): super(ChargingSocketBox, self).__init__(device) def translate_funcode(self, fun_code): fun_codeDict = { '01': u'查询所有端口状态', '02': u'查询端口详细信息', '03': u'上报投币充电事件', '04': u'上报刷卡事件', '05': u'上报充电结束事件', '06': u'远程停止充电', '07': u'远程启动充电', '08': u'查询投币总额', '09': u'清除投币总数', '0A': u'查询订单信息', } return fun_codeDict.get(fun_code, '') def translate_event_cmdcode(self, cmdCode): cmdDict = { } return cmdDict.get(cmdCode, '') def check_dev_status(self, attachParas=None): if attachParas.get('isTempPackage') == True: washConfig = self.device.get('tempWashConfig', {}) else: washConfig = self.device.get('washConfig', {}) packageId = attachParas.get('packageId') if not packageId: # 此时为快捷启动充电之前已经校验过一次 return package = washConfig.get(packageId) self._check_package(package) port = int(attachParas['chargeIndex']) port_stat = self.get_port_status_from_dev().get(str(port), {}) if port_stat.get('status') not in [Const.DEV_WORK_STATUS_CONNECTED, Const.DEV_WORK_STATUS_WORKING]: raise ServiceException({'result': 2, 'description': u'请先连接充电插座,再启动充电'}) if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get('price') == 0: if port_stat.get('status') == Const.DEV_WORK_STATUS_WORKING: raise ServiceException({'result': 2, 'description': u'当前端口已处于工作状态,无法使用充满自停套餐, 请换个端口进行充电'}) def get_port_info(self, port): data = {'fun_code': 2, 'port': int(port)} devInfo = self.send_mqtt(data) portInfo = devInfo.get('data', {}) result = {} pay_unit = self.show_pay_unit exec_orders = portInfo.get('exec_orders', []) _wait = [] for exec_order in exec_orders: if exec_order['status'] == 'running': result['voltage'] = round(portInfo.get('volt', 0), 2) result['power'] = round(portInfo.get('watt', 0), 2) result['ampere'] = round((portInfo.get('ampr', 0) * 0.001), 2) result['coins'] = '{}'.format(round(exec_order['amount'] / 100.0, 2)) result['usedTime'] = round(exec_order.get('time', 0) / 60.0, 1) result['usedElec'] = round(exec_order.get('elec', 0) * 0.000001, 4) result['startTime'] = datetime.datetime.fromtimestamp(int(exec_order['exec_time'])).strftime( '%m-%d %H:%M:%S') if exec_order['chrmt'] == 'TIME': result['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1) result['needTime'] = '{}分钟'.format(round(exec_order['amount_time'] / 60.0, 1)) elif exec_order['chrmt'] == 'ELEC': result['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2) result['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4) else: pass if exec_order['order_type'] == 'apps_start': result['consumeType'] = 'mobile' result['consumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), pay_unit) result['leftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2), pay_unit) try: orderNo = exec_order['id'] order = ConsumeRecord.objects.filter(orderNo=orderNo).first() if not order: result['nickName'] = '经销商上分' else: result['nickName'] = order.user.nickname package = order.package if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get( 'price') == 0: # 后付费 result['consumeType'] = 'postpaid' result['needTime'] = '充满自停' result.pop('needElec', None) result.pop('leftMoney', None) result.pop('leftTime', None) result.pop('leftElec', None) except: pass if exec_order['order_type'] == 'card_start': result['consumeType'] = 'card' result['cardNo'] = exec_order['card_no'] result['cardConsumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), pay_unit) result['cardLeftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2), pay_unit) result['cardBalance'] = '{}{}'.format(round(exec_order['balance'] * 0.01, 2), pay_unit) try: card = Card.objects.get(cardNo=exec_order['card_no']) result['nickName'] = card.cardName or card.nickName except: pass else: pass if exec_order['status'] == 'waiting': _one = {} if exec_order['chrmt'] == 'TIME': _one['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1) _one['needTime'] = '{}分钟'.format(round(exec_order['amount_time'] / 60.0, 1)) elif exec_order['chrmt'] == 'ELEC': _one['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4) _one['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2) else: pass if exec_order['order_type'] == 'apps_start': _one['consumeType'] = 'mobile' _one['coins'] = '{}{}'.format(round(exec_order['amount'] / 100.0, 2), pay_unit) try: order = ConsumeRecord.objects.filter(orderNo=exec_order['id']).first() if not order: _one['nickName'] = '经销商上分' else: _one['nickName'] = order.user.nickname except Exception: pass elif exec_order['order_type'] == 'card_start': _one['consumeType'] = 'card' _one['coins'] = '{}{}'.format(round(exec_order['amount'] / 100.0, 2), pay_unit) _one['cardNo'] = exec_order['card_no'] _one['cardBalance'] = '{}{}'.format(round(exec_order['balance'] * 0.01, 2), pay_unit) try: card = Card.objects.get(cardNo=exec_order['card_no']) _one['nickName'] = card.cardName or card.nickName except: pass else: pass _wait.append(_one) if _wait: result['waittingOrder'] = _wait return result def send_mqtt(self, data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, timeout=10): """ 发送mqtt 指令默认210 返回data """ payload = {'IMEI': self.device.devNo, 'data': data} result = MessageSender.send(self.device, cmd, payload=payload, timeout=timeout) if not result.has_key('rst'): raise ServiceException({'result': 2, 'description': u'报文异常'}) if result['rst'] == -1: raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'}) if result['rst'] == 1: raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'}) if result['rst'] == 2: raise ServiceException({'result': 2, 'description': u'订单已满'}) if result['rst'] == 3: raise ServiceException({'result': 2, 'description': u'端口已被禁用'}) if result['rst'] == 4: raise ServiceException({'result': 2, 'description': u'检测插头未连接,请先插上插头后再使用'}) if result['rst'] == 5: raise ServiceException({'result': 2, 'description': u'计费类型无效'}) if result['rst'] == 7: raise ServiceException({'result': 2, 'description': u'端口计量故障'}) else: if cmd in [DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE]: return if result.get('data') == '00': raise ServiceException({'result': 2, 'description': u'设备操作失败.请重试'}) else: return result def check_params_range(self, params, minData=None, maxData=None, desc=''): # type:(str,float,float,str) -> str """ 检查参数,返回字符串参数 """ if params is None: raise ServiceException({'result': 2, 'description': u'{} 参数错误(值为空).'.format(desc)}) 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超出可选范围(值为: %s),可选最大值为%g' % (desc, params, 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超出可选范围(值为: %s),可选最小值为%g' % (desc, params, 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参数超出可选范围(值为: %s),可取范围为%g-%g' % (desc, params, minData, maxData)}) def test(self, coins): data = {'fun_code': 0x07, 'order_id': '1111', 'coins': coins, 'port': 1, 'time': 60} devInfo = self.send_mqtt(data) return devInfo def _check_package(self, package): """ 获取设备启动的发送数据 根据设备的当前模式以及套餐获取 :param package: :return: """ unit = package.get('unit') _time = package.get('time') chrmt = self.device['otherConf'].get('chrmt') if not chrmt: chrmt = self.get_dev_setting().get('chrmt') # 按时间计费 if chrmt == 'TIME' or chrmt == 'POWER': billingType = 'time' if unit == u'小时': _time = _time * 60 elif unit == u'天': _time = _time * 24 * 60 elif unit == u'秒': _time = _time / 60 elif unit == u'分钟': _time = _time else: raise ServiceException({'result': 2, 'description': u'套餐单位错误,应选取单位(时间),请联系经销商'}) # 按电量计费 elif chrmt == 'ELEC': billingType = 'elec' if unit != u'度': raise ServiceException({'result': 2, 'description': u'套餐单位错误,应选取单位(度),请联系经销商'}) else: _time = _time * 100 else: raise ServiceException({'result': 2, 'description': u'套餐单位错误,应选取单位(时间,度),请联系经销商'}) return _time, unit, billingType # 访问设备,获取设备端口信息 def get_port_status_from_dev(self): data = {'fun_code': 0x01, 'all': True} devInfo = self.send_mqtt(data) portData = devInfo['data']['port_stat'] result = {} for k, v in portData.items(): if v == 'idle': result[k] = {'status': Const.DEV_WORK_STATUS_IDLE} elif v == 'link': result[k] = {'status': Const.DEV_WORK_STATUS_CONNECTED} elif v == 'busy': result[k] = {'status': Const.DEV_WORK_STATUS_WORKING} elif v == 'fault': result[k] = {'status': Const.DEV_WORK_STATUS_FAULT} elif v == 'forbid': result[k] = {'status': Const.DEV_WORK_STATUS_FORBIDDEN} else: result[k] = {'status': Const.DEV_WORK_STATUS_FAULT} 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 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 not ctrInfo.has_key('allPorts'): self.get_port_status_from_dev() ctrInfo = Device.get_dev_control_cache(self._device['devNo']) allPorts = ctrInfo.get('allPorts', 2) 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 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'请您选择合适的充电线路'}) port = int(attachParas['chargeIndex']) _time, unit, billingType = self._check_package(package) if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get('price') == 0: coins = 10 * 100 else: coins = int(float(package['coins']) * 100) # 单位为分 if attachParas.get('onPoints'): orderNo = ConsumeRecord.make_no() + self.device.owner.username else: orderNo = attachParas.get('orderNo') data = { 'fun_code': 0x07, 'port': port, 'amount': coins, 'order_id': orderNo } devInfo = self.send_mqtt(data, timeout=MQTT_TIMEOUT.START_DEVICE) ctrInfo = Device.get_dev_control_cache(self.device.devNo) lineInfo = ctrInfo.get(str(port), {}) if not lineInfo or lineInfo.get('status') == Const.DEV_WORK_STATUS_IDLE: lineInfo = { 'port': str(port), 'status': Const.DEV_WORK_STATUS_WORKING, 'order_type': 'apps_start', 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'orderNo': orderNo, } Device.update_port_control_cache(self._device['devNo'], lineInfo) devInfo['consumeOrderNo'] = orderNo devInfo['sequanceNo'] = orderNo if billingType == 'time': devInfo['finished_time'] = int(time.time()) + _time * 60 else: devInfo['finished_time'] = int(time.time()) + 3600 * 12 devInfo['ignoreService'] = True devInfo['servicedInfo'] = { 'chargeIndex': port } return devInfo def active_deactive_port(self, port, active): if active: raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'}) return self.stop_charging_port(port) # 停止该端口下的所有任务 def stop_charging_port(self, port): data = {'fun_code': 0x06, 'port': port} devInfo = self.send_mqtt(data) if devInfo['rst'] == 0: Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}}) return True if devInfo['rst'] == 0 else False def analyze_event_data(self, data): if data['fun_code'] == '32': # 成功启动设备需要回复该事件 return data['order'] if data['fun_code'] == '34': # 如果是结束事件,需要把reason翻译出来 descDict = { 'outofmoney': u'购买的充电时间或电量用完了', 'userstop': u'用户远程结束充电', 'adminstop': u'管理员远程结束充电', 'dealerstop': u'经销商远程结束充电', 'unplug': u'未检测到充电器, 结束充电', 'wattoverload': u'功率过载, 结束充电', 'voltoverload': u'电压过载, 结束充电', 'amproverload': u'电流过载, 结束充电', 'machoverload': u'整机功率过载, 结束充电', 'tempexcursion': u'温度过载, 结束充电', 'stopforfull': u'充满自停, 结束充电' } order = data['order'] order['reasonDesc'] = descDict.get(str(order['cause_desc']), u'') data['order'] = order return data def ack_event(self, order_id, fun_code): data = {'order_id': order_id, 'fun_code': fun_code} self.send_mqtt(data) def get_card_pwd(self): devInfo = self.send_mqtt({'fun_code': 17}) data = devInfo.get('data', {}) card_cur_key = data.get('card_cur_key') enObj = EncryptDate(cardKey) card_cur_key = enObj.decrypt(card_cur_key) return {'card_pwd': card_cur_key} def set_device_function(self, request, lastSetConf): if request.POST.has_key('clearSum'): self.clear_dev_feecount() elif request.POST.has_key('reboot'): self.reboot_device() def set_device_function_param(self, request, lastSetConf): """ 设置参数 对于计费模式做一下转换 顺便服务器保留一份 :param request: :param lastSetConf: :return: """ # 服务器侧的参数 先处理掉 if request.POST.get('id_card_oncefee') is not None: id_card_oncefee = request.POST['id_card_oncefee'] if not id_card_oncefee: raise ServiceException({'result': 2, 'description': u'在线卡单次刷卡金额不能为0'}) Device.get_collection().update_one(filter={'devNo': self.device.devNo}, update={'$set': { 'otherConf.id_card_oncefee': round(float(id_card_oncefee), 2), }}) Device.invalid_device_cache(self.device.devNo) if request.POST.get('refundProtection') is not None: refundProtection = request.POST['refundProtection'] Device.get_collection().update_one(filter={'devNo': self.device.devNo}, update={'$set': { 'otherConf.refundProtection': round(float(refundProtection), 2), }}) Device.invalid_device_cache(self.device.devNo) if request.POST.get('minAfterStartCoins') is not None: minAfterStartCoins = request.POST['minAfterStartCoins'] Device.get_collection().update_one(filter={'devNo': self.device.devNo}, update={'$set': { 'otherConf.minAfterStartCoins': round(float(minAfterStartCoins), 2), }}) Device.invalid_device_cache(self.device.devNo) # 参数发向设备 11, 16指令 setconfig1 = {'fun_code': 11} setconfig2 = {'fun_code': 16} # 音量适配 if request.POST.get('volume_list'): volume_list = request.POST.get('volume_list') volumes = {} self.check_params_range(params=request.POST.get('volume'), minData=0.0, maxData=7.0, desc='语音音量参数') volumes.update({'default': int(request.POST.get('volume'))}) for obj in volume_list: self.check_params_range(params=obj['volume'], minData=0.0, maxData=7.0, desc='音量参数') volumes.update({'{}-{}'.format(obj['start'], obj['end']): int(obj['volume'])}) setconfig1.update({'volumes': volumes}) # 计价模式适配 chrmt = request.POST.get('chrmt') package_time = request.POST.get('package_time', []) package_elec = request.POST.get('package_elec', []) package_power = request.POST.get('package_power', []) if chrmt: price = {'ELEC': int(float(package_elec[0]['elec']) * 1000000)} # 组织功率收费价格参数 TIME = [] if chrmt == 'POWER': # 主板实际并没有power计费方式 实际为功率分档模式的换一种显示 for _item in package_power: if float(_item['price']) == 0: raise ServiceException({'result': 2, 'description': u'计费参数设置(按功率收费)价格不能为0'}) TIME.append( [int(_item['power']), round(1.0 / float(_item['price']) * 60 * 60, 1)] # 价格倍率 * 固定时间(60分钟) * 60秒 ) if not TIME: raise ServiceException({'result': 2, 'description': u'计费参数设置(按功率收费)缺少收费标准'}) setconfig1['chrmt'] = 'TIME' elif chrmt == 'TIME': # 时间模式下 的时间计费规则 for _item in package_time: TIME.append( [int(_item['power']), int(_item['time']) * 60] ) if not TIME: raise ServiceException({'result': 2, 'description': u'计费参数设置(按时间收费)缺少收费标准'}) price['TIME'] = TIME setconfig1['chrmt'] = 'TIME' elif chrmt == 'ELEC': # 同样也处理一次时间计费规则 用于下发给设备 for _item in package_time: TIME.append( [int(_item['power']), int(_item['time']) * 60] ) setconfig1['chrmt'] = 'ELEC' price['TIME'] = TIME setconfig1.update({'price': price}) if request.POST.get('auto_close') is not None: setconfig1.update({'auto_close': request.POST.get('auto_close')}) if request.POST.get('float_time') or request.POST.get('float_watt') or request.POST.get('check_time'): float_charge = {} if request.POST.get('float_time'): float_charge['float_time'] = int(request.POST.get('float_time')) if request.POST.get('float_watt'): float_charge['float_watt'] = int(request.POST.get('float_watt')) if request.POST.get('check_time'): float_charge['check_time'] = int(request.POST.get('check_time')) setconfig1.update({'float_charge': float_charge}) if request.POST.get('port_max_watt'): setconfig1.update({'port_max_watt': int(request.POST.get('port_max_watt'))}) if request.POST.get('port_max_ampr'): setconfig1.update({'port_max_ampr': int(request.POST.get('port_max_ampr'))}) if request.POST.get('mach_max_watt'): setconfig1.update({'mach_max_watt': int(request.POST.get('mach_max_watt'))}) if request.POST.get('mach_max_temp'): setconfig1.update({'mach_max_temp': int(request.POST.get('mach_max_temp'))}) if request.POST.get('mach_max_volt'): setconfig1.update({'mach_max_volt': int(request.POST.get('mach_max_volt'))}) if request.POST.get('noload_check_watt') or request.POST.get('noload_check_time'): noload_check = {} if request.POST.get('noload_check_watt'): noload_check['watt'] = int(request.POST.get('noload_check_watt')) if request.POST.get('noload_check_time'): noload_check['time'] = int(request.POST.get('noload_check_time')) setconfig1.update({'noload_check': noload_check}) if request.POST.get('card_pwd'): card_pwd = request.POST.get('card_pwd') card_pwd2 = request.POST.get('card_pwd2') if card_pwd != card_pwd2: raise ServiceException({'result': 2, 'description': u'两次密码输入不一致'}) self.check_pwd(card_pwd) enObj = EncryptDate(cardKey) setconfig2.update({'card_cur_key': enObj.encrypt(card_pwd)}) self.send_mqtt(setconfig1) unit_price = None if chrmt == 'TIME': unit_price = {'unit': '分钟', 'value': max(map(lambda _: _[1] / 60.0, setconfig1['price']['TIME']))} elif chrmt == 'POWER': unit_price = {'unit': '分钟', 'value': max(map(lambda _: _[1] / 60.0, setconfig1['price']['TIME']))} elif chrmt == 'ELEC': unit_price = {'unit': '度', 'value': round(setconfig1['price']['ELEC'] / 1000000.0, 2)} if unit_price: Device.get_collection().update_one(filter={'devNo': self.device.devNo}, update={'$set': { 'otherConf.unit_price': unit_price, 'otherConf.chrmt': chrmt, }}) Device.invalid_device_cache(self.device.devNo) if request.POST.get('card_refund', None) is not None: setconfig2.update({'card_refund': request.POST.get('card_refund')}) if request.POST.get('card_disable', None) is not None: setconfig2.update({'card_disable': request.POST.get('card_disable')}) if request.POST.get('card_timeout'): setconfig2.update({'card_timeout': int(request.POST.get('card_timeout'))}) if request.POST.get('card_oncefee'): setconfig2.update({'card_oncefee': int(float(request.POST.get('card_oncefee')) * 100)}) self.send_mqtt(setconfig2) def get_dev_setting(self): """ 获取参数显示在前台 :return: """ # 服务器侧的参数 otherConf = self.device['otherConf'] # 获取主板侧的参数 devInfo = self.send_mqtt({'fun_code': 12}) # 参数整合 data = dict() # ID卡刷卡一次的费用 data['id_card_oncefee'] = otherConf.get('id_card_oncefee', 1) data['refundProtection'] = otherConf.get('refundProtection', 5) data['minAfterStartCoins'] = otherConf.get('minAfterStartCoins', 0) configs = devInfo['data'] # 价格适配 price_for_time = configs['price']['TIME'] package_time = [] chrmt = configs.get('chrmt') # 按功率分档收费显示 for _item in price_for_time: package_time.append({'power': _item[0], 'time': round(_item[1] / 60.0, 1)}) # 按电量收费 price_for_elec = round(configs['price']['ELEC'] / 1000000.0, 4) package_elec = [{'elec': price_for_elec, 'price': 1}] # 电量的固定单位是1 # 按功率收费显示 package_power = [] for _item in price_for_time: package_power.append({'power': _item[0], 'price': round(1.0 / (_item[1] / 60.0 / 60.0), 2)}) # 计费规则的添加 有就显示服务器的, 没有就显示主板的 data.update({ 'package_time': package_time, 'package_elec': package_elec, 'package_power': package_power, 'chrmt': otherConf.get('chrmt', chrmt) # 以缓存的为准 }) # 浮充参数的添加 float_charge = configs.get('float_charge', {}) data.update(float_charge) data['auto_close'] = configs.get('auto_close', {}) data['mach_max_watt'] = configs.get('mach_max_watt', 0) data['port_max_ampr'] = configs.get('port_max_ampr', 0) data['port_max_watt'] = configs.get('port_max_watt', 0) data['mach_max_volt'] = configs.get('mach_max_volt', 0) data['mach_max_temp'] = configs.get('mach_max_temp', 0) # 空载适配 data.update({ 'noload_check_watt': int(configs['noload_check'].get('watt', 0)), 'noload_check_time': int(configs['noload_check'].get('time', 0)), }) # 音量适配 volume_list = [] for k, v in configs['volumes'].items(): item = {} if k == 'default': continue if '-' in k: item['start'], item['end'] = k.split('-') item['volume'] = v volume_list.append(item) data.update({ 'volume': configs['volumes']['default'], 'volume_list': volume_list }) # 17 指令 devInfo = self.send_mqtt({'fun_code': 17}) configs2 = devInfo.get('data') data['card_curmode'] = configs2['card_curmode'] data['card_refund'] = configs2['card_refund'] data['card_disable'] = configs2['card_disable'] # data['card_token'] = configs2['card_token'] data['card_timeout'] = configs2['card_timeout'] data['card_oncefee'] = round(configs2['card_oncefee'] / 100.0, 2) state = self.get_dev_consume_count() data.update(state) return data def get_dev_consume_count(self): data = {'fun_code': 8} devInfo = self.send_mqtt(data) total_card = round(devInfo.get('data', {}).get('total_card', 0) * 0.01, 2) return {'total_card': total_card} def reset_total_card(self): data = { 'fun_code': 9 } self.send_mqtt(data) def set_max_watt(self, max_watt): self.send_mqtt({'fun_code': 11, 'max_watt': int(max_watt)}) def lock_unlock_port(self, port, lock=True): portInfo = self.get_port_info(port) if portInfo and portInfo['status'] == Const.DEV_WORK_STATUS_WORKING and lock: raise ServiceException({'result': 2, 'description': u'端口正忙,请先关闭端口后,再禁止端口'}) typeStr = not lock self.send_mqtt({'port': int(port), 'enable': typeStr, 'fun_code': 13}) def check_pwd(self, pwd): if len(pwd) != 6: raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'}) for char in pwd: if not (char >= '0' and char <= '9'): raise ServiceException({'result': 2, 'description': u'密码必须是6位纯数字密码'}) return def get_card_mode(self): devInfo = self.send_mqtt({'fun_code': 17}) MAP_MODE = { 'NORMAL': 0, 'ISSUE': 1, 'MODKEY': 2, } result = {} result['card_mode'] = MAP_MODE.get(devInfo['data']['card_curmode']) return result def set_card_mode(self, setConf): cardMode = int(setConf.get('card_mode')) data = {'fun_code': 16} if cardMode == 0: data.update({'card_curmode': {'mod': 'NORMAL'}}) elif cardMode == 1: # 格式化为离线卡 self.check_pwd(setConf['new_pwd']) newPwd = setConf['new_pwd'] if not str(setConf['balance']).isdigit(): raise ServiceException({'result': 2, 'description': u'余额必须是数字'}) balance = int(setConf['balance']) if not (balance >= 0 and balance <= 5000): raise ServiceException({'result': 2, 'description': u'余额必须在0和5000元之间'}) card_dft_val = balance * 100 # 硬件模块记录的单位是角 enObj = EncryptDate(cardKey) data.update({'card_curmode': {'mod': 'ISSUE', 'cfg': {'card_new_key': enObj.encrypt(str(newPwd)), 'card_dft_val': card_dft_val}}}) elif cardMode == 2: self.check_pwd(setConf['new_pwd']) oldPwd = setConf.get('old_pwd', '') newPwd = setConf.get('new_pwd', '') enObj = EncryptDate(cardKey) data.update({'card_curmode': {'mod': 'MODKEY', 'cfg': {'card_old_key': enObj.encrypt(str(oldPwd)), 'card_new_key': enObj.encrypt(str(newPwd))}}}) self.send_mqtt(data) def response_card_charge_result(self, cardNo, result): self.send_mqtt({'fun_code': 36, 'card_no': cardNo, 'result': result}) def recharge_card(self, cardNo, money, orderNo=None): self.send_mqtt( {'fun_code': 36, 'result': 1, 'card_no': cardNo, 'charge': int(money * 100), 'order_id': orderNo}) card = Card.objects.filter(cardNo=cardNo, dealerId=self.device.ownerId).first() balance = card.balance + money return { 'result': ErrorCode.SUCCESS, 'description': '' }, balance def response_card_balance(self, cardNo, amount, balance, result): return self.send_mqtt({'fun_code': 35, 'card_no': cardNo, 'balance': RMB.yuan_to_fen(balance), 'result': result, 'amount': RMB.yuan_to_fen(amount)}) def get_current_use(self, **kw): base_data = kw.get('base_data') spDict = kw.get('spDict') sp = ServiceProgress.objects.filter(device_imei=self.device.devNo, port=spDict['port']).first() data = {'fun_code': 2, 'port': spDict.get('port')} devInfo = self.send_mqtt(data) portInfo = devInfo.get('data', {}) exec_orders = portInfo.get('exec_orders', []) running_order = None waiting_order = [] for exec_order in exec_orders: # 第一层筛选 if exec_order['id'] not in sp.consumes: sp.consumes.remove(exec_order['id']) if exec_order['status'] == 'running': running_order = exec_order elif exec_order['status'] == 'waiting': waiting_order.append(exec_order) if len(sp.consumes) == 0: # 上一单没有正常结束 刷新此单的状态 if running_order: sp.consumes.append(running_order['id']) sp.start_time = running_order['exec_time'] sp.isFinished = False sp.finished_time = sp.start_time + running_order['amount_time'] if waiting_order: for wait_one in waiting_order: sp.consumes.append(wait_one['id']) sp.finished_time = sp.start_time + wait_one['amount_time'] sp.save() pay_unit = self.show_pay_unit result_list = [] # 数据整理返回 for exec_order in exec_orders: item = {} item.update(base_data) item['orderNo'] = exec_order['id'] item['port'] = exec_order['port'] if exec_order['status'] == 'running': item['voltage'] = round(portInfo.get('volt', 0), 2) item['power'] = round(portInfo.get('watt', 0), 2) item['ampere'] = round((portInfo.get('ampr', 0) * 0.001), 2) item['usedTime'] = round(exec_order.get('time', 0) / 60.0, 1) # item['elec'] = round(exec_order.get('elec', 0) * 0.000001, 4) if exec_order['chrmt'] == 'TIME': item['needTime'] = '{}分钟'.format(round(exec_order.get('amount_time', 0) / 60.0, 1)) item['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1) elif exec_order['chrmt'] == 'ELEC': item['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2) item['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4) else: pass if exec_order['order_type'] == 'apps_start': item['consumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), pay_unit) item['leftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2), pay_unit) item['order'] = { 'orderNo': exec_order['id'], # 停止按钮传订单停单用 'coin': '{}{}'.format(round(exec_order.get('amount', 0) * 0.01, 2), pay_unit), 'port': exec_order['port'], 'consumeType': 'mobile', } try: orderNo = exec_order['id'] order = ConsumeRecord.objects.filter(orderNo=orderNo).first() package = order.package if package.get('name') == '充满自停' and package.get('coins') == 0 and package.get( 'price') == 0: # 后付费 item['order'] = { 'orderNo': exec_order['id'], # 停止按钮传订单停单用 'coin': '{}{}'.format(0, pay_unit), 'port': exec_order['port'], 'consumeType': 'postpaid' } item['needTime'] = '充满自停' item.pop('needElec', None) item.pop('leftMoney', None) item.pop('leftTime', None) item.pop('leftElec', None) elif order.attachParas.get('vCardId'): item['order']['consumeType'] = 'mobile_vcard' except: pass elif exec_order['order_type'] == 'card_start': item['cardNo'] = exec_order['card_no'] item['cardConsumeMoney'] = exec_order['card_no'] item['cardConsumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), pay_unit) item['cardLeftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2), pay_unit) item['order'] = { 'orderNo': exec_order['id'], # 停止按钮传订单停单用 'coin': '{}{}'.format(round(exec_order.get('amount', 0) * 0.01, 2), pay_unit), 'port': exec_order['port'], 'consumeType': 'card', } else: pass elif exec_order['status'] == 'waiting': if exec_order['chrmt'] == 'TIME': item['needTime'] = '{}分钟'.format(round(exec_order.get('amount_time', 0) / 60.0, 1)) item['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 1) elif exec_order['chrmt'] == 'ELEC': item['needElec'] = round(exec_order.get('amount_elec', 0) * 0.000001, 2) item['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 2) item['desc'] = '此订单已经下发到设备上,上一单运行完毕就会自动运行此订单' item['order'] = { 'orderNo': exec_order['id'], # 停止按钮传订单停单用 'coin': '{}币'.format(round(exec_order.get('amount', 0) * 0.01, 2)), 'port': exec_order['port'], 'consumeType': 'card' if 'cardNo' in exec_order else 'mobile', } if 'cardNo' in exec_order: item['cardNo'] = exec_order['card_no'] item.update(DeviceType.get_services_button(self.device['devType']['id'])) result_list.append(item) return result_list def isHaveStopEvent(self): return True def stop_by_order(self, port, orderNo): data = {'fun_code': 4, 'order_id': orderNo, 'operator': 'user'} self.send_mqtt(data) def clear_dev_feecount(self): data = {'fun_code': 0x09, 'total_coin': True, 'total_card': True} self.send_mqtt(data) def reboot_device(self): # 重启单片机 MessageSender.send(self.device, DeviceCmdCode.SET_DEVINFO, {'reset_mcu': True}) # 重启模块 MessageSender.send(self.device, DeviceCmdCode.SET_DEVINFO, {'restart': True}) @property def show_pay_unit(self): """ 前台显示付费的时候,目前有不同的客户希望 显示不同的单位 有的显示金币 有的显示元, 这个地方处理下 :return: """ if self.device['otherConf'].get('pay_unit'): return self.device['otherConf'].get('pay_unit') return u'币' def get_port_using_detail(self, port, ctrInfo, isLazy=False): return self.get_port_info(port) def stop(self, port=None): return self.stop_charging_port(int(port)) # def __translate_status_from_str(self, status): # dictConf = { # 'idle': Const.DEV_WORK_STATUS_IDLE, # 'busy': Const.DEV_WORK_STATUS_WORKING, # 'forbid': Const.DEV_WORK_STATUS_FORBIDDEN, # 'fault': Const.DEV_WORK_STATUS_FAULT, # 'running': Const.DEV_WORK_STATUS_WORKING # } # return dictConf.get(status, Const.DEV_WORK_STATUS_IDLE) # # def get_many_port_info(self, portList): # data = {'fun_code': 1, 'all': True} # devInfo = self.send_mqtt(data) # portInfo = devInfo['data'] # portParam = portInfo.get('port_param', {}) # exec_queue = portInfo.get('exec_queue', {}) # # pay_unit = self.show_pay_unit # resultDict = {} # for port, exec_orders in exec_queue.items(): # if port not in portList: # continue # result = {'index': port} # onePortParam = portParam.get(port, {}) # _wait = [] # for exec_order in exec_orders: # if exec_order['status'] == 'running': # # result['voltage'] = round(onePortParam.get('volt', 0), 2) # result['power'] = round(onePortParam.get('watt', 0), 2) # result['ampere'] = round((onePortParam.get('ampr', 0) * 0.001), 2) # result['devTemp'] = round((portInfo.get('mach_temp', 0)), 2) # result['status'] = self.__translate_status_from_str(exec_order['status']) # result['usedTime'] = round(exec_order.get('time', 0) / 60.0, 2) # result['usedElec'] = round(exec_order.get('elec', 0) * 0.000001, 4) # result['coins'] = '{}'.format(round(exec_order['amount'] / 100.0, 2)) # # if 'left_time' in exec_order: # result['leftTime'] = round(exec_order.get('left_time', 0) / 60.0, 2) # # elif 'left_elec' in exec_order: # result['leftElec'] = round(exec_order.get('left_elec', 0) * 0.000001, 4) # # if exec_order['order_type'] == 'apps_start': # result['consumeType'] = 'mobile' # result['consumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), # pay_unit) # result['leftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2), # pay_unit) # try: # orderNo = exec_order['id'] # order = ConsumeRecord.objects.filter(orderNo=orderNo).first() # if not order: # result['nickName'] = '经销商上分' # else: # result['nickName'] = order.user.nickname # except Exception: # pass # # if exec_order['order_type'] == 'card_start': # result['consumeType'] = 'card' # try: # card = Card.objects.get(cardNo=exec_order['card_no']) # result['nickName'] = card.cardName or card.nickName # except: # pass # result['cardNo'] = exec_order['card_no'] # result['cardConsumeMoney'] = '{}{}'.format(round(exec_order.get('money', 0) * 0.01, 2), # pay_unit) # result['cardLeftMoney'] = '{}{}'.format(round(exec_order.get('left_money', 0) * 0.01, 2), # pay_unit) # result['cardBalance'] = '{}{}'.format(round(exec_order['balance'] * 0.01, 2), pay_unit) # # # elif exec_order['status'] == 'waiting': # _one = {} # if exec_order['order_type'] == 'apps_start': # _one['consumeType'] = 'mobile' # try: # order = ConsumeRecord.objects.filter(orderNo=exec_order['id']).first() # if not order: # _one['nickName'] = '经销商上分' # else: # _one['nickName'] = order.user.nickname # except Exception: # pass # elif exec_order['order_type'] == 'card_start': # _one['consumeType'] = 'card' # _one['cardNo'] = exec_order['card_no'] # _one['cardBalance'] = '{}{}'.format(round(exec_order['balance'] * 0.01, 2), pay_unit) # # try: # card = Card.objects.get(cardNo=exec_order['card_no']) # _one['nickName'] = card.cardName or card.nickName # except Exception: # pass # # if 'amount_time' in exec_order: # _one['needTime'] = '{}分钟'.format(round(exec_order['amount_time'] / 60.0, 1)) # if 'amount_elec' in exec_order: # _one['needElec'] = '{}度'.format(round(exec_order['amount_elec'] / 1000000.0, 2)) # if 'amount' in exec_order: # _one['coins'] = '{}{}'.format(round(exec_order['amount'] / 100.0, 2), pay_unit) # if 'create_time' in exec_order: # _one['createTime'] = datetime.datetime.fromtimestamp( # int(exec_order['create_time'])).strftime('%m-%d %H:%M:%S') # # _wait.append(_one) # # if _wait: # result['waittingOrder'] = _wait # # resultDict[port] = result # # return resultDict