# -*- coding: utf-8 -*- # !/usr/bin/env python import copy import logging import datetime import time from typing import TYPE_CHECKING from apps.web.constant import Const from apps.web.core.exceptions import ServiceException from apps.web.core.adapter.base import SmartBox, start_error_timer from apps.web.core.device_define.baolai import send_request from apps.web.device.models import Device from apps.web.user.models import ConsumeRecord if TYPE_CHECKING: pass logger = logging.getLogger(__name__) # 2.4 , 2.6 , 2.12 , 2.14 , 2.15 , 3.2 , 3.3 , 3.4 , 3.5 , 3.6 , 3.7 , 3.9 class SampleData: """ sampleMap = { "max_power":200, # 单路最大充电功率,单位W "charge_full_power_threshold":10, # 充满阈值,单位W,默认10W "charge_full_time_threshold":7200, # 浮充时间,单位s,默认7200s "charge_single_amount":100, # 单次按键金额,单位分,默认1.00 "max_time":900, # 最大充电时间,单位分,默认600分 "trickle_threshold":10, # 未开放,暂勿需对接 "no_load_power_threshold":2.5, # 空载阈值,单位W,默认0.8W "high_temperature_threshold":85, # 过温阈值,单位℃,默认60℃ "max_current":12, # 单路最大电流,单位A "no_load_time_threshold":45 # 空载时间,单位s,默认45s } """ sampleMap = { 'max_power': 0, 'charge_full_power_threshold': 0, 'charge_full_time_threshold': 0, 'charge_single_amount': 0, 'max_time': 0, 'trickle_threshold': 0, 'no_load_power_threshold': 0, 'high_temperature_threshold': 0, 'max_current': 0, 'no_load_time_threshold': 0, } class BoLaiTenCharge(SmartBox): def __init__(self, device): super(BoLaiTenCharge, self).__init__(device) devObj = self.device.my_obj self.billingType = devObj.otherConf.get('billingType', 'time') self.config_list = devObj.otherConf.get('config_list', []) self.onceCard = devObj.otherConf.get('onceCard', 100) self.cardTime = devObj.otherConf.get('cardTime', 180) self.cardElec = devObj.otherConf.get('cardElec', 1) # 2.4 配置节点最大充电功率 def _set_dev_max_power(self, portConfig): for port,conf in portConfig.items(): setInfo = {'gateway_id': self.device.devNo, 'node_index': 0, 'port_index': int(port)-1, 'max_current': conf['max_current'], 'max_power': conf['max_max_power'], 'timeout': 5} devInfo = self._send_request("cmd/set-node-config", setInfo,"2") if devInfo['data']['code'] != 0: raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'}) def _send_request(self, cmdPath, jsonPara, cmdKind): return send_request(self.device.devNo, self.device.devNo, cmdPath, jsonPara,cmdKind) # 2.6 获取节点最大充电功率 /2/cmd/get-node-config def _get_dev_max_power(self): portConfig = {} for i in range(12): setConf = {"gateway_id": self.device.devNo, "node_index": 0, "port_index": i} devInfo = self._send_request("cmd/get-node-config", setConf,"2") if devInfo['data']['code'] != 0: raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'}) config = devInfo['data']['data'] portConfig.update({str(i+1):{"max_current": config['max_current'], "max_max_power": config['max_power']}}) return portConfig # 2.12 控制节点(充电柜/十二路/十路机/六路机/独立版) /3/cmd/control, def _start_device(self, jsonPara): return self._send_request("cmd/control", jsonPara,"3") # 2.14 设置系统参数 /3/cmd/set-node-config, def _set_dev_setting(self, setConf): setConf.update({'node_index': 0}) devObj = Device.objects.get(devNo=self._device['devNo']) devObj.otherConf.update({ 'billingType': setConf['chargeType'], # 前端直接传elec,time,power 'onceCard': int(float(setConf['onceCard'])), 'cardTime': int(setConf['cardTime']), 'cardElec': float(setConf['cardElec']), 'config_list': setConf['config_list'], }) devObj.save() setConf.pop('chargeType') setConf.pop('onceCard') setConf.pop('cardTime') setConf.pop('cardElec') setConf.pop('config_list') setConf['charge_single_amount'] = int(setConf['charge_single_amount']) * 100 setConf.update({ 'charge_full_time_threshold': int(setConf['charge_full_timeout']), 'no_load_time_threshold': int(setConf['no_load_timeout']) }) setConf.pop('charge_full_timeout') setConf.pop('no_load_timeout') devInfo = self._send_request('cmd/set-node-config', setConf, 3) if devInfo['data']['code'] != 0: raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'}) return devInfo # 2.15 读取系统参数 /3/cmd/get-node-config, def get_dev_setting(self): setConf = { "gateway_id": self.device.devNo, "node_index": 0, } devInfo = self._send_request("cmd/get-node-config", setConf,3) if devInfo['data']['code'] != 0: raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'}) config = devInfo['data']['data'] if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE: portConfig = self._get_dev_max_power() config.update({'portConfig':portConfig}) config.update({ 'chargeType': str(self.billingType), 'onceCard': self.onceCard, 'cardTime': self.cardTime, 'cardElec': self.cardElec, 'config_list': self.config_list, 'charge_full_timeout': config['charge_full_time_threshold'], 'no_load_timeout': config['no_load_time_threshold'] }) config['charge_single_amount'] = config['charge_single_amount'] * 0.01 return config # 3.2 , 3.3 , 3.4 , 3.5 , 3.6 , 3.7 , 3.9 @start_error_timer( missMessages=[u"请您选择合适的充电线路、电池类型信息", u"请您选择合适的充电线路", u"该端口正在使用中"]) 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'请您选择合适的充电线路'}) # 端口从0开始 port = int(attachParas['chargeIndex']) # attachParas['chargeIndex'] = port unit = package.get('unit', u'分钟') needTime, needElec = None, None jsonPara = {'gateway_id': self.device.devNo, 'node_index': 0, 'port_index': port-1, \ 'switch_state': 1, 'control__type': 1, 'timeout': 10,'charge_energy': 0,\ 'charge_time': 0} # 按时充电 if self.billingType == 'time': if unit == u'秒': if int(package['time']) < 60: raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'}) needTime = int(float(package['time']) / 60.0) jsonPara.update({'charge_time': needTime, 'charge_type': 1}) elif unit == u'分钟': needTime = int(float(package['time'])) jsonPara.update({'charge_time': needTime, 'charge_type': 1}) elif unit == u'小时': needTime = int(float(package['time']) * 60) jsonPara.update({'charge_time': needTime, 'charge_type': 1}) elif unit == u'天': needTime = int(float(package['time']) * 60 * 24) jsonPara.update({'charge_time': needTime, 'charge_type': 1}) else: raise ServiceException({'result': 2, 'description': u'运营商没有配置正确的套餐,请运营商配置正确的套餐'}) # 按量充电 elif self.billingType == 'elec': if unit == u'度': needElec = int(float(package['time']) * 1000) # 微度 jsonPara.update({'charge_energy': needElec, 'charge_type': 2}) else: raise ServiceException({'result': 2, 'description': u'运营商没有配置正确的套餐,请运营商配置正确的套餐'}) # 按功率充电 else: if not self.config_list: raise ServiceException( {'result': 2, 'description': u'运营商没有配置正确的分档功率,请运营商配置正确的分档功率'}) """ charge_power = { "money":"", "config_list":[{ "power":"", "price":"", "time":"", }] } """ needTime = int(float(package['time'])) coins = int(float(package['coins']) * 100) # 单位为分 jsonPara.update({'charge_power': {'money': coins, 'config_list': self.config_list}}) jsonPara.update({'charge_type': 3}) jsonPara.pop('charge_energy') jsonPara.pop('charge_time') devInfo = self._send_request("cmd/control", jsonPara,"3") if devInfo['data']['code'] != 0: raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'}) if devInfo['rst'] == 0: # 成功 newValue = { str(port): { 'status': Const.DEV_WORK_STATUS_WORKING, 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'controlType': 1 } } else: raise ServiceException({'result': 2, 'description': u'充电插座响应异常,请您稍后再试哦'}) servicedInfo = {} if self.billingType == 'time': finishedTime = int(time.time()) + needTime * 60 devInfo['needTime'] = needTime servicedInfo.update({'needTime': needTime, 'billingType': 'time'}) elif self.billingType == 'elec': finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束 devInfo['needElec'] = float(package['time']) servicedInfo.update({'needElec': float(package['time']), 'billingType': 'elec'}) else: finishedTime = int(time.time()) + 60 * 60 * 10 # 设定10个小时,确实很难知道可以用多久结束 servicedInfo.update({'billingType': 'power'}) newValue[str(port)].update({'power': 10}) # 端口下的数据依赖心跳上报,但是心跳有时间间隔,这样查看服务的时候,因为功率是0,会认为已经结束,这里给一个初始值 sequanceNo = devInfo['data']['data']['transaction_id'] newValue[str(port)].update({'finishedTime': finishedTime,'sequanceNo':sequanceNo}) Device.clear_port_control_cache(self._device['devNo'], port) Device.update_dev_control_cache(self._device['devNo'], newValue) devInfo['finishedTime'] = finishedTime devInfo['sequanceNo'] = sequanceNo devInfo['servicedInfo'] = servicedInfo return devInfo def stop_charging_port(self,port): portInfo = self.get_port_info(port) controlType = portInfo.get('controlType', 1) jsonPara = {'node_index': 0, 'port_index': port, 'charge_type': 3, 'switch_state': 0,'control__type':controlType} if self.billingType == 'power': jsonPara.update({'charge_power': {'money': 0,'config_list': self.config_list}}) devInfo = self._send_request('cmd/control', jsonPara, 3) elif self.billingType == 'time': jsonPara.update({'charge_time': 0, 'charge_type': 1}) devInfo = self._send_request('cmd/control', jsonPara, 3) else: jsonPara.update({'charge_energy': 0, 'charge_type': 2}) devInfo = self._send_request('cmd/control', jsonPara, 3) if devInfo['data']['code'] != 0: raise ServiceException({'result': 2, 'description': u'设备服务器返回错误,建议您重试,或者联系客服'}) 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 get_port_status_from_dev(self): # 解析缓存 return self.get_port_status() def get_port_info(self, port): ''' 获取 端口的详细信息 :param port: :return: ''' port=int(port) devCache = Device.get_dev_control_cache(self.device.devNo) return devCache.get(str(port), dict()) def get_port_status(self, force=False): ''' 获取设备状态 :param force: :return: ''' statusDict = dict() devCache = Device.get_dev_control_cache(self._device['devNo']) if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE: allPorts = devCache.get('allPorts', 12) else: allPorts = devCache.get('allPorts', 10) for portNum in range(allPorts): tempDict = devCache.get(str(portNum + 1), {}) if 'status' in tempDict: statusDict[str(portNum + 1)] = {'status': tempDict.get('status')} if tempDict['status'] == 1: try: order = ConsumeRecord.get_consumed_records(sequanceNo=tempDict['sequanceNo'])[0] startTime = order.dateTimeAdded usedTime = (datetime.datetime.now() - startTime).seconds / 60 statusDict[str(portNum + 1)].update({'usedTime':usedTime}) except: pass elif 'isStart' in tempDict: if tempDict['isStart']: statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_WORKING} else: statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE} else: statusDict[str(portNum + 1)] = {'status': Const.DEV_WORK_STATUS_IDLE} Device.update_dev_control_cache(self._device['devNo'],statusDict) 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 set_device_function_param(self, request, lastSetConf): newConf = copy.deepcopy(request.POST) newConf.pop('logicalCode', None) if 'portConfig' in newConf: portConfig = newConf.pop('portConfig') self._set_dev_setting(newConf) if self.device.devTypeCode == Const.DEVICE_TYPE_CODE_CHANGING_BL_TWELVE: self._set_dev_max_power(portConfig) Device.invalid_device_cache(self.device.devNo) def active_deactive_port(self, port, active): port = int(port)-1 if active: raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'}) return self.stop_charging_port(port) def get_server_setting(self): refundProtectionTime = self.device.otherConf.get('refundProtectionTime',5) return refundProtectionTime def set_server_setting(self,payload): refundProtectionTime = int(payload['refundProtectionTime']) self.device.update_other_conf(refundProtectionTime=refundProtectionTime)