123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522 |
- # -*- 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)
|