# -*- coding: utf-8 -*- from apps.web.core.adapter.base import * from apps.web.device.models import Device class ChargingMXZ2Box(SmartBox): def __init__(self, device): super(ChargingMXZ2Box, self).__init__(device) def translate_funcode(self,funCode): funCodeDict = { '31':u'获取端口数量', '20':u'操作端口', '02':u'回复刷卡余额', '03':u'回复刷卡充电', '04':u'回复结束报文', '23':u'获取功率', } return funCodeDict.get(funCode,'') def translate_event_cmdcode(self,cmdCode): cmdDict = { '02':u'刷卡事件', '03':u'刷卡启动或者关闭端口', '04':u'充电结束', '20':u'端口开始或者结束', } return cmdDict.get(cmdCode,'') def get_port_info(self,line): portDict = self.get_power() if portDict.has_key(line): return {'power':portDict[line]} def is_port_can_use(self, port, canAdd=False): return super(ChargingMXZ2Box, self).is_port_can_use(port, True) 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']) 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) statusDict = {} 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, attachParas=None): devInfo = MessageSender.send_for_moxiaozhiv2(self.device, self.make_random_cmdcode(), {'IMEI': self._device['devNo'],"funCode":'31','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'][18::] if data[0:2] == '01':#表示成功 pass else: raise ServiceException({'result': 2, 'description': u'获取设备信息失败,,建议您试试旁边其他设备,或者稍后再试哦'}) portNum = int(data[2:4],16) #充电板那边说,用获取功率的方式更加稳定一些 try: confDict = Device.objects.get(devNo = self._device['devNo']).otherConf except Exception,e: logger.error('update dev=%s coin enable ic enable e=%s' %(self._device['devNo'],e)) raise ServiceException({'result': 2, 'description': u'没有找到该设备的配置信息,请稍候重试,或者换周围其他的设备吧'}) devInfo = Device.get_dev_control_cache(self._device['devNo']) nowTime = datetime.datetime.now() resultDict = {} powerDict = self.get_power() for port,power in powerDict.items(): portCtrInfo = devInfo.get(str(port)) if int(port) > portNum: continue if power <= 25: resultDict[str(port)] ={'status':Const.DEV_WORK_STATUS_IDLE} if portCtrInfo is not None: strStartTime = portCtrInfo.get('startTime',None) if portCtrInfo.get('isStart',False) and strStartTime: startTime = to_datetime(strStartTime) timeDelta = (nowTime - startTime).total_seconds() if timeDelta <= 60: resultDict[str(port)] ={'status':Const.DEV_WORK_STATUS_WORKING} else:#设备功率是按照分钟来取的,端口停掉后,设备一分钟内的状态不会马上变化,所以需要刷新 if portCtrInfo is None: resultDict[str(port)] ={'status':Const.DEV_WORK_STATUS_WORKING} else: strEndTime = portCtrInfo.get('endTime',None) if not strEndTime: resultDict[str(port)] ={'status':Const.DEV_WORK_STATUS_WORKING} else: endTime = to_datetime(strEndTime) timeDelta = (nowTime - endTime).total_seconds() if timeDelta <= 60: resultDict[str(port)] ={'status':Const.DEV_WORK_STATUS_IDLE} else: resultDict[str(port)] ={'status':Const.DEV_WORK_STATUS_WORKING} portKey = 'port%s' % port if confDict.has_key(portKey) and confDict[portKey] == Const.DEV_WORK_STATUS_FORBIDDEN: resultDict[str(port)] = {'status':Const.DEV_WORK_STATUS_FORBIDDEN} allPorts,usedPorts,usePorts = self.get_port_static_info(resultDict) 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 resultDict.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 resultDict def stop_charging_port(self,port): self.active_deactive_port(port, False) def lock_unlock_port(self,port,lock): dev = Device.objects.get(devNo = self._device['devNo']) portKey = 'port%s' % port if lock: dev.otherConf.update({portKey:Const.DEV_WORK_STATUS_FORBIDDEN}) else: dev.otherConf.update({portKey:Const.DEV_WORK_STATUS_IDLE}) dev.save() if lock: self.stop_charging_port(port) 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,duration=None): tmpPort = hex(int(port)) hexPort = fill_2_hexByte(tmpPort,2) if active: strOp = '01' else: strOp = '00' if duration: cmdDict = {'IMEI': self._device['devNo'],"funCode":'20','data':'00' + hexPort + strOp,'duration':int(duration) } else: cmdDict = {'IMEI': self._device['devNo'],"funCode":'20','data':'00' + hexPort + strOp } devInfo = MessageSender.send_for_moxiaozhiv2(self.device, self.make_random_cmdcode(),cmdDict) 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'][18::] if data[0:2] == '01':#表示成功 pass else: raise ServiceException({'result': 2, 'description': u'操作和预期不符合,请您选择其他线路,或者稍候再试哦'}) if not active:#关闭充电桩的端口 devInfo = Device.get_dev_control_cache(self._device['devNo']) portCtrInfo = devInfo.get(str(port),{}) portCtrInfo.update({'isStart':False,'status':Const.DEV_WORK_STATUS_IDLE,'needTime':0,'leftTime':0,'endTime':datetime.datetime.now().strftime(Const.DATETIME_FMT)}) newValue = {str(port):portCtrInfo} Device.update_dev_control_cache(self._device['devNo'], newValue) return devInfo def test(self, coins): hexPort = fill_2_hexByte(1,2) cmdDict = {'duration':5} cmdDict.update({'IMEI': self._device['devNo'],"funCode":'20','data':'00' + hexPort + '01' }) devInfo = MessageSender.send_for_moxiaozhiv2(self.device, self.make_random_cmdcode(), cmdDict) return devInfo 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'请您选择合适的充电线路'}) #如果端口正在使用,不允许重复付款 strPort = str(attachParas['chargeIndex']) ctrInfo = Device.get_dev_control_cache(self._device['devNo']) if ctrInfo.__class__.__name__ == 'dict' and ctrInfo.has_key(strPort): portInfo = ctrInfo[strPort] if portInfo.has_key('isStart') and portInfo['isStart']: raise ServiceException({'result': 2, 'description': u'您选择的充电端口正在使用,不允许使用此端口,建议您换其他端口哦!'}) coins = float(package['coins']) unit = package.get('unit',u'分钟') if unit in [u'分钟',u'小时',u'天']: time1 = int(package['time']) if unit == u'小时': time1 = time1 * 60 elif unit == u'天': time1 = time1 * 1440 devObj = Device.objects.get(devNo = self._device['devNo']) billingType = devObj.otherConf.get('billingType','time') if billingType == 'time': minuteFee = devObj.otherConf.get('minuteFee',0.03) time2 = int(coins/minuteFee) maxValue = int(min(time1,time2)) cmdDict = {'duration':maxValue} else: elecFee = devObj.otherConf.get('elecFee',0.9) maxValue = int(coins/elecFee*3600) cmdDict = {'elec':maxValue,'duration':time1} elif unit == u'次': devObj = Device.objects.get(devNo = self._device['devNo']) billingType = devObj.otherConf.get('billingType','time') if billingType == 'time': minuteFee = devObj.otherConf.get('minuteFee',0.03) time2 = int(coins/minuteFee) cmdDict = {'duration':time2} else: elecFee = devObj.otherConf.get('elecFee',0.9) maxValue = int(coins/elecFee*3600) cmdDict = {'elec':maxValue} elif unit == u'度': devObj = Device.objects.get(devNo = self._device['devNo']) billingType = devObj.otherConf.get('billingType','time') if billingType == 'time': minuteFee = devObj.otherConf.get('minuteFee',0.03) time2 = int(coins/minuteFee) cmdDict = {'duration':time2} else: elecConf = float(package['time']) elecFee = devObj.otherConf.get('elecFee',0.9) maxValue = int(min(coins/elecFee*3600,elecConf*3600)) cmdDict = {'elec':maxValue} tmpPort = hex(int(attachParas['chargeIndex'])) hexPort = fill_2_hexByte(tmpPort,2) cmdDict.update({'IMEI': self._device['devNo'],"funCode":'20','data':'00' + hexPort + '01' }) devInfo = MessageSender.send_for_moxiaozhiv2(self.device, self.make_random_cmdcode(),cmdDict,timeout=120) 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'][18::] if data[0:2] == '01':#表示成功 pass else: raise ServiceException({'result': 2, 'description': u'操作和预期不符合,请您选择其他线路,或者稍候再试哦'}) #刷新状态 if package.has_key('time'): needTime = int(float(package.get('time'))) newValue = { str(attachParas['chargeIndex']): { 'status': Const.DEV_WORK_STATUS_WORKING, 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'coins': coins, 'isStart': True, 'refunded': False, 'openId': openId, 'needTime': needTime, 'vCardId': self._vcard_id } } elif package.has_key('power'): newValue = { str(attachParas['chargeIndex']): { 'status': Const.DEV_WORK_STATUS_WORKING, 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'coins': coins, 'isStart': True, 'refunded': False, 'openId': openId, 'needPower': package.get('power'), 'vCardId': self._vcard_id } } Device.update_dev_control_cache(self._device['devNo'], newValue) return devInfo def analyze_event_data(self,data): cmdCode = data[12:14] if cmdCode == '02':#刷卡 cardNo = str(int(data[20:36][-10::])) return {'cardNo':cardNo,'cmdCode':cmdCode} elif cmdCode == '03':#刷卡,启动或者关闭设备 portNo = int(data[20:22],16) cardNo = str(int(data[24:40][-10::])) flag = int(data[22:24]) if flag == 0: isStart = False return {'cmdCode':cmdCode,'cardNo':cardNo,'port':portNo,'isStart':isStart,'endTime':datetime.datetime.now().strftime(Const.DATETIME_FMT)} else: isStart = True return {'cmdCode':cmdCode,'cardNo':cardNo,'port':portNo,'isStart':isStart,'startTime':datetime.datetime.now().strftime(Const.DATETIME_FMT)} elif cmdCode == '04': portNo = int(data[20:22],16) flag = int(data[22:24]) reason = '' if flag == 0: isStart = False else: isStart = True return {'cmdCode':cmdCode,'port':portNo,'isStart':isStart,'reason':reason,'startTime':datetime.datetime.now().strftime(Const.DATETIME_FMT)} if not isStart: flag = data[24:26] if flag == '00': reason = u'电池没有充满!原因未知。' elif flag == '01': reason = u'可能是电池没有接好,或者电池本身就是满电的。建议您到现场检查是否有人误操作,以尽快恢复充电。' elif flag == '02': reason = u'恭喜您!电池已经充满电!' elif flag == '03': reason = u'警告!您的电池功率超过本机最大限制,已经停止充电,为了公共安全,不建议您在该充电桩充电!提醒您,为了安全大功率的电池不要放入楼道、室内等位置充电哦' return {'cmdCode':cmdCode,'port':portNo,'isStart':isStart,'reason':reason,'endTime':datetime.datetime.now().strftime(Const.DATETIME_FMT),'flag':flag} elif cmdCode == '20': portNo = int(data[20:22],16) flag = int(data[22:24]) reason = '' if flag == 0: isStart = False else: isStart = True return {'cmdCode':cmdCode,'port':portNo,'isStart':isStart,'reason':reason,'startTime':datetime.datetime.now().strftime(Const.DATETIME_FMT)} if not isStart: reason = u'管理人员可能远程断电了,建议您根据已经充电的时间评估是否需要到现场换到其他端口充电。' return {'cmdCode':cmdCode,'port':portNo,'isStart':isStart,'reason':reason,'endTime':datetime.datetime.now().strftime(Const.DATETIME_FMT),'flag':flag} return None def response_card_balance(self,cardNo,balance): devObj = Device.objects.get(devNo = self._device['devNo']) billingType = devObj.otherConf.get('billingType','time') if billingType == 'time': minuteFee = devObj.otherConf.get('minuteFee',0.03) maxValue = int(float(str(balance))/minuteFee) maxType = 'duration' else: elecFee = devObj.otherConf.get('elecFee',0.9) maxValue = int(float(str(balance))/elecFee*3600) maxType = 'elec' data = '' try: if balance == 0: data = '03' else: data = '01' + fill_2_hexByte(hex(int(balance*100)),8) except Exception,e: logger.error('can not find the card=%s' % cardNo) data = '05' devInfo = MessageSender.send_for_moxiaozhiv2(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {maxType:maxValue,'IMEI': self._device['devNo'],"funCode":'02','data':data}) if devInfo.has_key('rst') and devInfo['rst'] != 0: if devInfo['rst'] == -1: raise ServiceException( {'result': 2, 'description': u'充电桩正在玩命找网络,请您稍候再试'}) elif devInfo['rst'] == 1:#等于1的时候,说明服务器和远程模块通讯OK,响应已经收到,不需要异常处理 pass def response_card_charging(self,result): if result: data = '01' else: data = '00' devInfo = MessageSender.send_for_moxiaozhiv2(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'],"funCode":'03','data':data}) if devInfo.has_key('rst') and devInfo['rst'] != 0: if devInfo['rst'] == -1: raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,建议您试试旁边其他设备,或者稍后再试哦'}) elif devInfo['rst'] == 1: pass def response_finished_back(self, result): if result: data = '01' else: data = '00' devInfo = MessageSender.send_for_moxiaozhiv2(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'],"funCode":'04','data':data}) if devInfo.has_key('rst') and devInfo['rst'] != 0: if devInfo['rst'] == -1: raise ServiceException({'result': 2, 'description': u'充电桩正在玩命找网络,建议您试试旁边其他设备,或者稍后再试哦'}) elif devInfo['rst'] == 1: pass def get_power(self): devInfo = MessageSender.send_for_moxiaozhiv2(self.device, self.make_random_cmdcode(), {'IMEI': self._device['devNo'],"funCode":'23','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'][18::] if data[0:2] == '01':#表示成功 pass else: raise ServiceException({'result': 2, 'description': u'获取功率失,请试试其他线路,或者稍后再试哦'}) powerData = data[2:-8] resultDict = {} for ii in range(len(powerData)/4): port = ii + 1 status = powerData[ii*4:ii*4+4] resultDict[str(port)] = int(status,16) return resultDict #目前支持按时间计费,后续支持按照电量计费的方式 def calc_consume_money(self, spendTime, elec): try: dev = Device.objects.get(devNo = self._device['devNo']) except Exception, e: logger.error('can not find the dev=%s' % self._device['devNo']) return RMB(0) billingType = dev.otherConf.get('billingType', 'time') if billingType == 'time': minuteFee = dev.otherConf.get('minuteFee', 0.03) return RMB(1) * spendTime * minuteFee, u'时间计费' else: elecFee = dev.otherConf.get('elecFee', 0.9) return RMB(1) * elecFee * elec, u'电度计费' def get_dev_setting(self): try: dev = Device.objects.get(devNo = self._device['devNo']) except Exception,e: logger.error('can not find the dev=%s' % self._device['devNo']) return {} minuteFee = dev.otherConf.get('minuteFee',0.03) elecFee = dev.otherConf.get('elecFee',0.9) billingType = dev.otherConf.get('billingType','time') return {'minuteFee':minuteFee,'elecFee':elecFee,'billingType':billingType} def set_dev_setting(self,conf): try: dev = Device.objects.get(devNo = self._device['devNo']) except Exception,e: logger.error('can not find the dev=%s' % self._device['devNo']) return 0 if conf.has_key('minuteFee'): dev.otherConf.update({'minuteFee':conf['minuteFee']}) if conf.has_key('elecFee'): dev.otherConf.update({'elecFee':conf['elecFee']}) if conf.has_key('billingType'): dev.otherConf.update({'billingType':conf['billingType']}) try: dev.save() except Exception,e: logger.exception('save dev=%s conf error=%s' % (self._device['devNo'],e)) def set_device_function_param(self,request,lastSetConf): minuteFee = float(request.POST.get('minuteFee', None)) if minuteFee: lastSetConf.update({'minuteFee': float(minuteFee)}) elecFee = float(request.POST.get('elecFee', None)) if elecFee: lastSetConf.update({'elecFee': float(elecFee)}) billingType = request.POST.get('billingType', 'time') if billingType: lastSetConf.update({'billingType': billingType}) minuteFee = request.POST.get('minuteFee', None) if minuteFee: lastSetConf.update({'minuteFee': float(minuteFee)}) self.set_dev_setting(lastSetConf)