# -*- coding: utf-8 -*- # !/usr/bin/env python import copy import datetime import time 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 ServiceProgress class AoQiangSocketNodeBox(SmartBox): def __init__(self, device): super(AoQiangSocketNodeBox, 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'设备启动超时'}) # 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'请您选择合适的充电线路'}) attachParas['chargeIndex'] = self.get_port_from_ab(attachParas['chargeIndex']) port = attachParas['chargeIndex'] unit = package.get('unit', u'分钟') needTime, needElec = 0, 0 orderNo = attachParas.get('orderNo') if unit == u'秒': if int(package['time']) < 60: raise ServiceException({'result': 2, 'description': u'套餐的最小时间不能小于60秒'}) needTime = int(float(package['time'])) / 60 data = {'fun_code': 0x07, 'chrmt': 1, 'port_id': port, 'amount': needTime} elif unit == u'分钟': needTime = int(package['time']) data = {'fun_code': 0x07, 'chrmt': 1, 'port_id': port, 'amount': needTime} elif unit == u'小时': needTime = int(float(package['time']) * 60) data = {'fun_code': 0x07, 'chrmt': 1, 'port_id': port, 'amount': needTime} elif unit == u'天': needTime = int(float(package['time']) * 60 * 24) data = {'fun_code': 0x07, 'chrmt': 1, 'port_id': port, 'amount': needTime} elif unit == u'度': needElec = int(float(package['time'])) * 1000 data = {'fun_code': 0x07, 'chrmt': 2, 'port_id': port, 'amount': needElec} else: raise ServiceException({'result': 2, 'description': u'套餐配置错误'}) 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) if devInfo['rst'] == 0: # 成功 newValue = { 'port': str(port), 'status': Const.DEV_WORK_STATUS_WORKING, 'startTime': datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S'), 'orderNo': orderNo, 'coins': round(package.get('coins'), 2), 'isStart': True, 'openId': openId, 'chrmt': data.get('chrmt'), } if data.get('chrmt') == 1: newValue.update({'needTime': data.get('amount')}) elif data.get('chrmt') == 2: newValue.update({'needElec': data.get('amount')}) else: # TODO result的枚举列出原因 raise ServiceException({'result': 2, 'description': u'充电插座响应异常,请您稍后再试哦'}) if needTime: finishedTime = int(time.time()) + needTime * 60 devInfo['needTime'] = needTime 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 Device.update_port_control_cache(self._device['devNo'], newValue) devInfo.update({'finishedTime': finishedTime}) devInfo['consumeOrderNo'] = orderNo 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 = {} ctrInfo = Device.get_dev_control_cache(self._device.devNo) for portId, portInfo in devInfo['data']['ports'].items(): portDict = { 'status': self.__translate_status_from_str(str(portInfo['port_status'])), 'power': round(portInfo['watt'], 2), 'leftTime': round(portInfo['left_time'], 2), } lineInfo = ctrInfo.get(portId, {}) if lineInfo.get('status') == 1: if portDict['status'] == 1: lineInfo.update(portDict) if portDict['status'] == 0: ServiceProgress.objects.filter(**{ 'device_imei': self.device['devNo'], 'port': int(portId), 'isFinished': False }).update(isFinished=True, expireAt = datetime.datetime.now()) lineInfo.update(portDict) else: lineInfo['status'] = portDict['status'] result[portId] = lineInfo else: Device.clear_port_control_cache(self._device['devNo'], portId) result[portId] = portDict 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 = self.get_port_status_from_dev() 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_FORBIDDEN, } 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: devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x60, 'port_id': port, 'action': 1}}) else: devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x60, 'port_id': port, 'action': 0}}) self.check_feedback_result(devInfo) 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, 'sub_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, 'sub_id': self._device['devNo']}}) self.check_feedback_result(devInfo) # 子节点的父节点也要更新 devObj = Device.objects.get(devNo=self._device['devNo']) devObj.gatewayNode = '' devObj.save() # 获取设备配置参数 def get_dev_setting(self): devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': {'fun_code': 0x12}}) self.check_feedback_result(devInfo) configs = devInfo['data']['configs'] modeDict = {'0': 'time', '1': 'power', '2': 'elec'} configs['chrmt_mode'] = modeDict.get(str(configs['chrmt_mode'])) online_card_chrmt = str(self.device['otherConf'].get('online_card_chrmt', 1)) configs['online_card_chrmt'] = modeDict.get(online_card_chrmt) configs['online_card_cost'] = self.device['otherConf'].get('online_card_cost', 10) configs['online_card_val'] = self.device['otherConf'].get('online_card_val', 240) configs['refundProtectionTime'] = self.device['otherConf'].get('refundProtectionTime', 5) return configs # 获取设备配置参数 def set_dev_setting(self, setConf): configs = {'fun_code': 0x11} configs['mach_max_watt'] = int(setConf['mach_max_watt']) configs['port_max_watt'] = int(setConf['port_max_watt']) configs['noload_check_watt'] = int(setConf['noload_check_watt']) configs['noload_check_time'] = int(setConf['noload_check_time']) configs['float_charge_watt'] = int(setConf['float_charge_watt']) configs['float_charge_time'] = int(setConf['float_charge_time']) configs['power_lev_max'] = int(setConf['power_lev_max']) configs['power_lv1_watt'] = int(setConf['power_lv1_watt']) configs['power_lv1_time'] = int(setConf['power_lv1_time']) configs['power_lv2_watt'] = int(setConf['power_lv2_watt']) configs['power_lv2_time'] = int(setConf['power_lv2_time']) configs['power_lv3_watt'] = int(setConf['power_lv3_watt']) configs['power_lv3_time'] = int(setConf['power_lv3_time']) configs['once_card_cost'] = int(setConf['once_card_cost']) configs['card_lv1_val'] = int(setConf['card_lv1_val']) configs['card_lev_max'] = int(setConf['card_lev_max']) configs['card_refund_en'] = int(setConf['card_refund_en']) configs['coin_en'] = int(setConf['coin_en']) configs['volume'] = int(setConf['volume']) configs['temp_threshold'] = int(setConf['temp_threshold']) configs['close_for_full'] = int(setConf['close_for_full']) configs['chrmt_mode'] = {'time': 0, 'power': 1, 'elec': 2}.get(setConf['chrmt_mode']) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'data': configs}) self.check_feedback_result(devInfo) billingType = setConf['chrmt_mode'] online_card_chrmt = {'time': 0, 'power': 1, 'elec': 2}.get(setConf['online_card_chrmt']) online_card_cost = int(setConf['online_card_cost']) online_card_val = int(setConf['online_card_val']) refundProtectionTime = int(setConf.get('refundProtectionTime', 5)) Device.get_collection().update_one({'devNo': self.device['devNo']}, {'$set': { 'otherConf.billingType': billingType, 'otherConf.online_card_chrmt': online_card_chrmt, 'otherConf.online_card_cost': online_card_cost, 'otherConf.online_card_val': online_card_val, 'otherConf.refundProtectionTime': refundProtectionTime, }}) Device.invalid_device_cache(self.device.devNo) 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_NO_RESPONSE, {'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(self,request, lastSetConf): print request.POST if request.POST.get('reboot', False) == True: self.reboot_device() def set_device_function_param(self, request, lastSetConf): newConf = copy.deepcopy(request.POST) lastSetConf.update(newConf) self.set_dev_setting(lastSetConf) def isHaveStopEvent(self): return True def stop(self, port=None): return self.stop_charging_port(port) def set_dev_disable(self, disable): """ 设备端锁定解锁设备 :param disable: :return: """ Device.get_collection().update_one({'devNo': self._device['devNo']}, { '$set': {'otherConf.disableDevice': disable}}) Device.invalid_device_cache(self.device.devNo)