# -*- coding: utf-8 -*- #!/usr/bin/env python import time import logging import datetime from apilib.utils_datetime import timestamp_to_dt from apps.web.constant import Const, DeviceCmdCode, MQTT_TIMEOUT from apps.web.core.adapter.base import SmartBox, fill_2_hexByte 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 apps.web.core.device_define.water_despenser import CMD_CODE from apps.web.helpers import get_wechat_manager_mp_proxy from apps.web.user.models import MyUser logger = logging.getLogger(__name__) class WaterControllerBox(SmartBox): def __init__(self, device): super(WaterControllerBox, self).__init__(device) def _refresh_device_uart(self): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": 'E9', 'data': ''}, timeout=15) self.__verify_device_operate_status(devInfo) def __verify_device_operate_status(self, devInfo): if 'rst' in devInfo and devInfo['rst'] != 0: if devInfo['rst'] == -1: raise ServiceException( { 'result': 2, 'description': u'当前设备信号弱无响应。本次操作没有扣除您的金额,您可以稍后重试或者试试附近其他设备。' } ) elif devInfo['rst'] == 1: raise ServiceException( {'result': 2, 'description': u'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能。'}) def start_device(self, package, openId, attachParas): self._refresh_device_uart() if attachParas is None or 'chargeIndex' not in attachParas: raise ServiceException({'result': 2, 'description': u'请您选择合适的端口'}) unit = package.get('unit', u'分钟') if unit not in [u'分钟', u'秒']: raise ServiceException({'result': 2, 'description': u'套餐错误,套餐只支持秒,分钟'}) price = float(package['price']) coins = float(package['coins']) port = hex(int(attachParas['chargeIndex'])) hexPort = fill_2_hexByte(port, 2) devPortInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': 'EF', 'data': hexPort }, timeout=15) self.__verify_device_operate_status(devPortInfo) portCanUse = True if devPortInfo['data'][2:6] == '0000' else False if portCanUse is False: raise ServiceException({'result': 2, 'description': u'端口繁忙,目前无法启动,请稍后再试。'}) # 杜绝续充以及事件异常导致有缓存的情况 Device.clear_port_control_cache(self._device['devNo'], str(attachParas['chargeIndex'])) type = 'FE' if unit == u'秒' else 'FD' needTime = int(package['time']) hexTime = fill_2_hexByte(hex(needTime), 4) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, { 'IMEI': self._device['devNo'], 'funCode': '55', 'data': hexPort + type + hexTime }, timeout=MQTT_TIMEOUT.START_DEVICE) self.__verify_device_operate_status(devInfo) usePort = int(attachParas['chargeIndex']) start_timestamp = int(time.time()) if type == 'FE': finishedTime = start_timestamp + int(needTime) else: finishedTime = start_timestamp + (int(needTime) * 60) portDict = { 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'), 'status': Const.DEV_WORK_STATUS_WORKING, 'price': price, 'coins': coins, 'isStart': True, 'openId': openId, 'refunded': False, 'needTime': needTime, 'type': 'second' if type == 'FE' else 'minute', 'vCardId': self._vcard_id, 'finishedTime': finishedTime, 'isPause': False } if 'linkedRechargeRecordId' in attachParas: item = { 'rechargeRcdId': str(attachParas['linkedRechargeRecordId']) } portDict['payInfo'] = [item] Device.update_dev_control_cache(self._device['devNo'], {str(usePort): portDict}) return devInfo def get_port_status(self, force=True): # self._refresh_device_uart() # ctrInfo = Device.get_dev_control_cache(self._device['devNo']) # device = Device.objects(devNo=self._device['devNo']).first() # allPorts = ctrInfo.get('allPorts', device.otherConf.get('portNumber', 5)) # 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}) # # ctrInfo = Device.get_dev_control_cache(self._device['devNo']) # for strPort, info in statusDict.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 statusDict self._refresh_device_uart() devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": 'EF', 'data': '55'}, timeout=15) self.__verify_device_operate_status(devInfo) device = Device.objects(devNo=self._device['devNo']).first() result = {} portNum = device.otherConf.get('portNumber', 5) + 1 portData = devInfo['data'] ctrInfo = Device.get_dev_control_cache(self._device['devNo']) ii = 1 while ii < portNum: port = int(portData[ii * 8 - 2:ii * 8], 16) statusTemp = portData[ii * 8 - 6:ii * 8 - 2] if statusTemp == '0000': if str(port) in ctrInfo: if ctrInfo[str(port)].get('status', 0) == Const.DEV_WORK_STATUS_FORBIDDEN: status = {'status': Const.DEV_WORK_STATUS_FORBIDDEN} else: status = {'status': Const.DEV_WORK_STATUS_IDLE} else: status = {'status': Const.DEV_WORK_STATUS_IDLE} else: status = {'status': Const.DEV_WORK_STATUS_WORKING} 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 strPort in ctrInfo: ctrInfo[strPort].update({'status': info['status']}) else: ctrInfo[strPort] = info Device.update_dev_control_cache(self._device['devNo'], ctrInfo) return result def get_port_status_from_dev(self): return {} def pauseToUseDevice(self, port, oper): self._refresh_device_uart() ctrInfo = Device.get_dev_control_cache(self.device['devNo']) lineInfo = ctrInfo.get(str(port)) funCode = 'EE' if lineInfo.get('isPause', True) is True else 'ED' hexPort = fill_2_hexByte(hex(int(port)), 2) MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": funCode, 'data': hexPort}) if funCode == 'EE': Device.update_dev_control_cache(self._device['devNo'], {str(port): {'isPause': False}}) elif funCode == 'ED': Device.update_dev_control_cache(self._device['devNo'], {str(port): {'isPause': True}}) else: pass 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 stop_charging_port(self, port): self._refresh_device_uart() hexPort = fill_2_hexByte(hex(int(port)), 2) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": 'EC', 'data': hexPort}, timeout=7) self.__verify_device_operate_status(devInfo) leftTime = int(devInfo['data'][2:6], 16) port = int(devInfo['data'][6:8], 16) return {'leftTime': leftTime, 'port': str(port)} def stop(self, port = None): boardRefund = self.get_dev_setting()['boardRefund'] if boardRefund is False: raise ServiceException({'result': 2, 'description': u'暂不支持用户远程停止设备'}) self.stop_charging_port(port) infoDict = dict() infoDict['remainder_time'] = 0 return infoDict @property def isHaveStopEvent(self): return True def analyze_event_data(self, data): cmdCode = data[0:2] if cmdCode == 'EB': port = str(int(data[2:4], 16)) return { 'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port } elif cmdCode == 'EC': leftTime = str(int(data[2:6], 16)) port = str(int(data[6:8], 16)) return { 'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'leftTime': leftTime, 'port': port } def get_dev_setting(self): device = Device.objects(devNo=self._device['devNo']).first() volumeControl = device.otherConf.get('volumeControl', 'medium') portNumber = device.otherConf.get('portNumber', 5) boardRefund = device.otherConf.get('boardRefund', False) return {'volumeControl': volumeControl, 'portNumber': portNumber, 'boardRefund': boardRefund} def set_device_function_param(self, request, lastSetConf): self._refresh_device_uart() portNumber = request.POST['portNumber'] volumeControl = request.POST['volumeControl'] boardRefund = request.POST['boardRefund'] if volumeControl == 'high': volumeControl = '03' elif volumeControl == 'medium': volumeControl = '02' elif volumeControl == 'low': volumeControl = '01' else: pass MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'], "funCode": 'EA', 'data': volumeControl}, timeout=15) time.sleep(2) MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'], "funCode": 'F7' if boardRefund is True else 'F9', 'data': ''}, timeout=15) device = Device.objects(devNo=self._device['devNo']).first() device.otherConf.update({'volumeControl': request.POST['volumeControl']}) device.otherConf.update({'boardRefund': request.POST['boardRefund']}) device.otherConf.update({'portNumber': int(portNumber)}) device.save() Device.invalid_device_cache(device.devNo) def lock_unlock_port(self, port, lock = True): 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}})