# -*- coding: utf-8 -*- # !/usr/bin/env python import datetime import logging import re from decimal import Decimal from typing import TYPE_CHECKING, Optional from apps.web.common.proxy import ClientConsumeModelProxy from apps.web.constant import Const, DeviceCmdCode, CONSUMETYPE from apps.web.core.adapter.base import SmartBox from apps.web.core.adapter.policy_common import PolicyCommon from apps.web.core.device_define.jndz import CMD_CODE from apps.web.core.exceptions import ServiceException from apps.web.core.networking import MessageSender from apps.web.dealer.models import Dealer from apps.web.device.models import Device, Group from taskmanager.mediator import task_caller logger = logging.getLogger(__name__) if TYPE_CHECKING: pass # from apps.web.device.models import Device, Group # from apps.web.user.models import ConsumeRecord, MyUser, Card class CmdHelper(object): @staticmethod def encode_str(data, length=2, ratio=1.0, base=16): # type:(str,int,float,int) -> str if not isinstance(data, Decimal): data = Decimal(data) 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 @staticmethod def decode_str(data, ratio=1, base=16, to_num=True): # type:(str,Optional[float, int],int, bool) -> Optional[float, str] """ ratio:比率单位转换 """ if not isinstance(data, str): data = str(data) if to_num: return int(data, base) * ratio else: return '%.10g' % (int(data, base) * ratio) @staticmethod def reverse_hex(data): # type:(str) -> str if not isinstance(data, str): raise TypeError return ''.join(list(reversed(re.findall(r'.{2}', data)))) @staticmethod def split_data_to_list(split_str, data): # type:(str,str) ->Optional[list, None] """ return: list """ part = '({})' all_ = sum(map(lambda _: int(_) * 2, split_str)) pattern = reduce(lambda a, b: a + b, map(lambda _: part.format('..' * int(_)), split_str)) result = re.match(pattern, data[:all_]) if result: return result.groups() 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 @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)}) class JNDZPOLICYBox(PolicyCommon, CmdHelper): def __init__(self, device): super(JNDZPOLICYBox, self).__init__(device) 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']) @property def device_configs(self): dev = Device.get_dev(self.device.devNo) deviceConfigs = dev.get('otherConf', {}).get('deviceConfigs', {}) return deviceConfigs @property def server_configs(self): dev = Device.get_dev(self.device.devNo) serverConfigs = dev.get('otherConf', {}).get('serverConfigs', {}) return serverConfigs def analyze_event_data(self, device_event): # 升级兼容. 避免重启过程中老的消息 if 'data' in device_event: data = device_event['data'] else: data = device_event cmdCode = data[4:6] # 4个故障的告警 if cmdCode == CMD_CODE.DEVICE_FAULT_FIRE: return {"cmdCode": cmdCode, "fault": u"火灾报警"} elif cmdCode == CMD_CODE.DEVICE_FAULT_SMOKE: return {"cmdCode": cmdCode, "fault": "烟雾报警"} elif cmdCode == CMD_CODE.DEVICE_FAULT_TEMPERATURE: return {"cmdCode": cmdCode, "fault": "温度超限告警"} elif cmdCode == CMD_CODE.DEVICE_FAULT_POWER: return {"cmdCode": cmdCode, "fault": "功率超线告警"} elif cmdCode == CMD_CODE.DEVICE_FAULT_ALTER: def getBin8Str(binData): bin8Str = str(bin(binData))[2:] while len(bin8Str) < 8: bin8Str = '0' + bin8Str return bin8Str fire = int(data[8:10], 16) smoke = int(data[10:12], 16) overload = int(data[12:14], 16) overheat = int(data[14:16], 16) relayAdhesion = data[16:24] relayAdhesionDetail = (getBin8Str(int(relayAdhesion[0:2], 16)) + getBin8Str( int(relayAdhesion[2:4], 16)) + getBin8Str(int(relayAdhesion[4:6], 16)) + getBin8Str( int(relayAdhesion[6:8], 16)))[::-1] portRelayAdhesion = {} for _ in range(0, len(relayAdhesionDetail)): if int(relayAdhesionDetail[_]): portRelayAdhesion.update({str(_ + 1): int(relayAdhesionDetail[_])}) result = {"cmdCode": cmdCode, "fire": bool(fire), "smoke": bool(smoke), "overload": bool(overload), "overheat": bool(overheat), "portRelayAdhesion": portRelayAdhesion} dealer = Dealer.objects(id=self.device['ownerId']).first() if dealer is None: return {} if 'supportAdhesionAlert' not in dealer.features: result.pop('portRelayAdhesion') fault = [] desc = [] if result.get('fire', False): fault.append("火灾报警") result["errorCode"] = "B202" if result.get('smoke', False): fault.append("烟雾报警") result["errorCode"] = "B202" if result.get('overload', False): fault.append("功率超限告警") result["errorCode"] = "B203" if result.get('overheat', False): fault.append("温度超限告警") result["errorCode"] = "B201" if result.get('portRelayAdhesion', {}): fault.append("继电器粘连告警") result["errorCode"] = "B204" for _ in portRelayAdhesion.keys(): desc.append("{}号继电器粘连告警 ".format(_)) if desc: desc = '--'.join(desc) result.update({"desc": desc}) if fault: fault = '--'.join(fault) result.update({"fault": fault}) else: result = {} return result # 2个状态量上报 elif cmdCode == CMD_CODE.DEVICE_FAULT_POWER: maxPower = int(data[8:12], 16) return {"cmdCode": cmdCode, "maxPower": maxPower} elif cmdCode == CMD_CODE.DEVICE_FAULT_TEMPERATURE: maxTemperature = int(data[8:10], 16) return {"cmdCode": cmdCode, "maxTemperature": maxTemperature} elif cmdCode == CMD_CODE.DEVICE_ELEC: elec = int(data[8:12], 16) return {"cmdCode": cmdCode, "elec": elec} elif cmdCode == CMD_CODE.DEVICE_TEMPERATURE: temperature = int(data[10:12], 16) if data[8:10] == "00": temperature = temperature * -1 return {"cmdCode": cmdCode, "temperature": temperature} elif cmdCode == CMD_CODE.DEVICE_REAL_TIME_REPORT_21: _result = data[6: 8] port_num = int(data[8:10], 16) port_info_urat_info = data[10:170] port_status_desc = { "01": "端口空闲", "02": "端口正在使用", "03": "端口禁用", "04": "端口故障", } port_info = {} for index in xrange(0, 16 * port_num, 16): item = port_info_urat_info[index: index + 16] one_port = {} one_port["port"] = int(item[:2], 16) one_port["portStatus"] = item[2:4] one_port["portStatusDesc"] = port_status_desc.get(item[2:4]) one_port["leftTime"] = int(item[4:8], 16) one_port["power"] = int(item[8:12], 16) one_port["elec"] = int(item[12:16], 16) * 0.01 port_info[str(one_port["port"])] = one_port return {"cmdCode": cmdCode, "result": _result, "sourceData": data, "portNum": port_num, "portInfo": port_info} else: logger.info("receive data <{}>, cmd is invalid".format(data)) def get_default_port_nums(self): data = self.send_mqtt({'funCode': '01', 'data': '00'}) portTotalNum = self.decode_str(data[8:10]) theFirst = self.decode_str(data[10:12]) return portTotalNum, theFirst def get_idle_port(self): data = self.send_mqtt({'funCode': '02', 'data': '00'}) idlePortNum = self.decode_str(data[8:10]) idlePortList = self.decode_long_hex_to_list(data[10:-2]) return {'idlePortNum': idlePortNum, 'idlePortList': idlePortList} def lock_unlock_port(self, port, lock=True): lockStr = '00' if lock else '01' portStr = self.encode_str(port) data = portStr + lockStr data = self.send_mqtt({'funCode': '0C', 'data': data}) if data[6:8] == '01': # 表示成功 pass else: raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'}) if lock: Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_FORBIDDEN}}) else: Device.update_dev_control_cache(self._device['devNo'], {str(port): {'status': Const.DEV_WORK_STATUS_IDLE}}) def active_deactive_port(self, port, active): if not active: self.stop_charging_port(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 get_port_status(self, force=False): if force: return self.get_port_status_from_dev() ctrInfo = Device.get_dev_control_cache(self._device['devNo']) statusDict = {} 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', 10) # allPorts 有的时候会为0, 这个时候强制设置为10 if allPorts == 0: allPorts = 10 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 get_port_status_from_dev(self): data = self.send_mqtt({'funCode': '0F', 'data': '00'}) data = data[6:] if data[0:2] == '01': # 表示成功 pass else: raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'}) result = {} portNum = int(data[2:4], 16) portData = data[4::] ii = 0 while ii < portNum: port = int(portData[ii * 4:ii * 4 + 2], 16) statusTemp = portData[ii * 4 + 2:ii * 4 + 4] if statusTemp == '01': status = {'status': Const.DEV_WORK_STATUS_IDLE} elif statusTemp == '02': status = {'status': Const.DEV_WORK_STATUS_WORKING} elif statusTemp == '03': status = {'status': Const.DEV_WORK_STATUS_FORBIDDEN} elif statusTemp == '04': status = {'status': Const.DEV_WORK_STATUS_FAULT} else: status = {'status': Const.DEV_WORK_STATUS_FAULT} ii += 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 test(self, coins, port=1, time='60', elec='0'): data = self.encode_str(str(port)) data += self.encode_str(coins) data += self.encode_str(time, length=4) data += self.encode_str(elec, length=4, ratio=100) devInfo = self.send_mqtt({'funCode': '14', 'data': data}) return devInfo def get_dev_setting(self): """ 获取设备配置参数 :return: """ devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '1E', '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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) data = devInfo['data'][6::] if data[0:2] == '01': # 表示成功 pass else: raise ServiceException({'result': 2, 'description': u'操作端口失败,请重试看能否解决'}) confData = data[2:-2] coinMin = int(confData[0:4], 16) cardMin = int(confData[4:8], 16) coinElec = int(confData[8:10], 16) cardElec = int(confData[10:12], 16) cst = int(confData[12:14], 16) powerMax1 = int(confData[14:18], 16) powerMax2 = int(confData[18:22], 16) powerMax3 = int(confData[22:26], 16) powerMax4 = int(confData[26:30], 16) power2Ti = int(confData[30:32], 16) power3Ti = int(confData[32:34], 16) power4Ti = int(confData[34:36], 16) spRecMon = int(confData[36:38], 16) spFullEmpty = int(confData[38:40], 16) fullPowerMin = int(confData[40:42], 16) fullChargeTime = int(confData[42:44], 16) elecTimeFirst = int(confData[44:46], 16) try: firstCoinTime = int(confData[46:50], 16) secondCoinTime = int(confData[50:54], 16) thirdCoinTime = int(confData[54:58], 16) except Exception as e: firstCoinTime = 0 secondCoinTime = 0 thirdCoinTime = 0 try: self.device.update_other_conf( cst=cst, coinMin=coinMin, coinElec=coinElec, cardMin=cardMin, cardElec=cardElec) except Exception as e: pass resultDict = { 'coinMin': coinMin, 'cardMin': cardMin, 'coinElec': coinElec, 'cardElec': cardElec, 'cst': cst, 'powerMax1': powerMax1, 'powerMax2': powerMax2, 'powerMax3': powerMax3, 'powerMax4': powerMax4, 'power2Ti': power2Ti, 'power3Ti': power3Ti, 'power4Ti': power4Ti, 'spRecMon': spRecMon, 'spFullEmpty': spFullEmpty, 'fullPowerMin': fullPowerMin, 'fullChargeTime': fullChargeTime, 'elecTimeFirst': elecTimeFirst, 'firstCoinTime': firstCoinTime, 'secondCoinTime': secondCoinTime, 'thirdCoinTime': thirdCoinTime } consumeInfo = self.get_dev_consume_count() resultDict.update(consumeInfo) deviceInfo = self.get_real_time_device_info() resultDict.update(deviceInfo) return resultDict @SmartBox.check_device_features(device_features=["fun_code_30_31"], no_features_to_return={"haveStatus": False}) def get_real_time_device_info(self): try: devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'funCode': '30', 'data': '00'}, timeout=7) 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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) except Exception: return {"haveStatus": False} data = devInfo.get("data") maxPower = int(data[8:12], 16) elec = int(data[12:16], 16) maxTemperature = int(data[16:18], 16) base = -1 if int(data[18:20], 16) == 1 else 1 temperature = int(data[20:22], 16) * base fire = int(data[22:24], 16) smoke = int(data[24:26], 16) overheat = int(data[26:28], 16) overload = int(data[28:30], 16) relayMasterSwitch = int(data[30:32], 16) return {"haveStatus": True, "maxPower": maxPower, "elec": elec, "maxTemperature": maxTemperature, "temperature": temperature, "fire": fire, "smoke": smoke, "overheat": overheat, "overload": overload, "relayMasterSwitch": relayMasterSwitch, } def get_dev_consume_count(self): data = self.send_mqtt({'funCode': '07', 'data': '00'}) data = data[6:] if data[0:2] == '01': # 表示成功 pass else: raise ServiceException({'result': 2, 'description': u'获取统计数据失败,请重试看能否解决'}) cardFee = int(data[2:6], 16) / 10.0 # 以角为单位 coinFee = int(data[6:10], 16) # 以元为单位 return {'cardFee': cardFee, 'coinFee': coinFee} def set_dev_setting(self, setConf): data = self.encode_str(setConf['coinMin'], length=4) data += self.encode_str(setConf['cardMin'], length=4) data += self.encode_str(setConf['coinElec'], length=2) data += self.encode_str(setConf['cardElec'], length=2) data += self.encode_str(setConf['cst'], length=2) data += self.encode_str(setConf['powerMax1'], length=4) data += self.encode_str(setConf['powerMax2'], length=4) data += self.encode_str(setConf['powerMax3'], length=4) data += self.encode_str(setConf['powerMax4'], length=4) data += self.encode_str(setConf['power2Ti'], length=2) data += self.encode_str(setConf['power3Ti'], length=2) data += self.encode_str(setConf['power4Ti'], length=2) data += self.encode_str(setConf['spRecMon'], length=2) data += self.encode_str(setConf['spFullEmpty'], length=2) data += self.encode_str(setConf['fullPowerMin'], length=2) data += self.encode_str(setConf['fullChargeTime'], length=2) data += self.encode_str(setConf['elecTimeFirst'], length=2) self.send_mqtt({'funCode': '18', 'data': data}) def set_dev_setting2(self, setConf): if 'lowPower' in setConf: # 新版本 data = self.encode_str(setConf['lowPower']) else: # 老版本 data = self.encode_str(setConf['stopDelay']) data += self.encode_str(setConf['maxTotalTime']) data += self.encode_str(setConf['overVoltage'], length=4) data += self.encode_str(setConf['lowVoltage'], length=4) data += self.encode_str(setConf['overTemp']) data += self.encode_str(setConf['overTempDelayTime']) data += str(setConf['timeDspOn']).replace(':', '') data += str(setConf['timeDspOff']).replace(':', '') data += self.encode_str(setConf['pricePower1'], length=4, ratio=1000.0) data += self.encode_str(setConf['pricePower2'], length=4, ratio=1000.0) data += self.encode_str(setConf['pricePower3'], length=4, ratio=1000.0) data += self.encode_str(setConf['pricePower4'], length=4, ratio=1000.0) data += self.encode_str(setConf['pricePower5'], length=4, ratio=1000.0) if 'lowPower' in setConf: # 新版本 data += self.encode_str(setConf.get('lowPowerCheckTime', 30), length=4) data += self.encode_str(setConf.get('stopDelayTime', 30), length=4) else: pass if 'maxTotalPower' in setConf: data += self.encode_str(setConf['maxTotalPower']) self.send_mqtt({'funCode': '22', 'data': data}) def set_device_function_param(self, request, lastSetConf): coinMin = request.POST.get('coinMin', None) cardMin = request.POST.get('cardMin', None) coinElec = request.POST.get('coinElec', None) cardElec = request.POST.get('cardElec', None) cst = request.POST.get('cst', None) powerMax1 = request.POST.get('powerMax1', None) powerMax2 = request.POST.get('powerMax2', None) powerMax3 = request.POST.get('powerMax3', None) powerMax4 = request.POST.get('powerMax4', None) power2Ti = request.POST.get('power2Ti', None) power3Ti = request.POST.get('power3Ti', None) power4Ti = request.POST.get('power4Ti', None) spRecMon = request.POST.get('spRecMon', None) spFullEmpty = request.POST.get('spFullEmpty', None) fullPowerMin = request.POST.get('fullPowerMin', None) fullChargeTime = request.POST.get('fullChargeTime', None) elecTimeFirst = request.POST.get('elecTimeFirst', None) # 这几个参数是墨小智V3特有的 stWTime = request.POST.get('stWTime', None) temThre = request.POST.get('temThre', None) freeUse = request.POST.get('freeUse', None) relayMasterSwitch = request.POST.get('relayMasterSwitch', None) # 这几个参数是久恒保险丝版本特有的 firstCoinTime = request.POST.get('firstCoinTime', None) secondCoinTime = request.POST.get('secondCoinTime', None) thirdCoinTime = request.POST.get('thirdCoinTime', None) # 这几个参数是申林电子8档久恒板特有的 powerMax5 = request.POST.get('powerMax5', None) powerMax6 = request.POST.get('powerMax6', None) powerMax7 = request.POST.get('powerMax7', None) powerMax8 = request.POST.get('powerMax8', None) power5Ti = request.POST.get('power5Ti', None) power6Ti = request.POST.get('power6Ti', None) power7Ti = request.POST.get('power7Ti', None) power8Ti = request.POST.get('power8Ti', None) if coinMin: lastSetConf.update({'coinMin': int(coinMin)}) if cardMin: lastSetConf.update({'cardMin': int(cardMin)}) if coinElec: lastSetConf.update({'coinElec': int(coinElec)}) if cardElec: lastSetConf.update({'cardElec': int(cardElec)}) if cst: lastSetConf.update({'cst': int(cst)}) if powerMax1: lastSetConf.update({'powerMax1': int(powerMax1)}) if powerMax2: lastSetConf.update({'powerMax2': int(powerMax2)}) if powerMax3: lastSetConf.update({'powerMax3': int(powerMax3)}) if powerMax4: lastSetConf.update({'powerMax4': int(powerMax4)}) if power2Ti: lastSetConf.update({'power2Ti': int(power2Ti)}) if power3Ti: lastSetConf.update({'power3Ti': int(power3Ti)}) if power4Ti: lastSetConf.update({'power4Ti': int(power4Ti)}) if spRecMon: lastSetConf.update({'spRecMon': int(spRecMon)}) if spFullEmpty: lastSetConf.update({'spFullEmpty': int(spFullEmpty)}) if fullPowerMin: lastSetConf.update({'fullPowerMin': int(fullPowerMin)}) if fullChargeTime: lastSetConf.update({'fullChargeTime': int(fullChargeTime)}) if elecTimeFirst: lastSetConf.update({'elecTimeFirst': int(elecTimeFirst)}) # 这几个参数是墨小智V3特有的 if stWTime: lastSetConf.update({'stWTime': int(stWTime)}) if temThre: lastSetConf.update({'temThre': int(temThre)}) if freeUse: lastSetConf.update({'freeUse': int(freeUse)}) # 这几个参数是久恒保险丝版本特有的 if firstCoinTime: lastSetConf.update({'firstCoinTime': int(firstCoinTime)}) if secondCoinTime: lastSetConf.update({'secondCoinTime': int(secondCoinTime)}) if thirdCoinTime: lastSetConf.update({'thirdCoinTime': int(thirdCoinTime)}) # 这几个参数是申林电子8档久恒板特有的 if powerMax5: lastSetConf.update({'powerMax5': int(powerMax5)}) if powerMax6: lastSetConf.update({'powerMax6': int(powerMax6)}) if powerMax7: lastSetConf.update({'powerMax7': int(powerMax7)}) if powerMax8: lastSetConf.update({'powerMax8': int(powerMax8)}) if power5Ti: lastSetConf.update({'power5Ti': int(power5Ti)}) if power6Ti: lastSetConf.update({'power6Ti': int(power6Ti)}) if power7Ti: lastSetConf.update({'power7Ti': int(power7Ti)}) if power8Ti: lastSetConf.update({'power8Ti': int(power8Ti)}) self.set_dev_setting(lastSetConf) # 新增总继电器开关 if relayMasterSwitch: try: self.relay_master_switch(relayMasterSwitch) except Exception as e: pass def handle_clear_start_error(self, port): dealer = Dealer.objects.get(id=self._device['ownerId']) if not dealer or not dealer.managerialOpenId: return group = Group.get_group(self._device['groupId']) self.lock_unlock_port(port, lock=False) notifyData = { 'title': '设备故障报警解除', 'device': u'{gNum}组-{lc}-{port}端口'.format(gNum=self._device['groupNumber'], lc=self._device['logicalCode'], port=port), 'location': u'{address}-{groupName}'.format(address=group['address'], groupName=group['groupName']), 'fault': u'当前端口已被正常启动,端口故障解除', 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') } task_caller( func_name='report_to_dealer_via_wechat', openId=dealer.managerialOpenId, dealerId=str(dealer.id), templateName='device_fault', **notifyData ) self.lock_unlock_port(port, lock=False) def handle_out_start_error(self, port): dealer = Dealer.objects.get(id=self._device['ownerId']) if not dealer or not dealer.managerialOpenId: return group = Group.get_group(self._device['groupId']) times = Device.get_error_start_times(self._device['devNo'], port) self.lock_unlock_port(port, lock=True) notifyData = { 'title': u'注意,您的设备可能发生故障!', 'device': u'{gNum}组-{lc}-{port}端口'.format(gNum=self._device['groupNumber'], lc=self._device['logicalCode'], port=port), 'location': u'{address}-{groupName}'.format(address=group['address'], groupName=group['groupName']), 'fault': u'当前设备端口连续启动 {times} 失败,目前该端口已经被自动禁用,请注意该端口是否发生故障'.format(times=times), 'notifyTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') } task_caller( func_name='report_to_dealer_via_wechat', openId=dealer.managerialOpenId, dealerId=str(dealer.id), templateName='device_fault', **notifyData ) # 麦总的告警3次触发,同时锁定设备,为避免解锁设备之后 再次触发 这个地方需要将其缓存清空 Device.delete_error_start_times(self._device['devNo'], port) def set_coin_ic_switch(self, coin=True, ic=True): if coin: data = '01' else: data = '00' if ic: data += '01' else: data += '00' result = self.send_mqtt({'funCode': '09', 'data': data}) return result @SmartBox.check_device_features(device_features=["fun_code_30_31"]) def relay_master_switch(self, relayMasterSwitch=1): if relayMasterSwitch == 1: data = "01" else: data = "00" devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'funCode': '31', 'data': data}, timeout=7) 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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) self.device.update_other_conf(relayMasterSwitch=relayMasterSwitch) def check_order_state(self, openId): """ 通过 openId 以及设备来鉴别 订单 :param openId: :return: """ dealerId = self.device.ownerId return ClientConsumeModelProxy.get_not_finished_record(ownerId=dealerId, openId=openId, devTypeCode=self._device['devType']['code'], package__billingMethod=CONSUMETYPE.POSTPAID) def start_device_realiable(self, order): return super(JNDZPOLICYBox, self).start_device_realiable(order) def deal_order_finish(self, order, data=None): pass def set_volume(self, volume): volume = self.check_params_range(volume, minData=0.0, maxData=8.0, desc='音量') try: self.send_mqtt({'funCode': '24', 'data': self.encode_str(volume)}, timeout=2) except: pass Device.get_collection().update_one(filter={'devNo': self.device.devNo}, update={'$set': {'otherConf.volume': volume, }}) Device.invalid_device_cache(self.device.devNo) def get_server_setting(self): return { 'minAfterStartCoins': self.device['otherConf'].get('minAfterStartCoins', 0), 'refundProtectionTime': self.server_configs.get('refundProtectionTime', 5), 'packages': self.get_power_price_rules(), 'timeElec': self.server_configs.get('timeElec', 1), 'coinRatio': self.server_configs.get('coinRatio', 1), 'onlineCardMinStartCoins': self.server_configs.get('onlineCardMinStartCoins', 0), 'onlineCardTime': self.server_configs.get('onlineCardTime', 720), 'onlineCardELec': self.server_configs.get('onlineCardELec', 3) } def set_server_setting(self, payload): updateConf = { } packages = payload.get('packages') if packages: updateConf.update({ 'otherConf.serverConfigs.power_price_rules': self.check_power_price_rules(packages) }) timeElec = payload.get('timeElec') if timeElec: updateConf.update({'otherConf.serverConfigs.timeElec': round(float(timeElec), 4)}) refundProtectionTime = payload.get('refundProtectionTime', None) if refundProtectionTime: updateConf.update({ 'otherConf.serverConfigs.refundProtectionTime': int(refundProtectionTime) }) coinRatio = payload.get('coinRatio') if coinRatio: updateConf.update({ 'otherConf.serverConfigs.coinRatio': round(float(coinRatio), 2) }) if 'minAfterStartCoins' in payload and payload['minAfterStartCoins']: minAfterStartCoins = self.check_params_range( payload['minAfterStartCoins'], minData=0.0, maxData=100.0, desc='设备启动最小余额') updateConf.update({ 'otherConf.minAfterStartCoins': float(minAfterStartCoins) }) onlineCardMinStartCoins = payload.get('onlineCardMinStartCoins') onlineCardTime = payload.get('onlineCardTime') onlineCardELec = payload.get('onlineCardELec') if onlineCardMinStartCoins and onlineCardTime and onlineCardELec: updateConf.update( { 'otherConf.serverConfigs.onlineCardMinStartCoins': round(float(onlineCardMinStartCoins), 2), 'otherConf.serverConfigs.onlineCardTime': round(float(onlineCardTime), 2), 'otherConf.serverConfigs.onlineCardELec': round(float(onlineCardELec), 4) }) self.device.update_device_obj(**updateConf)