# coding=utf-8 from apps.web.core.adapter.base import * import simplejson as json class QiangLongBox(SmartBox): PORT_NUMBER_KEY = "CZ" CARD_NUMBER_KEY = "KH" CARD_BALANCE = "YE" DEFAULT_CARD_CST = 1 DEFAULT_CARD_TIME = 3 def _send_data(self, funCode, data=None, cmd=None, timeout=None): if data is None: data = "" if cmd is None: cmd = DeviceCmdCode.OPERATE_DEV_SYNC if timeout is None: timeout = MQTT_TIMEOUT.NORMAL result = MessageSender.send(device = self.device, cmd = cmd, payload = { "IMEI": self._device["devNo"], "funCode": funCode, "data": data }, timeout = timeout) if "rst" in result and result.get("rst") != 0: if result.get("rst") == -1: raise ServiceException({"result": 2, "description": u"网络故障,请重新试试"}) if result.get("rst") == 1: raise ServiceException({"result": 2, "description": u"充电桩无响应,请稍后再试试"}) return result @staticmethod def _parse_one_port_data(data): data0 = data[0:2] data1 = data[2:4] data2 = data[4:6] data3 = data[6:8] data0Bit = "{:0>8}".format(bin(int(data0, 16)).replace("0b", "")) data0PartOne = data0Bit[:2] data0PartTwo = data0Bit[2:] status = int(data0PartOne) power = int(data0PartTwo, 2) * 100 + int(data1, 16) elec = int(data2, 16) + int(data3, 16) * 0.01 return { "status": status, "power": power, "elec": elec } @staticmethod def _parse_event_C0(data): portStr = str(int(data[6:8], 16)) return { "portStr": portStr } @staticmethod def _parse_event_EE(data): # 尾部会有00 终止符 asciiData = data[6: -4] jsonData = binascii.unhexlify(asciiData) dictData = json.loads(jsonData.strip(b'\x00'.decode())) portStr = dictData.get(QiangLongBox.PORT_NUMBER_KEY, 0) cardNo = dictData.get(QiangLongBox.CARD_NUMBER_KEY, "") return { "portStr": portStr, "cardNo": cardNo } def _query_all_port_status(self): result = self._send_data("D0") data = result.get("data", "")[8:-4] portNum = int(result.get("data", "")[6:8] or "0", 16) portInfo = dict() for i in range(portNum): portStr = str(int(data[:2], 16)) portInfo[portStr] = QiangLongBox._parse_one_port_data(data[2:10]) data = data[10:] print portStr, portInfo[portStr] return portInfo def _query_port_status(self, port): portHex = fill_2_hexByte(hex(int(port)), 2) result = self._send_data("D1", portHex) data = result.get("data", "")[6:-4] return QiangLongBox._parse_one_port_data(data) def _start(self, port, _time): statusHex = "01" timeHex = fill_2_hexByte(hex(int(_time)), 4) portHex = fill_2_hexByte(hex(int(port)), 2) return self._send_data("D2", portHex+statusHex+timeHex, timeout = MQTT_TIMEOUT.START_DEVICE) def _stop(self, port): statusHex = "00" timeHex = "0000" portHex = fill_2_hexByte(hex(int(port)), 2) return self._send_data("D2", portHex+statusHex+timeHex) def _response_card(self, portStr, balance, msg): data = { "Z": "P", "ADDR": "1", } data.update({ QiangLongBox.PORT_NUMBER_KEY: str(portStr), QiangLongBox.CARD_BALANCE: str(balance), "msg": str(msg), "ZL": str(msg) == "255" and "1" or "255" }) data = binascii.hexlify(json.dumps(data, separators=(",", ":"))).upper() self._send_data("EF", data, cmd=DeviceCmdCode.OPERATE_DEV_NO_RESPONSE) def get_port_status_from_dev(self): portInfo = self._query_all_port_status() portDict = dict() for portStr, info in portInfo.items(): tempStatus = info.get("status", Const.DEV_WORK_STATUS_IDLE) portDict[portStr] = {"status": tempStatus} # 更新可用端口数量 allPorts, usedPorts, usePorts = self.get_port_static_info(portDict) Device.update_dev_control_cache( self._device["devNo"], { "allPorts": allPorts, "usedPorts": usedPorts, "usePorts": usePorts } ) # 更新端口状态 devCache = Device.get_dev_control_cache(self._device["devNo"]) for port, info in portDict.items(): if port in devCache and isinstance(info, dict): devCache[port].update({"status": info["status"]}) else: devCache[port] = info Device.update_dev_control_cache(self._device["devNo"], devCache) return portDict def get_port_status(self, force=False): if force: return self.get_port_status_from_dev() devCache = Device.get_dev_control_cache(self._device["devNo"]) if "allPorts" not in devCache: self.get_port_status_from_dev() devCache = Device.get_dev_control_cache(self._device["devNo"]) allPorts = devCache.get("allPorts") if allPorts is None: raise ServiceException({'result': 2, 'description': u'充电端口信息获取失败'}) statusDict = dict() for portNum in xrange(allPorts): portStr = str(portNum + 1) tempDict = devCache.get(portStr, {}) if "status" in tempDict: statusDict[portStr] = {"status": tempDict["status"]} elif "isStart" in tempDict: if tempDict["isStart"]: statusDict[portStr] = {"status": Const.DEV_WORK_STATUS_WORKING} else: statusDict[portStr] = {"status": Const.DEV_WORK_STATUS_IDLE} else: statusDict[portStr] = {"status": Const.DEV_WORK_STATUS_IDLE} allPorts, usedPorts, usePorts = self.get_port_static_info(statusDict) portsDict = {"allPorts": allPorts, "usedPorts": usedPorts, "usePorts": usePorts} Device.update_dev_control_cache(self._device["devNo"], portsDict) # 返还的是要显示的端口数量 return statusDict def start_device(self, package, openId, attachParas): chargeIndex = attachParas.get("chargeIndex") _time = package.get("time", 0) coins = package.get("coins") result = self._start(port=chargeIndex, _time=_time) result["finishedTime"] = int(time.time()) + _time * 60 portCache = { "status": Const.DEV_WORK_STATUS_WORKING, "coins": coins, "startTime": datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S"), "openId": openId, "isStart": True, "needTime": _time, "startTimeStamp": int(time.time()) } Device.update_dev_control_cache(self.device.devNo, {chargeIndex: portCache}) return result def analyze_event_data(self, data): cmdCode = data[4:6] funcName = "_parse_event_{}".format(cmdCode.upper()) func = getattr(QiangLongBox, funcName) if not func: return eventData = func(data) eventData.update({"cmdCode": cmdCode}) return eventData def get_dev_setting(self): otherConf = self.device.get("otherConf", dict()) cardCst = otherConf.get("cardCst", QiangLongBox.DEFAULT_CARD_CST) cardTime = otherConf.get("cardTime", QiangLongBox.DEFAULT_CARD_TIME) return { "cardCst": cardCst, "cardTime": cardTime } def set_device_function_param(self, request, lastSetConf): cardCst = request.POST.get("cardCst") cardTime = request.POST.get("cardTime") if not all([cardCst, cardTime]): raise ServiceException({"result": "2", "description": u"参数不全"}) otherConf = self.device.get("otherConf", dict()) otherConf.update( { "cardCst": cardCst, "cardTime": cardTime } ) Device.objects.filter(devNo=self.device.devNo).update(otherConf=otherConf) Device.invalid_device_cache(self.device.devNo) def active_deactive_port(self, port, active): if not active: self._stop(port) else: raise ServiceException({'result': 2, 'description': u'此设备不支持直接打开端口'})