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