# -*- coding: utf-8 -*- #!/usr/bin/env python import copy import datetime import time from apilib.monetary import RMB from apps.web.common.transaction import UserConsumeSubType from apps.web.constant import DeviceCmdCode, Const, MQTT_TIMEOUT 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, MyUser class ChargingPlugBox(SmartBox): def __init__(self, device): super(ChargingPlugBox, self).__init__(device) def translate_funcode(self, fun_code): fun_codeDict = { '01': u'查询所有子设备状态', '02': u'查询全部端口详情', '03': u'绑定设备', '04': u'重启设备', '05': u'解绑设备', '07': u'启动端口', '08': u'查询设备信息', '09': u'查询端口信息', '0B': u'设置设备配置', '0C': u'查询设备配置', } return fun_codeDict.get(fun_code, '') def translate_event_cmdcode(self, cmdCode): cmdDict = { } return cmdDict.get(cmdCode, '') def test(self, coins): data = {'fun_code':0x07,'order_id':'1111','chrmt':0,'port_id':1,'amount':60} devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': data}) return devInfo def check_feedback_result(self,devInfo): if not devInfo.has_key('rst'): raise ServiceException({'result': 2, 'description': u'报文异常'}) if devInfo['rst'] == -1: raise ServiceException({'result': 2, 'description': u'充电插座正在玩命找网络,请您稍候再试'}) if devInfo['rst'] == 1: raise ServiceException({'result': 2, 'description': u'串口通讯失败,您稍候再试,或者联系客服'}) if devInfo['rst'] == 2: raise ServiceException({'result': 2, 'description': u'端口被禁用'}) if devInfo['rst'] == 3: raise ServiceException({'result': 2, 'description': u'端口计量器故障'}) if devInfo['rst'] == 4: raise ServiceException({'result': 2, 'description': u'设备订单已达上限'}) if devInfo['rst'] == 5: raise ServiceException({'result': 2, 'description': u'设备正在自检'}) # result = devInfo['data']['result'] # if result == 0: # return # else:#等待设备的错误码进行细化 # raise ServiceException({'result': 2, 'description': u'充电插座返回了错误,请您重试看看能否解决问题'}) def get_port_from_ab(self,portAB): portConf = {'A':1,'B':2,'C':3} if portAB in portConf: return portConf[portAB] return portAB def get_abport_from_index(self,port): portConf = {'1':'A','2':'B','3':'C'} return portConf.get(port) 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(self.get_port_from_ab(attachParas['chargeIndex'])) attachParas['chargeIndex'] = port unit = package.get('unit', u'分钟') needTime,needElec = None,None order_no = ConsumeRecord.make_no(self.device.logicalCode, UserConsumeSubType.NETPAY) if unit == u'秒': if int(package['time']) < 60: raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'}) needTime = int(float(package['time'])) data = {'fun_code':0x07,'order_id':order_no,'chrmt':0,'port_id':port,'amount':needTime} elif unit == u'分钟': needTime = int(package['time'])*60 data = {'fun_code':0x07,'order_id':order_no,'chrmt':0,'port_id':port,'amount':needTime} elif unit == u'小时': needTime = int(float(package['time']) * 60 * 60) data = {'fun_code':0x07,'order_id':order_no,'chrmt':0,'port_id':port,'amount':needTime} elif unit == u'天': needTime = int(float(package['time']) * 60 * 60 * 24) data = {'fun_code':0x07,'order_id':order_no,'chrmt':0,'port_id':port,'amount':needTime} elif unit == u'度': needElec = int(float(package['time'])*1000)#微度,需要乘于16个零 data = {'fun_code':0x07,'order_id':order_no,'chrmt':2,'port_id':port,'amount':needElec} else: needTime = int(package['time']) data = {'fun_code':0x07,'order_id':order_no,'chrmt':1,'port_id':port,'amount':needTime} devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': data}, timeout = MQTT_TIMEOUT.START_DEVICE) self.check_feedback_result(devInfo) data = devInfo['data'] if devInfo['rst'] == 0: # 成功 newValue = { str(port): { 'status': Const.DEV_WORK_STATUS_WORKING, 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S') } } else:#TODO result的枚举列出原因 raise ServiceException({'result': 2, 'description': u'充电插座响应异常,请您稍后再试哦'}) if needTime: finishedTime = int(time.time()) + needTime devInfo['needTime'] = needTime/60 elif needElec: finishedTime = int(time.time()) + 60 * 60 * 10#设定10个小时,确实很难知道可以用多久结束 devInfo['needElec'] = float(package['time']) else: finishedTime = int(time.time()) + 60 * 60 * 10#设定10个小时,确实很难知道可以用多久结束 pass newValue.update({'finishedTime': finishedTime}) Device.update_dev_control_cache(self._device['devNo'], newValue) devInfo['finished_time'] = finishedTime devInfo['consumeOrderNo'] = order_no return devInfo def analyze_event_data(self, data): if data['fun_code'] == '34':#如果是结束事件,需要把reason翻译出来 descDict = { '5':u'支付的金额已经使用完毕', '6':u'用户手工停止了充电', '7':u'电池充满自停', '8':u'故障导致充电停止', '9':u'本端口功率过载,主动关闭', '10':u'没有连接充电器,主动关闭', '11':u'远程关闭', '12':u'检测到烟雾告警,主动关闭' } order = data['order'] order['reason'] = descDict.get(str(order['closeType']),u'') data['order'] = order return data def get_port_status_from_dev(self): # 先到设备上,把所有子节点的信息取出来,记录到主节点的缓存 devInfo = MessageSender.send(self.device, self.make_random_cmdcode(), {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x02}}) self.check_feedback_result(devInfo) allPorts,usedPorts = 0,0 result = {} for portId,portInfo in devInfo['data']['ports'].items(): portDict = { 'status':self.__translate_status_from_str(str(portInfo['port_status'])), 'power':round(portInfo['watt']*0.1,2), 'electricity':round(portInfo['ampr']*0.1,2), } if not portInfo.has_key('order') or not portInfo['order']: Device.clear_port_control_cache(self._device['devNo'],portId) result[portId] = portDict allPorts += 1 continue order = portInfo['order'] portDict['elec'] = order['elec'] * 0.001 if order['order_type'] == 'apps_start': portDict['consumeType'] = 'mobile' try: rcd = ConsumeRecord.objects.get(orderNo = order['id']) if u'虚拟卡' in rcd.remarks: portDict['consumeType'] = 'mobile_vcard' except Exception,e: pass elif order['order_type'] == 'coin_start': portDict['consumeType'] = 'coin' elif order['order_type'] == 'card_start': portDict['consumeType'] = 'card' else: portDict['consumeType'] = 'mobile' if order.has_key('chrmt'): if order['chrmt'] in [0,1]: portDict['needTime'] = round(order['amount']/60.0,1) if order.has_key('time'): portDict['duration'] = round(order['time']/60.0,1) portDict['usedTime'] = round(order['time']/60.0,1) if order.has_key('left_time'): portDict['leftTime'] = round(order['left_time']/60.0,1) else: portDict['needElec'] = order['amount'] * 0.001 if order.has_key('elec'): portDict['usedElec'] = order.get('elec') * 0.001 if order.has_key('execute_time'): portDict['startTime'] = datetime.datetime.fromtimestamp(int(portInfo['execute_time'])).strftime('%m-%d %H:%M:%S') if order.has_key('id') and (order['order_type'] not in ['coin_start','card_charge']) :#card_charge try: rcd = ConsumeRecord.objects.get(orderNo = order['id']) portDict['openId'] = rcd['openId'] portDict['coins'] = float(str(rcd['coin']))#都用coins portDict['money'] = float(str(rcd['money'])) portDict['orderNo'] = str(portInfo['id']) user = MyUser.objects(openId=portDict['openId']).first() if user: portDict['nickName'] = user.nickname except Exception,e:#IC卡,如果没有绑定,不会有consumeRcd,应该直接从订单中拿数据 pass result[portId] = portDict if portInfo['port_status'] == 1: usedPorts += 1 allPorts += 1 result.update({'usedPorts':usedPorts,'allPorts':allPorts,'usePorts':allPorts-usedPorts}) Device.update_dev_control_cache(self._device['devNo'],result) return result def get_port_info(self, line): line = self.get_port_from_ab(line) portCache = Device.get_dev_control_cache(self._device['devNo']) return portCache.get(str(line),{}) def __translate_status_from_str(self,status): dictConf = { '0':Const.DEV_WORK_STATUS_IDLE, '1':Const.DEV_WORK_STATUS_WORKING, '2':Const.DEV_WORK_STATUS_FAULT, '3':Const.DEV_WORK_STATUS_FAULT, } return dictConf.get(status,Const.DEV_WORK_STATUS_FAULT) def get_port_status(self, force = False): if force: self.get_port_status_from_dev() portCache = Device.get_dev_control_cache(self._device['devNo']) result = {} for ii in range(5): if str(ii) in portCache: if ii == 1: result['A'] = portCache[str(ii)] elif ii == 2: result['B'] = portCache[str(ii)] elif ii == 3: result['C'] = portCache[str(ii)] return result def lock_unlock_port(self, port, lock = True): port = self.get_port_from_ab(port) portInfo = self.get_port_info(port) if portInfo['status'] == Const.DEV_WORK_STATUS_WORKING: 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 stop_charging_port(self, port): port = self.get_port_from_ab(port) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x06, 'port_id': port}}) self.check_feedback_result(devInfo) 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 add_to_gateway(self,gatewayDevNo): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': gatewayDevNo, 'data': {'fun_code': 0x03, 'dev_id': self._device['devNo']}}) self.check_feedback_result(devInfo) # 子节点的父节点也要更新 devObj = Device.objects.get(devNo = self._device['devNo']) devObj.gatewayNode = gatewayDevNo devObj.save() def remove_from_gateway(self,gatewayDevNo): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': gatewayDevNo, 'data': {'fun_code': 0x05, 'dev_id': self._device['devNo']}}) self.check_feedback_result(devInfo) # 子节点的父节点也要更新 devObj = Device.objects.get(devNo = self._device['devNo']) devObj.gatewayNode = '' devObj.save() def response_card_event(self, cardNo,portId,balance,result=None): otherConf = Device.objects.get(devNo = self._device['devNo']).otherConf cardConf = otherConf.get('cardConf',{'billingType':'time','onceCard':100,'onceTime':180*60}) chrmt = 0 if cardConf['billingType'] == 'time': amount = float(cardConf['onceCard']) * 0.1 * int(cardConf['onceTime']) * 60 chrmt = 0 elif cardConf['billingType'] == 'elec': amount = float(cardConf['onceCard']) * 0.1 * float(cardConf['onceElec']) * 1000 chrmt = 2 else: amount = float(cardConf['onceCard']) * 0.1 * int(cardConf['onceTime']) * 60 chrmt = 1 if result is None: if RMB(float(cardConf['onceCard']) * 0.1) > balance: result = 5 else: result = 1 devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': {'fun_code':35, 'card_no':cardNo, 'balance':int(100*float(balance)), 'amount':int(amount), 'result':result, 'chrmt':chrmt, 'port_id':portId }}) self.check_feedback_result(devInfo) # 获取设备配置参数 def get_dev_setting(self): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x0C}}) self.check_feedback_result(devInfo) configs = devInfo['data']['configs'] devObj = Device.objects.get(devNo = self._device['devNo']) otherConf = devObj.otherConf configs['online_card_once_card'] =otherConf.get('cardConf',{}).get('onceCard',100) configs['online_card_once_time'] = otherConf.get('cardConf',{}).get('onceTime',180) configs['online_card_once_elec'] = otherConf.get('cardConf',{}).get('onceElec',1) if configs['chrmt_mode'] in [0,1]: configs['once_offline_card_charge_time'] = configs['card_lv1_val'] configs['once_offline_card_elec'] = otherConf.get('cardConf',{}).get('offlineOnceElec',1) else: configs['once_offline_card_charge_time'] = otherConf.get('cardConf',{}).get('offlineOnceTime',180) configs['once_offline_card_elec'] = configs['card_lv1_val'] modeDict = {'0':'time','1':'power','2':'elec'} configs['chrmt_mode'] = modeDict.get(str(configs['chrmt_mode'])) return configs # 获取设备配置参数 def set_dev_setting(self, setConf): setConf.update({'fun_code':0x0B}) if setConf['chrmt_mode'] == 'time': setConf['chrmt_mode'] = 0 setConf['card_lv1_val'] = setConf['once_offline_card_charge_time'] elif setConf['chrmt_mode'] == 'power': setConf['chrmt_mode'] = 1 setConf['card_lv1_val'] = setConf['once_offline_card_charge_time'] else: setConf['chrmt_mode'] = 2 setConf['card_lv1_val'] = setConf['once_offline_card_elec'] setConf['temp_threshold'] = int(setConf['temp_threshold']) setConf['float_charge_watt'] = int(setConf['float_charge_watt']) setConf['float_charge_time'] = int(setConf['float_charge_time']) setConf['noload_check_time'] = int(setConf['noload_check_time']) setConf['port_max_watt'] = int(setConf['port_max_watt']) setConf['mach_max_watt'] = int(setConf['mach_max_watt']) setConf['noload_check_watt'] = int(setConf['noload_check_watt']) setConf['power_lv1_watt'] = int(setConf['power_lv1_watt']) setConf['power_lv1_time'] = int(setConf['power_lv1_time']) setConf['power_lv2_watt'] = int(setConf['power_lv2_watt']) setConf['power_lv2_time'] = int(setConf['power_lv2_time']) setConf['power_lv3_watt'] = int(setConf['power_lv3_watt']) setConf['power_lv3_time'] = int(setConf['power_lv3_time']) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,{'IMEI': self._device['devNo'],'data': setConf}) self.check_feedback_result(devInfo) devObj = Device.objects.get(devNo = self._device['devNo']) otherConf = devObj.otherConf if not otherConf.has_key('cardConf'): otherConf['cardConf'] = {} modeDict = {'0':'time','1':'power','2':'elec'} otherConf['cardConf']['billingType'] = modeDict.get(str(setConf['chrmt_mode'])) otherConf['cardConf']['onceCard'] = float(setConf['online_card_once_card']) otherConf['cardConf']['onceTime'] = int(setConf['online_card_once_time']) otherConf['cardConf']['onceElec'] = int(setConf['online_card_once_elec']) otherConf['cardConf']['offlineOnceTime'] = setConf['once_offline_card_charge_time'] otherConf['cardConf']['offlineOnceElec'] = setConf['once_offline_card_elec'] devObj.save() def ack_event(self,orderNo,funCode): devInfo = MessageSender.send(self.device, DeviceCmdCode.PASSTHROUGH_OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'], 'data': {'fun_code':funCode,'order_id':orderNo}}) self.check_feedback_result(devInfo) def reboot_device(self): data = {'fun_code':0x04} MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC,{'IMEI': self._device['devNo'], 'data': data}) def active_deactive_port(self, port, active): port = self.get_port_from_ab(port) if active: raise ServiceException({'result': 2, 'description': u'该设备不支持直接打开端口'}) return self.stop_charging_port(port) def set_device_function_param(self, request, lastSetConf): newConf = copy.deepcopy(request.POST) newConf.pop('logicalCode', None) self.set_dev_setting(newConf)