# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import re from decimal import Decimal from apps.web.constant import DeviceCmdCode, Const 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 from apps.web.user.models import ConsumeRecord class FastCharge(SmartBox): def __init__(self, device): super(FastCharge, self).__init__(device) def _check_package(self, package): """ 获取设备启动的发送数据 根据设备的当前模式以及套餐获取 :param package: :return: """ devConf = self.get_device_configs() coinElec = devConf.get('coinElec', 10) # 单位是0.1度 coinTime = devConf.get('coinMin', 240) maxTotalTime = devConf.get('maxTotalTime', 0) or 720 coins = float(package.get('coins')) elec = coins * coinElec * 0.1 _time = min(coins * coinTime, maxTotalTime) return _time, elec, coins 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']) def reverse_hex(self, data): # type:(str) -> str if not isinstance(data, str): raise TypeError return ''.join(list(reversed(re.findall(r'.{2}', data)))) def encode_str(self, data, length=2, ratio=1.0, base=16): # type:(any,int,float,int) -> str if not isinstance(data, Decimal): data = Decimal(data).quantize(Decimal('0.00')) if not isinstance(length, str): length = str(length) if not isinstance(ratio, Decimal): ratio = Decimal(ratio) end = 'X' if base == 16 else 'd' encodeStr = '%.' + length + end encodeStr = encodeStr % (data * ratio) return encodeStr def decode_str(self, data, ratio=1.0, base=16, reverse=False): # type:(str,float,int,bool) -> str """ ratio:比率单位转换 """ if not isinstance(data, str): data = str(data) if reverse: data = ''.join(list(reversed(re.findall(r'.{2}', data)))) return '%.10g' % (int(data, base) * ratio) def decode_long_hex_to_list(self, data, split=2, ratio=1.0, base=16): # type:(str,int,float,int) -> list """ return: list """ if len(data) % split != 0: raise Exception('Invalid data') pattern = r'.{%s}' % split hex_list = re.findall(pattern, data) hex_list = map(lambda x: self.decode_str(x, ratio=ratio, base=base), hex_list) return hex_list 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'参数错误.'}) 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, funCode, data, cmd=DeviceCmdCode.OPERATE_DEV_SYNC, order_id=None): """ 发送mqtt 指令210 返回data """ if not isinstance(funCode, str): funCode = str(funCode) if not isinstance(data, str): data = str(data) payload = {'IMEI': self.device['devNo'], 'funCode': funCode, 'data': data} if order_id: payload.update({'order_id': order_id}) result = MessageSender.send(self.device, cmd, payload) 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 'order_id' in result or 'order_info' in result: return result else: return result.get('data', '') @staticmethod def port_is_busy(port_dict): if not port_dict: return False if 'billingType' not in port_dict: return False if 'status' not in port_dict: return False if 'coins' not in port_dict: return False if port_dict['billingType'] not in ['time', 'elec']: return False if port_dict['billingType'] == 'time': if 'needTime' not in port_dict: return False else: if 'needElec' not in port_dict: return False if port_dict['status'] == Const.DEV_WORK_STATUS_WORKING: return True else: return False 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) def get_device_configs(self): dev = Device.get_dev(self.device.devNo) deviceConfigs = dev.get('otherConf', {}).get('deviceConfigs', {}) return deviceConfigs def start_device_realiable(self, order): # type:(ConsumeRecord)->dict package = order.package coins = package.get('coins', 0) deviceType = '03' port = order.used_port userType = '01' userNum = '{:0>16s}'.format(order.orderNo) sequanceNo = '{:0>16s}'.format(order.orderNo) + datetime.datetime.now().strftime('%Y%m%d%H%M%S') balance = self.encode_str(coins, length=8, ratio=100.0) chargeType = '00' # 00 为立即充电 01为 预约充电 featureStr = 'FF' self.get_consumption_rules() return {} def get_dev_setting(self): deviceConfigs = self.get_device_configs() if not deviceConfigs: pass packages = [{'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '00:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '03:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '06:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '09:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '12:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '15:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '18:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '21:00'}] return {'package': packages} def set_device_function_param(self, request, lastSetConf): print request, lastSetConf def get_consumption_rules(self): packages = [ {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '00:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '03:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '06:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '09:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '12:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '15:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '18:00'}, {'serviceFee': '2.5', 'parkingFee': '2.5', 'unitPrice': '2.5', 'startTime': '21:00'}, ] data = '' count = 0 for item in packages: count += 1 hour, min = item['startTime'].split(':') data += self.encode_str(hour) data += self.encode_str(min) if count % 2 == 0: data += self.encode_str(item['unitPrice']) data += self.encode_str(item['serviceFee']) data += self.encode_str(item['parkingFee']) return data def stop(self, port=None): data = { 'port': int(port), 'remote_type': 0, } result = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, data)