# -*- coding: utf-8 -*- # !/usr/bin/env python import logging import time from typing import TYPE_CHECKING from apilib.utils_string import split_str from apps.web.constant import DeviceCmdCode, MQTT_TIMEOUT, Const 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.device.models import Device if TYPE_CHECKING: pass logger = logging.getLogger(__name__) class ChargingZhongChuangCarBox(SmartBox): DATA_OFFSET = 8 ARRAY_INDEX_INCR = 10 def __init__(self, device): super(ChargingZhongChuangCarBox, self).__init__(device) def translate_funcode(self,funCode): funCodeDict = { '03':u'从设备读数据', '06':u'向设备写数据', } return funCodeDict.get(funCode,'') def __read__(self, offset, size): request_data = fill_2_hexByte(hex(int(offset)), 4) request_data += (fill_2_hexByte(hex(int(size)), 4)) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": '03', 'data': request_data}) 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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) return devInfo['data'][ChargingZhongChuangCarBox.DATA_OFFSET:] def __write__(self, offset, value,timeout = MQTT_TIMEOUT.NORMAL,orderNo=None): request_data = fill_2_hexByte(hex(int(offset)), 4) request_data += fill_2_hexByte(hex(int(value)), 4) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], 'funCode': '06', 'data': request_data}, timeout = timeout) 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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) if devInfo['data'][:-4] != ('0106' + request_data): raise ServiceException({'result': 2, 'description': u'写入充电桩数据错误'}) return devInfo def get_port_info(self, line): return self.get_port_status().get(line) @staticmethod def __parse_port_status(response_data): def translate_status(status): if status in [0,1]: return Const.DEV_WORK_STATUS_IDLE elif status in [2]: return Const.DEV_WORK_STATUS_CONNECTED elif status in [3]: return Const.DEV_WORK_STATUS_WORKING elif status in [5,6,7,8]: return Const.DEV_WORK_STATUS_FAULT else: return Const.DEV_WORK_STATUS_FINISHED if len(response_data) < 80:#现网日志报错,有异常报文上报 return {} descDict = { '0':u'空闲', '1':u'空闲', '2':u'枪已经连接', '3':u'正在充电', '4':u'充电完成', '5':u'电压偏高', '6':u'漏电保护', '7':u'电压偏低', '8':u'紧急停止' } result = split_str(response_data, lens="4"*21) devStatus = dict() # 定义多路之间数组下标增量 portNum = int(result[0], 16) for port in xrange(portNum): portStr = str(port+1) devStatus[portStr] = { "power": int(result[1+port*ChargingZhongChuangCarBox.ARRAY_INDEX_INCR], 16), "voltage": int(result[2+port*ChargingZhongChuangCarBox.ARRAY_INDEX_INCR], 16), "elec": int(result[3+port*ChargingZhongChuangCarBox.ARRAY_INDEX_INCR], 16) / 1000.0, "orgStatus": int(result[4+port*ChargingZhongChuangCarBox.ARRAY_INDEX_INCR], 16), "balance": int(result[5+port*ChargingZhongChuangCarBox.ARRAY_INDEX_INCR], 16) / 10.0, "duration": int(result[6+port*ChargingZhongChuangCarBox.ARRAY_INDEX_INCR], 16), "status": translate_status(int(result[4+port*ChargingZhongChuangCarBox.ARRAY_INDEX_INCR], 16)), "desc": descDict.get(str(int(result[4+port*ChargingZhongChuangCarBox.ARRAY_INDEX_INCR]))) } return devStatus def get_port_status(self, force=False): # 缓存中会有初始下发的金币信息 devStatus = self.__parse_port_status(self.__read__(0, 21)) # TODO 连接状态不要影响支付 这个地方暂时简单修改 后续需要将这个去掉 然后前台的状态为 连接状态的时候可以进行支付 for value in devStatus.values(): if isinstance(value, dict) and "status" in value and value["status"] == Const.DEV_WORK_STATUS_CONNECTED: value["status"] = Const.DEV_WORK_STATUS_IDLE Device.update_dev_control_cache(self._device["devNo"], devStatus) devCache = Device.get_dev_control_cache(self._device["devNo"]) return devCache def start_device(self, package, openId, attachParas): price = int(package['price'] * 10) if price < 1: raise ServiceException({'result': 2, 'description': u'请输入正确的支付费用'}) port = attachParas['chargeIndex'] logger.debug('charge index = %s; price = %s' % (port, price)) offset = 10 + (int(port) - 1) * self.ARRAY_INDEX_INCR orderNo = attachParas.get('orderNo') devInfo = self.__write__(offset, price, timeout = MQTT_TIMEOUT.START_DEVICE, orderNo = orderNo) cacheValue = Device.get_dev_control_cache(self._device['devNo']) if not cacheValue: return rechargeRcdId = attachParas.get("linkedRechargeRecordId") cacheValue.update({ str(port): { 'openId': openId, "coins": package['coins'], "price": package['price'], "rechargeRcdId": str(rechargeRcdId) if rechargeRcdId else None, "vCardId": self._vcard_id, 'isStart': True, 'status': Const.DEV_WORK_STATUS_WORKING, 'finishedTime': int(time.time()) + 24 * 60 * 60 } }) Device.update_dev_control_cache(self._device['devNo'], cacheValue) return devInfo def get_port_status_from_dev(self): status = self.get_port_status() allPorts,usedPorts = len(status),0 for portInfo in status.values(): count = 0 if portInfo['status'] in [Const.DEV_WORK_STATUS_IDLE,Const.DEV_WORK_STATUS_FINISHED] else 1 usedPorts += count status.update({'allPorts':allPorts,'usedPorts':usedPorts,'usePorts':allPorts - len(usedPorts)}) Device.update_dev_control_cache(self._device['devNo'], status) return status def analyze_event_data(self, data): return self.__parse_port_status(data[ChargingZhongChuangCarBox.DATA_OFFSET:]) def reply_left_balance(self,port,balance=0): offset = 5 + (int(port) - 1) * self.ARRAY_INDEX_INCR self.__write__(offset, int(balance), timeout=120)