# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging import re import threading import time from decimal import Decimal from django.core.cache import cache from mongoengine import Q from apilib.monetary import RMB from apilib.utils_AES import EncryptDate from apps import serviceCache from apps.web.common.proxy import ClientConsumeModelProxy from apps.web.constant import DeviceCmdCode, ErrorCode, Const, MQTT_TIMEOUT from apps.web.core.adapter.base import SmartBox from apps.web.core.exceptions import ServiceException, DeviceNetworkTimeoutError, StartDeviceError from apps.web.core.networking import MessageSender from apps.web.device.models import Device, DeviceType from apps.web.user.models import ServiceProgress, Card, MyUser, ConsumeRecord cardKey = 'FR4e1OFCnDdrYA7u' logger = logging.getLogger(__name__) class WeiFuLeCar(SmartBox): def __init__(self, device): super(WeiFuLeCar, self).__init__(device) self.port = '1' def analyze_event_data(self, device_data): uart_data = device_data.get('data') if not uart_data: return fun_code = uart_data.get('fun_code') if not fun_code: return billingType = 'elec' cmd = fun_code if cmd == '32': return uart_data.get('order') def disable_app_device(self, switch=True): # type:(bool) -> None otherConf = self.device.get('otherConf', {}) otherConf['disableDevice'] = switch Device.objects.filter(devNo=self.device['devNo']).update(otherConf=otherConf) Device.invalid_device_cache(self.device['devNo']) @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 send_mqtt(self, data=None, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, otherData=None, timeout=5): """ 发送mqtt 指令默认210 返回data """ if data: payload = {'data': data} else: payload = otherData result = MessageSender.send(self.device, cmd, payload, timeout=timeout) if 'rst' in result and result['rst'] != 0: if result['rst'] == -1: raise ServiceException( {'result': 2, 'description': u'该设备正在玩命找网络,请您稍候再试', 'rst': -1}) elif result['rst'] == 1: raise ServiceException( {'result': 2, 'description': u'该设备忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能', 'rst': 1}) 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.get('data', 'ok') def _do_update_configs(self, updateDict): dev = Device.objects.get(devNo=self.device.devNo) deviceConfigs = dev.otherConf.get('deviceConfigs', {}) deviceConfigs.update(updateDict) dev.otherConf['deviceConfigs'] = deviceConfigs dev.save() Device.invalid_device_cache(self.device.devNo) self._device = Device.get_dev(self.device.devNo) def _get_device_configs(self): return self.device.otherConf.get('deviceConfigs', {}) def _start(self, port, money, order_id): amount = int(float(money) * 100) data = { 'fun_code': 7, 'port': port, 'amount': amount, 'order_id': order_id } payload = {'data': data} return MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, payload, timeout=MQTT_TIMEOUT.START_DEVICE) def do_ack_order_32(self, order_id): data = { 'fun_code': 32, 'order_id': order_id } self.send_mqtt(data) def do_ack_remove_order_from_device_34(self, order_id): data = { 'fun_code': 34, 'order_id': order_id } self.send_mqtt(data) def _check_dev_status(self, port): data = { 'fun_code': 2, 'port': int(port) } data = self.send_mqtt(data) exec_orders = data.get('exec_task') or [] order_list = list(map(lambda x: x['id'], exec_orders)) result = False status = data.get('status') if status == 'fault': raise ServiceException({'result': 2, 'description': u'该充电桩出现故障,请使用其他充电桩'}) elif status == 'idle': raise ServiceException({'result': 2, 'description': u'请先连接充电枪'}) elif status == 'link': result = True elif status == 'estop': raise ServiceException({'result': 2, 'description': u'该充电桩处于 紧急停止 状态,请确认充电桩安全状态后,再次扫码使用或选择其他充电桩'}) elif status == 'ready': result = True elif status == 'busy': result = True else: pass return {'result': result, 'order_list': order_list} def _check_package(self, package): """ 获取设备启动的发送数据 根据设备的当前模式以及套餐获取 :param package: :return: """ unit = package.get('unit') _time = package.get('time') billingType = 'elec' if unit != u'度': raise ServiceException({'result': 2, 'description': u'套餐单位错误,应选取单位(度),请联系经销商'}) else: _time = _time return _time, unit, billingType def _transform_prices(self, prices, mode='send'): if mode == 'send': send_list = [] default_price = round(float(prices.get('default_price', 0)), 2) item = ['default', default_price] send_list.append(item) if all([prices.get('time1_start_m'), prices.get('time1_start_h'), prices.get('time1_end_m'), prices.get('time1_end_h'), prices.get('price1')]): time1_start_m = '{0:0>2}'.format(prices.get('time1_start_m')) time1_start_h = '{0:0>2}'.format(prices.get('time1_start_h')) time1_end_m = '{0:0>2}'.format(prices.get('time1_end_m')) time1_end_h = '{0:0>2}'.format(prices.get('time1_end_h')) price1 = round(float(prices.get('price1', 0)), 2) if time1_end_h + ':' + time1_end_m <= time1_start_h + ':' + time1_start_m: raise ServiceException({'result': 2, 'description': u'时段1结束时间必须大于起始时间'}) str = time1_start_h + ':' + time1_start_m + '-' + time1_end_h + ':' + time1_end_m item = [str, price1] send_list.append(item) else: raise ServiceException({'result': 2, 'description': u'时段1参数不完整'}) if all([prices.get('time2_start_m'), prices.get('time2_start_h'), prices.get('time2_end_m'), prices.get('time2_end_h'), prices.get('price2')]): time2_start_m = '{0:0>2}'.format(prices.get('time2_start_m')) time2_start_h = '{0:0>2}'.format(prices.get('time2_start_h')) time2_end_m = '{0:0>2}'.format(prices.get('time2_end_m')) time2_end_h = '{0:0>2}'.format(prices.get('time2_end_h')) price2 = round(float(prices.get('price2', 0)), 2) if time2_end_h + ':' + time2_end_m <= time2_start_h + ':' + time2_start_m: raise ServiceException({'result': 2, 'description': u'时段2结束时间必须大于起始时间'}) str = time2_start_h + ':' + time2_start_m + '-' + time2_end_h + ':' + time2_end_m item = [str, price2] send_list.append(item) else: raise ServiceException({'result': 2, 'description': u'时段2参数不完整'}) if all([prices.get('time3_start_m'), prices.get('time3_start_h'), prices.get('time3_end_m'), prices.get('time3_end_h'), prices.get('price3')]): time3_start_m = '{0:0>2}'.format(prices.get('time3_start_m')) time3_start_h = '{0:0>2}'.format(prices.get('time3_start_h')) time3_end_m = '{0:0>2}'.format(prices.get('time3_end_m')) time3_end_h = '{0:0>2}'.format(prices.get('time3_end_h')) price3 = round(float(prices.get('price3', 0)), 2) if time3_end_h + ':' + time3_end_m <= time3_start_h + ':' + time3_start_m: raise ServiceException({'result': 2, 'description': u'时段3结束时间必须大于起始时间'}) str = time3_start_h + ':' + time3_start_m + '-' + time3_end_h + ':' + time3_end_m item = [str, price3] send_list.append(item) else: raise ServiceException({'result': 2, 'description': u'时段3参数不完整'}) if not ( time3_start_h + ':' + time3_start_m >= time2_end_h + ':' + time2_end_m and time2_start_h + ':' + time2_start_m >= time1_end_h + ':' + time1_end_m): raise ServiceException({'result': 2, 'description': u'时段的其实时间不能小于上一个时段的结束时间'}) return send_list else: price_dict = {} index = 1 for price in prices: if price[0] == 'default': price_dict.update({'default_price': price[1]}) else: time1_start, time1_end = price[0].split('-') price_dict.update({ 'time{}_start_h'.format(index): time1_start.split(':')[0], 'time{}_start_m'.format(index): time1_start.split(':')[1], 'time{}_end_h'.format(index): time1_end.split(':')[0], 'time{}_end_m'.format(index): time1_end.split(':')[1], 'price{}'.format(index): price[1] }) index += 1 return price_dict def _reboot_device(self): data = { 'fun_code': 11, 'reset_mcu': True, } self.send_mqtt(data) def _restart_device(self): data = { 'restart': True, } self.send_mqtt(otherData=data, cmd=DeviceCmdCode.SET_DEVINFO) def _factory_set_device(self): data = { 'factory_set': True, } self.send_mqtt(otherData=data, cmd=DeviceCmdCode.SET_DEVINFO) def _get_current_order(self): data = { 'fun_code': 2, 'exec_orders': True, } data = self.send_mqtt(data) return data.get('exec_orders', []) def _get_total_card(self): data = { 'fun_code': 8 } data = self.send_mqtt(data) return {'total_card': int(data.get('total_card', 0)) / 100.0} def _reset_total_card(self): data = { 'fun_code': 9 } self.send_mqtt(data) def is_port_can_use(self, port, canAdd=False): return True, '' # data = { # 'fun_code': 2, # 'status': True, # 'exec_orders': True, # 'wait_orders': True, # } # data = self.send_mqtt(data) # exec_orders = data.get('exec_orders') # wait_orders = data.get('wait_orders') # # order_list = [] # if exec_orders: # order_list.append(exec_orders[0]['id']) # if wait_orders: # order_list += list(map(lambda x: x['id'], wait_orders)) # # status = data.get('status') # if status == 'fault': # return False, '该充电桩出现故障,请使用其他充电桩' # elif status == 'idle': # return False, '请先连接充电枪' # elif status == 'link': # return True, '' # elif status == 'estop': # raise False, '该充电桩处于 紧急停止 状态,请确认充电桩安全状态后,再次扫码使用或选择其他充电桩' # elif status == 'ready': # return True, '' # elif status == 'busy': # return True, '' # else: # return False, '该充电桩出现故障,请使用其他充电桩' 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', '1') package = washConfig.get(packageId) # self._check_package(package) port = attachParas.get('chargeIndex') if not port: raise ServiceException({'result': 2, 'description': u'请选择端口后再启动设备'}) data = self._check_dev_status(port) openId = attachParas.get('openId') order_list = data.get('order_list') result = data.get('result') if not order_list: return result else: consumeRcd = ConsumeRecord.objects.filter(devNo=self.device.devNo, orderNo=order_list[0]).first() if not consumeRcd: # 没有找到订单 证明是刷卡启动的 或则经销商远程上分 raise ServiceException({'result': 2, 'description': u'当前设备已经有其他人启动充电,请不要操作设备或充电枪, 小心触电!'}) else: if consumeRcd.openId != openId: raise ServiceException({'result': 2, 'description': u'当前设备已有人在使用,请您选择空闲的设备进行操作'}) else: return result def get_port_status(self, force=False): return self._get_port_status() def async_update_portinfo_from_dev(self): class Sender(threading.Thread): def __init__(self, smartBox): super(Sender, self).__init__() self._smartBox = smartBox def run(self): try: self._smartBox._get_port_status() except Exception as e: logger.info('get port stats from dev,e=%s' % e) sender = Sender(self) sender.start() 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.get('chargeIndex')) if not port: raise ServiceException({'result': 2, 'description': u'请选择端口后再启动设备'}) onPoints = attachParas.get('onPoints') if onPoints: # 远程上分 self._check_dev_status(port) orderNo = ConsumeRecord.make_no() logger.info('dealer onPoints package<{}> order<{}>'.format(package, orderNo)) else: orderNo = str(attachParas.get('orderNo')) coins = package.get('coins') result = self._start(port, coins, orderNo) if result['rst'] == 0: consumeOrder = { 'orderNo': orderNo, 'coin': package.get('coins'), 'consumeType': 'coin', } self.register_service_progress(openId, orderNo, port, consumeOrder, attachParas) elif result['rst'] == -1: # 网络丢失 raise DeviceNetworkTimeoutError() elif result['rst'] == 1: raise StartDeviceError('订单号已存在') elif result['rst'] == 2: raise StartDeviceError('订单已满') elif result['rst'] == 3: raise StartDeviceError('{}号端口被禁用'.format(port)) elif result['rst'] == 4: raise StartDeviceError('计量器故障') elif result['rst'] == 5: raise StartDeviceError('检查电压异常') elif result['rst'] == 6: raise StartDeviceError('设备急停状态') elif result['rst'] == 7: raise StartDeviceError('继电器故障') elif result['rst'] == 8: raise StartDeviceError('请连接充电器') elif result['rst'] == 9: raise StartDeviceError('车辆侧充电器开关未闭合') event_info = { 'cmd': 100, 'data': { 'fun_code': 32, 'order': { 'order_type': 'apps_start', 'id': orderNo, 'status': 'running', 'adapter': True } }, 'IMEI': '862167056713559', 'rst': 0 } return event_info def register_service_progress(self, openId, weifuleOrderNo, port, consumeOrder=None, attachParas=None): return ServiceProgress.objects.create( open_id=openId, device_imei=self.device.devNo, devTypeCode=self.device.devTypeCode, port=port, attachParas=attachParas if attachParas else {}, start_time=int(time.time()), finished_time=int(time.time() + 12 * 60 * 60), consumeOrder=consumeOrder if consumeOrder else {}, weifuleOrderNo=weifuleOrderNo, expireAt=datetime.datetime.now() + datetime.timedelta(days=1) ).id def get_port_info(self, port): data = cache.get('port_info_{}_{}'.format(self.device.devNo, port)) if data: return data else: data = { 'fun_code': 2, 'all': True } data = self.send_mqtt(data) exec_task = data.get('exec_orders', []) for task in exec_task: # 电量 task['elec'] = round((task.pop('elec', 0) / 1000000.0), 4) # 时间 task['time'] = round((task.pop('time', 0) / 60.0), 1) # 金额 task['money'] = round((task.pop('money', 0) / 100.0), 2) task['left_money'] = round((task.pop('left_money', 0) / 100.0), 2) task['amount'] = round((task.pop('amount', 0) / 100.0), 2) # 卡余额 if 'balance' in task: task['balance'] = round((task.pop('balance', 0) / 100.0), 2) data['power'] = round(data.pop('watt', 0), 2) data['voltage'] = round(data.pop('volt', 0), 2) data['ampere'] = round(data.pop('ampr', 0) / 1000.0, 2) cache.set('port_info_{}_{}'.format(self.device.devNo, port), data, 5) return data def lock_unlock_port(self, port, lock=True): data = { "fun_code": 13, "port": int(port), "enable": not lock } self.send_mqtt(data) def recharge_card(self, cardNo, money, orderNo=None): data = { 'card_no': cardNo, 'fun_code': 37, 'result': 1, 'charge': int(money * 100), 'order_id': orderNo } self.send_mqtt(data) card = Card.objects.filter(cardNo=cardNo, dealerId=self.device.ownerId).first() balance = card.balance + money return { 'result': ErrorCode.SUCCESS, 'description': '' }, balance def set_device_function(self, request, lastSetConf): update_dict = {'fun_code': 11} if request.POST.get('pile_disable') == True or request.POST.get('pile_disable') == False: update_dict.update({'pile_disable': request.POST['pile_disable']}) if request.POST.get('pile_restart') == True: self._restart_device() return if request.POST.get('czskze') == True: self._reset_total_card() return self.send_mqtt(update_dict) self.get_dev_setting() def set_device_function_param(self, request, lastSetConf): update_dict = {'fun_code': 11} if request.POST.get('volume'): self.check_params_range(request.POST.get('volume'), minData=0, maxData=7, desc='音量') update_dict.update({'volume': int(request.POST.get('volume'))}) if request.POST.get('max_ampr'): self.check_params_range(request.POST.get('max_ampr'), minData=0, maxData=32, desc='最大电流') update_dict.update({'max_ampr': int(request.POST.get('max_ampr'))}) if request.POST.get('temp_threshold'): self.check_params_range(request.POST.get('temp_threshold'), minData=0, maxData=150, desc='温度阈值') update_dict.update({'temp_threshold': int(request.POST.get('temp_threshold'))}) if request.POST.get('card_timeout'): self.check_params_range(request.POST.get('card_timeout'), minData=0, maxData=20, desc='刷卡超时时间') update_dict.update({'card_timeout': int(request.POST.get('card_timeout'))}) if request.POST.get('prices'): prices = [] for i, price in enumerate(request.POST.get('prices', [])): if i == 0: prices.append(['default', round(RMB(price['elec_fee']), 2), round(RMB(price['server_fee']), 2)]) else: prices.append( ['{}-{}'.format(price['start_time'], price['end_time']), round(RMB(price['elec_fee']), 2), round(RMB(price['server_fee']), 2)]) update_dict.update({'prices': prices}) if len(update_dict) > 1: self.send_mqtt(update_dict) if request.POST.get('sys_old_pwd'): password = serviceCache.get(self.pwd_cache_key()) if not password: raise ServiceException({'result': 2, 'description': u'当前页面已过期,请刷新后重试'}) enObj = EncryptDate(cardKey) password = enObj.decrypt(password) sys_old_pwd = request.POST.get('sys_old_pwd') sys_new_pwd = request.POST.get('sys_new_pwd') if password != sys_old_pwd: raise ServiceException({'result': 2, 'description': u'旧密码输入错误'}) result = re.findall(r'[0-9]{6}', sys_new_pwd) if not result or len(result[0]) != len(sys_new_pwd) or len(result[0]) < 6 or len(result[0]) > 10: raise ServiceException({'result': 2, 'description': u'新密码只能是6位数字'}) update_dict.update({'sys_pwd': enObj.encrypt(sys_new_pwd)}) self.send_mqtt(update_dict) serviceCache.set(self.pwd_cache_key(), enObj.encrypt(sys_new_pwd), 600) self.get_dev_setting() def get_dev_setting(self): def format_prices(prices): result = [] for price in prices: if price[0] == 'default': result.append({ 'elec_fee': price[1], 'server_fee': price[2], }) else: result.append({ 'start_time': price[0].split('-')[0], 'end_time': price[0].split('-')[1], 'elec_fee': price[1], 'server_fee': price[2], }) return result data = { 'fun_code': 12, 'all': True, } data = self.send_mqtt(data) result = {} result['max_ampr'] = data.get('max_ampr', 0) result['volume'] = data.get('volume', 0) result['pile_disable'] = data.get('pile_disable', False) result['card_timeout'] = data.get('card_timeout', 0) result['temp_threshold'] = data.get('temp_threshold', 0) result['prices'] = format_prices(data.get('prices', [])) if 'sys_pwd' in data: serviceCache.set(self.pwd_cache_key(), data['sys_pwd'], 600) self._do_update_configs(data) return result def get_port_status_from_dev(self): data = { 'fun_code': 2, 'all': True } data = self.send_mqtt(data) status = data.get('status') port = self.port result = [] item = { 'index': port, 'voltage': round(data.get('volt', 0), 2), 'power': round(data.get('watt', 0), 2), 'ampere': round(data.get('ampr', 0) * 0.001, 2), 'devTemp': round(data.get('temp', 0), 2), } if status == 'busy' or status == 'ready': item.update({'status': status}) exec_task = data.get('exec_orders', []) waittingOrder = [] for task in exec_task: # 启动方式 个人信息 consumeOrder = ConsumeRecord.objects.filter(Q(orderNo=task['id']) | Q(sequanceNo=task['id']), devNo=self.device.devNo).first() if task['order_type'] == 'apps_start': item['consumeType'] = 'mobile' if not consumeOrder: people = MyUser(nickname='经销商远程上分') else: people = consumeOrder.user item['nickName'] = people.nickname else: item['consumeType'] = 'card' item['cardNo'] = task['card_no'] if consumeOrder: card = Card.objects.filter(cardNo=task['card_no'], dealerId=self.device.ownerId).first() card and item.update({'nickName': card.nickName or card.cardName}) else: item.update({'nickName': '匿名用户'}) # 订单状态 if task['status'] == 'running': # 设备参数 # 电量 item['elec'] = round(task['elec'] / 1000000.0, 2) # 时间 item['usedTime'] = round(task['time'] / 60.0, 1) # 金额 records = task['records'] item['elecFee'] = round(sum(map(lambda _: _['elec_money'], records)) * 0.01, 2) item['serviceFee'] = round(sum(map(lambda _: _['serv_money'], records)) * 0.01, 2) item['consumeMoney'] = '{}{}'.format(item['elecFee'] + item['serviceFee'], self.show_pay_unit) item['coins'] = '{}{}'.format(RMB.fen_to_yuan(task['amount']), self.show_pay_unit) # 开始时间 start_time = task.get('create_time') start_time = datetime.datetime.fromtimestamp(start_time) item['startTime'] = start_time.strftime('%m-%d %H:%M:%S') if consumeOrder: # 后付费 payAfterUse = consumeOrder.attachParas.get('payAfterUse') if payAfterUse: item['consumeType'] = 'postpaid' item.pop('leftMoney', None) item.pop('coins', None) elif task['status'] == 'waiting': one = {} one['coins'] = '{}{}'.format(task['amount'], self.show_pay_unit) createTime = datetime.datetime.fromtimestamp(task['create_time']) one['createTime'] = createTime.strftime('%m-%d %H:%M:%S') if task['order_type'] == 'apps_start': one['consumeType'] = 'mobile' if not consumeOrder: people = MyUser(nickname='经销商远程上分') else: people = consumeOrder.user consumeOne = ConsumeRecord.objects.filter(Q(orderNo=task['id']) | Q(sequanceNo=task['id']), devNo=self.device.devNo).first() if consumeOne.attachParas.get('payAfterUse'): one['consumeType'] = 'postpaid' one['nickName'] = people.nickname elif task['order_type'] == 'card_start': one['consumeType'] = 'card' one['cardNo'] = task.get('card_no') if consumeOrder: card = Card.objects.filter(cardNo=task['card_no'], dealerId=self.device.ownerId).first() one.update({'nickName': card.nickName or card.cardName}) else: one.update({'nickName': '匿名用户'}) one['cardBalance'] = '{}{}'.format(task['balance'], self.show_pay_unit) waittingOrder.append(one) if waittingOrder: item['waittingOrder'] = waittingOrder elif status == 'fault': item.update({'status': status}) elif status == 'estop': item.update({'status': status}) elif status == 'idle': item.update({'status': status}) elif status == 'link': item.update({'status': 'connected'}) elif status == 'forbiden': item.update({'status': 'ban'}) result.append(item) return result def stop(self, port=None): data = { 'fun_code': 6, 'operator': 'dealer', 'port': int(port) } self.send_mqtt(data) def active_deactive_port(self, port, active): if active == False: self.stop(port) def stop_by_order(self, port=None, orderNo=''): order = ConsumeRecord.objects.filter(orderNo=orderNo, isNormal=True).first() if not order: logger.info('no this order <{}>'.format(orderNo)) return people = MyUser.objects.filter(openId=order.openId, groupId=self.device['groupId']).first() data = { 'fun_code': 4, 'operator': 'user', 'operator_id': str(people.id), 'order_id': orderNo } self.send_mqtt(data) @property def isHaveStopEvent(self): return True def pwd_cache_key(self): return 'sys_pwd_{}'.format(self.device.devNo) def _get_port_status(self): data = { 'fun_code': 2, 'all': True } data = self.send_mqtt(data) status = data.get('status') result = {} if status == 'fault': result[self.port] = {'status': Const.DEV_WORK_STATUS_FAULT, 'port': self.port} elif status == 'idle': result[self.port] = {'status': Const.DEV_WORK_STATUS_IDLE, 'port': self.port} elif status == 'link': result[self.port] = {'status': Const.DEV_WORK_STATUS_CONNECTED, 'port': self.port} elif status == 'estop': result[self.port] = {'status': Const.DEV_WORK_STATUS_ESTOP, 'port': self.port} elif status == 'ready': result[self.port] = {'status': Const.DEV_WORK_STATUS_READY, 'port': self.port} elif status == 'busy': result[self.port] = {'status': Const.DEV_WORK_STATUS_WORKING, 'port': self.port} elif status == 'forbiden': result[self.port] = {'status': Const.DEV_WORK_STATUS_FORBIDDEN, 'port': self.port} else: result[self.port] = {'status': Const.DEV_WORK_STATUS_FAULT, 'port': self.port} Device.update_dev_control_cache(self.device['devNo'], result) return result 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, weifuleOrderNo=spDict.get('weifuleOrderNo')).first() port = spDict.get('port') result_list = [] # 订单信息组织 _info = self.get_port_info(port) exec_task = _info.get('exec_orders', []) for task in exec_task: item = base_data if spDict['weifuleOrderNo'] != task['id']: continue # 启动方式 if task['order_type'] == 'apps_start': consumeType = 'mobile' else: consumeType = 'card' item['cardNo'] = task['card_no'] # 订单状态 if task['status'] == 'running': # 设备参数 item['voltage'] = _info.get('voltage', 0) item['power'] = _info.get('power', 0) item['ampere'] = _info.get('ampere', 0) # 时间 item['elec'] = task['elec'] # 电量 item['usedTime'] = task['time'] # 金额 records = task['records'] item['elecFee'] = round(sum(map(lambda _: _['elec_money'], records)) * 0.01, 2) item['serviceFee'] = round(sum(map(lambda _: _['serv_money'], records)) * 0.01, 2) item['consumeMoney'] = '{}{}'.format(item['elecFee'] + item['serviceFee'], self.show_pay_unit) # 订单内部信息 item['order'] = { 'orderNo': task['id'], # 停止按钮传订单停单用 'coin': '{}{}'.format(task['amount'], self.show_pay_unit), 'consumeType': consumeType, } if 'card_no' in task: item['cardNo'] = task['card_no'] elif task['status'] == 'waiting': item['desc'] = '此订单已经下发到设备上,上一单运行完毕就会自动运行此订单' item['order'] = { 'orderNo': task['id'], # 停止按钮传订单停单用 'coin': '{}{}'.format(task['amount'], self.show_pay_unit), 'consumeType': consumeType, } try: consumeRcd = ConsumeRecord.objects.filter(orderNo=task['id']).first() if consumeRcd and consumeRcd.attachParas.get('payAfterUse') == True: item['order'] = { 'orderNo': task['id'], # 停止按钮传订单停单用 'coin': '{}{}'.format(0, self.show_pay_unit), 'consumeType': 'postpaid', } item.pop('leftMoney', None) except: pass item.update(DeviceType.get_services_button(self.device['devType']['id'])) result_list.append(item) if not result_list: ServiceProgress.objects.filter(device_imei=self.device.devNo, weifuleOrderNo=spDict.get('weifuleOrderNo')).update( isFinished=True, expireAt=datetime.datetime.now()) ConsumeRecord.objects.filter(devNo=self.device.devNo, isNormal=True, orderNo=spDict.get('weifuleOrderNo')).update(isNormal=False, errorDesc='异常结束,设备订单丢失 code:4', finishedTime=datetime.datetime.now()) return result_list @property def show_pay_unit(self): """ 前台显示付费的时候,目前有不同的客户希望 显示不同的单位 有的显示金币 有的显示元, 这个地方处理下 :return: """ if self.device['otherConf'].get('pay_unit'): return self.device['otherConf'].get('pay_unit') return u'元' def dealer_get_port_status(self): """ 远程上分的时候获取端口状态 :return: """ return self.get_port_status(force=True) def check_order_state(self, openId): dealerId = self.device.ownerId return ClientConsumeModelProxy.get_not_finished_record(ownerId=dealerId, openId=openId, devTypeCode=self._device['devType']['code'], attachParas__payAfterUse=True) def force_stop_order(self, order, **kwargs): if not order.attachParas.get('payAfterUse'): pass else: errorDesc = order.errorDesc + '经销商手动强制关单<{}>'.format(datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")) order.update(status='finished', errorDesc=errorDesc, isNormal=False) def get_policy_infos(self): data = { 'fun_code': 12, 'all': True, } data = self.send_mqtt(data) price = data.pop('prices') price_dict = self._transform_prices(price, 'get') return price_dict def set_policy_infos(self, payload): update_dict = {'fun_code': 11} if payload.get('price1'): prices = self._transform_prices(payload) update_dict.update({'prices': prices}) return self.send_mqtt(update_dict) def get_policy_for_user(self): data = self._get_device_configs() if not data: self.get_dev_setting() data = self._get_device_configs() prices = data.get('prices') str_to_datetime = lambda _: datetime.datetime.strptime(_, "%H:%M") datetime_to_str = lambda _: _.strftime("%H:%M") # 用默认时间填满缝隙 defaultElecPrice = 0.5 defaultSevicePrice = 0.5 time_points = [] priceList = [] for price in prices: if price[0] == 'default': defaultElecPrice = price[1] defaultSevicePrice = price[2] # priceList.append([to_datetime('00:00'), to_datetime('23:59'), defaultElecPrice, defaultSevicePrice]) else: st_point = str_to_datetime(price[0].split('-')[0]) ft_point = str_to_datetime(price[0].split('-')[1]) time_points.extend([st_point, ft_point]) priceList.append([st_point, ft_point, price[1], price[2]]) dst_point = str_to_datetime('00:00') dft_point = str_to_datetime('23:59') dst_point not in time_points and time_points.append(dst_point) dft_point not in time_points and time_points.append(dft_point) time_points = sorted(time_points) resultList = [] for point in time_points: if point == dft_point: break price_model = None for price in priceList: if point == price[0]: price_model = price break if price_model: resultList.append( {"startTime": datetime_to_str(price_model[0]), "elecPrice": price_model[2], "sevicePrice": price_model[3]}) else: resultList.append( {"startTime": datetime_to_str(point), "elecPrice": defaultElecPrice, "sevicePrice": defaultSevicePrice}) return resultList def get_customize_score_unit(self): return u'元' def start_customize_point(self, pointNum, openId, port): package = {'name': 'customizePoint', 'price': pointNum, 'coins': pointNum, 'unit': u'次', 'time': 1} attachParas = {'chargeIndex': port, 'onPoints': True} return self.start_device(package, openId, attachParas) def support_device_package(self): return True def format_device_package(self, isTemp=False, **kw): def __generate_id(ids): i = 1 while True: if str(i) in ids: i += 1 else: return str(i) def __formart_ruleList(): packageList = kw['serviceData'] ids = [str(rule['id']) for rule in packageList if 'id' in rule] washConfig = {} for i, rule in enumerate(packageList): ruleId = str(rule.get('id', '')) if not ruleId: ruleId = __generate_id(ids) ids.append(ruleId) washConfig[ruleId] = {} if 'switch' in rule: washConfig[ruleId].update({'switch': rule['switch']}) if 'billingMethod' in rule: washConfig[ruleId].update({'billingMethod': rule['billingMethod']}) if 'price' in rule: washConfig[ruleId].update( {'price': round(float(rule['price']), 2) or 0, 'coins': round(float(rule['price']), 2) or 0}) # if 'time' in rule: # washConfig[ruleId].update({'time': rule['time'] or 0}) if 'name' in rule: washConfig[ruleId].update({'name': rule['name'] or '套餐{}'.format(i + 1)}) if 'unit' in rule: washConfig[ruleId].update({'unit': rule['unit']}) if 'sn' in rule: washConfig[ruleId].update({'sn': rule['sn']}) if 'autoStop' in rule: washConfig[ruleId]['autoStop'] = rule['autoStop'] if 'autoRefund' in rule: washConfig[ruleId]['autoRefund'] = rule['autoRefund'] if 'minAfterStartCoins' in rule: washConfig[ruleId]['minAfterStartCoins'] = rule['minAfterStartCoins'] if 'minFee' in rule: washConfig[ruleId]['minFee'] = rule['minFee'] if isTemp: pass # 检验部分 if RMB(rule.get('price') or 0) > self.device.owner.maxPackagePrice: raise ServiceException( {'result': 0, 'description': '套餐( {} )金额超限'.format(rule['name']), 'payload': {}}) return washConfig def __formart_displaySwitchs(): return {'displayCoinsSwitch': False, 'displayTimeSwitch': False, 'displayPriceSwitch': True, 'setPulseAble': False, 'setBasePriceAble': False} washConfig = __formart_ruleList() displaySwitchs = __formart_displaySwitchs() return washConfig, displaySwitchs def dealer_show_package(self, isTemp=False, **kw): def get_rule_list(): if isTemp: config = self.device.get('tempWashConfig', {}) else: config = self.device['washConfig'] ruleList = [] for packageId, rule in config.items(): item = { 'id': packageId } if 'switch' in rule: item['switch'] = rule['switch'] if 'name' in rule: item['name'] = rule['name'] if 'coins' in rule: item['coins'] = rule['coins'] if 'price' in rule: item['price'] = rule['price'] if 'time' in rule: item['time'] = rule['time'] if 'description' in rule: item['description'] = rule['description'] if 'unit' in rule: item['unit'] = rule['unit'] if 'imgList' in rule: item['imgList'] = rule['imgList'] if 'sn' in rule: item['sn'] = rule['sn'] if 'autoStop' in rule: item['autoStop'] = rule['autoStop'] if 'minAfterStartCoins' in rule: item['minAfterStartCoins'] = rule['minAfterStartCoins'] if 'minFee' in rule: item['minFee'] = rule['minFee'] ruleList.append(item) return sorted(ruleList, key=lambda x: (x.get('sn'), x.get('id'))) def get_display_switchs(): if "displaySwitchs" in self.device["otherConf"]: displaySwitchs = self.device["otherConf"].get('displaySwitchs') else: displaySwitchs = {'displayCoinsSwitch': False, 'displayTimeSwitch': False, 'displayPriceSwitch': True, "setPulseAble": False, "setBasePriceAble": False} return displaySwitchs ruleList = get_rule_list() displaySwitchs = get_display_switchs() return {"ruleList": ruleList, 'displaySwitchs': displaySwitchs} def custom_push_url(self, order, user, **kw): from apps.web.utils import concat_user_center_entry_url from apps.web.utils import concat_front_end_url return concat_user_center_entry_url(agentId=user.productAgentId, redirect=concat_front_end_url( uri='/user/index.html#/user/deviceStatus'))