# -*- coding: utf-8 -*- from apps.web.core.adapter.base import * from apps.web.device.models import Device from apps.web.user.models import MyUser class ChargingXUEYINGBox(SmartBox): def __init__(self, device): super(ChargingXUEYINGBox, self).__init__(device) def translate_funcode(self, funCode): funCodeDict = { 'A8': u'回复卡余额', 'A7': u'移动支付', 'C1': u'获取设备投币统计', 'C2': u'获取设备刷卡统计', 'B3': u'获取设备端口信息', 'D4': u'获取端口状态', 'C3': u'获取电流标准', 'A4': u'设置电流标准', 'B8': u'获取消费标准配置', 'B7': u'设置消费标准配置', 'B2': u'获取空载关闭时间', 'B1': u'设置线路空载关闭时间', 'D8': u'充满自停标记', 'F4': u'获取设备版本', 'F5': u'回复出厂设置', 'D6': u'清理通道时间', 'D7': u'复位设备', 'D1': u'设置浮充功率', 'E2': u'获取4.5安培的AD功率', 'E1': u'设置4.5安培的AD功率', 'E4': u'查询空载断电功率值', 'E5': u'设置空载断时间值', 'E7': u'获取设备时间', } for k, v in funCodeDict.items(): if k in funCode: return v return '' def translate_event_cmdcode(self, cmdCode): cmdDict = { 'B4': u'上报修改后的消费标准', 'A8': u'刷卡上报', 'C4': u'上报设备状态', 'B5': u'主动上报投币订单结束', 'B6': u'用户刷卡上报的信息结束', 'C8': u'刷网络钱包卡完成上传消费订单', 'C9': u'网络任务完成上传消费订单', } return cmdDict.get(cmdCode, '') def test(self, coins): data = '00 00 00 00 00 00 00 00 00 00 0A 00 00 0A' data = data.replace(' ', '') devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": 'A7', 'data': data}) return devInfo def reply_event_response(self, funCode, port = None, result = True): if port is not None: funCode = fill_2_hexByte(hex(int(port)), 2) + '00' + funCode data = '01' if not result: data = '00' MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'], "funCode": funCode, 'data': data}) def reply_card_balance(self, res, orderNo, balance): data = res data += orderNo data += fill_2_hexByte(hex(int(balance)), 6) MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_NO_RESPONSE, {'IMEI': self._device['devNo'], "funCode": '0101A8', 'data': data}) 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(attachParas['chargeIndex']) hexPort = fill_2_hexByte(hex(port), 2) orderNo = attachParas.get('orderNo') hexOrderNo = fill_2_hexByte(hex(int(orderNo)), 16) coins = float(package['coins']) hexCoins = fill_2_hexByte(hex(int(coins * 100)), 6) needTime = int(package['time']) if 'onPoints' not in attachParas: try: user = MyUser.objects.get(groupId = self._device['groupId'], openId = openId) hexBalance = fill_2_hexByte(hex(int(user.balance * 100)), 6) except Exception, e: logger.info('get user error=%s' % e) raise ServiceException({'result': 2, 'description': u'系统异常,没有查询到用户'}) else: hexBalance = fill_2_hexByte(hex(int(1 * 100)), 6) devInfo = MessageSender.send(self.device, DeviceCmdCode.OPERATE_DEV_SYNC, {'IMEI': self._device['devNo'], "funCode": hexPort + '00' + 'A7', 'data': hexOrderNo + hexCoins + hexBalance}, timeout = MQTT_TIMEOUT.START_DEVICE) 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'充电桩正在忙,无响应,您的金币还在,请试试其他线路,或者请稍后再试哦'}) result = devInfo['data'][10:12] if result == '00': # 成功 raise ServiceException({'result': 2, 'description': u'充电站付款失败,可能是设备忙,或者设备故障'}) start_timestamp = int(time.time()) Device.update_dev_control_cache( self._device['devNo'], { str(port): { 'startTime': timestamp_to_dt(start_timestamp).strftime('%Y-%m-%d %H:%M:%S'), 'status': Const.DEV_WORK_STATUS_WORKING, 'finishedTime': start_timestamp + needTime * 60, 'coins': coins, 'needTime': needTime, 'isStart': True, 'openId': openId, 'refunded': False, 'vCardId': self._vcard_id } }) devInfo['consumeOrderNo'] = orderNo return devInfo def analyze_event_data(self, data): cmdCode = data[6:8] if cmdCode in ['B4']: # 本地修改消费标准时,设备主动上报修改后的消费标准 mobilePrice = int(data[10:14], 16) mobileTime = int(data[14:18], 16) mobileOnsale = int(data[18:20], 16) icPrice = int(data[20:24], 16) icTime = int(data[24:28], 16) coinPrice = int(data[28:32], 16) coinTime = int(data[32:36], 16) return {'cmdCode': cmdCode, 'mobilePrice': mobilePrice, 'mobileTime': mobileTime, 'mobileOnsale': mobileOnsale, 'icPrice': icPrice, 'icTime': icTime, 'coinPrice': coinPrice, 'coinTime': coinTime} elif cmdCode == 'A8': check = int(data[34:36], 16) ^ int(data[36:38], 16) ^ int(data[38:40], 16) ^ int(data[40:42], 16) strCheck = fill_2_hexByte(hex(check), 2) cardNo = data[34:42] + strCheck orderNo = str(data[42:46]) coins = int(data[46:52], 16) return {'cmdCode': cmdCode, 'cardNo': cardNo, 'orderNo': orderNo, 'coins': coins} elif cmdCode == 'C4': # 上报设备状态 port = int(data[2:4], 16) status = int(data[10:12], 16) if status == 1: return {'status': Const.DEV_WORK_STATUS_WORKING, 'cmdCode': cmdCode, 'port': port} elif status == 0: return {'status': Const.DEV_WORK_STATUS_IDLE, 'cmdCode': cmdCode, 'port': port} elif status >= 55: return {'status': Const.DEV_WORK_STATUS_FAULT, 'cmdCode': cmdCode, 'port': port, 'FaultCode': status} elif cmdCode == 'B5': # 主动上报投币订单结束 port = int(data[2:4], 16) orderNo = int(data[10:14], 16) coins = int(data[14:22], 16) duration = int(data[22:30], 16) finishedTime = int(data[30:38], 16) return {'cmdCode': cmdCode, 'port': port, 'orderNo': orderNo, 'coins': coins, 'duration': duration, 'finishedTime': finishedTime} elif cmdCode == 'B6': # 用户刷卡上报的信息结束 port = int(data[2:4], 16) orderNo = int(data[10:14], 16) cardNo = data[14:24] coins = int(data[24:32], 16) balance = int(data[32:40], 16) duration = int(data[40:48], 16) finishedTime = int(data[48:56], 16) return {'cmdCode': cmdCode, 'port': port, 'orderNo': orderNo, 'cardNo': cardNo, 'coins': coins, 'balance': balance, 'duration': duration, 'finishedTime': finishedTime} elif cmdCode == 'C8': # 刷网络钱包卡完成上传消费订单 port = int(data[2:4], 16) check = int(data[34:36], 16) ^ int(data[36:38], 16) ^ int(data[38:40], 16) ^ int(data[40:42], 16) strCheck = fill_2_hexByte(hex(check), 2) cardNo = data[34:42] + strCheck orderNo = str(data[42:46]) coins = int(data[46:52], 16) duration = int(data[52:56], 16) finishedTime = int(data[56:64], 16) return {'cmdCode': cmdCode, 'port': port, 'orderNo': orderNo, 'cardNo': cardNo, 'coins': coins, 'duration': duration, 'finishedTime': finishedTime} elif cmdCode == 'C9': # 网络任务完成上传消费订单 port = int(data[2:4], 16) orderNo = int(data[10:26], 16) orderSequance = int(data[26:30], 16) coins = int(data[30:36], 16) duration = int(data[36:40], 16) finishedTime = int(data[40:48], 16) return {'cmdCode': cmdCode, 'port': port, 'orderNo': orderNo, 'orderSequance': orderSequance, 'coins': coins, 'duration': duration, 'finishedTime': finishedTime} def get_dev_consume_count(self): data = self.get_info_base('C1') coinFee = int(data[12:18], 16) / 10.0 # 以角为单位 data = self.get_info_base('C2') cardFee = int(data[12:18], 16) / 10.0 # 以角为单位 return {'cardFee': cardFee, 'coinFee': coinFee} def get_port_info(self, line): hexPort = fill_2_hexByte(hex(int(line)), 2) devInfo = MessageSender.send(self.device, self.make_random_cmdcode(), {'IMEI': self._device['devNo'], "funCode": hexPort + '00' + 'B3', 'data': '01'}) 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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) result = devInfo['data'][10:12] if result == '00': raise ServiceException({'result': 2, 'description': u'充电桩查询端口失败,请您重试'}) elec = int(devInfo['data'][12:14], 16) return {'port': line, 'elec': elec} # 访问设备,获取设备端口信息 def get_port_status_from_dev(self): devInfo = MessageSender.send(self.device, self.make_random_cmdcode(), {'IMEI': self._device['devNo'], "funCode": '0100D4', 'data': '01'}) 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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) result = devInfo['data'][10:12] if result == '00': raise ServiceException({'result': 2, 'description': u'充电桩查询端口失败,请您重试'}) result = {} portData = devInfo['data'][12:32] ii = 0 while ii < 10: statusTemp = portData[ii * 2:ii * 2 + 2] if statusTemp == '00': status = {'status': Const.DEV_WORK_STATUS_IDLE} elif statusTemp == '01': status = {'status': Const.DEV_WORK_STATUS_WORKING} ii += 1 result[str(ii)] = 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 ctrInfo.has_key(strPort): 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(self, force = False): if force: return self.get_port_status_from_dev() ctrInfo = Device.get_dev_control_cache(self._device['devNo']) if not ctrInfo.has_key('allPorts'): self.get_port_status_from_dev() ctrInfo = Device.get_dev_control_cache(self._device['devNo']) allPorts = 10 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}) return statusDict def get_info_base(self, funCode): devInfo = MessageSender.send(self.device, self.make_random_cmdcode(), {'IMEI': self._device['devNo'], "funCode": '0100' + funCode, 'data': '01'}) 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'充电桩忙,无响应,请您稍候再试。也可能是您的设备版本过低,暂时不支持此功能'}) result = devInfo['data'][10:12] if result == '00': raise ServiceException({'result': 2, 'description': u'充电桩串口通讯失败,请您重试'}) return devInfo['data'] def set_info_base(self, funCode, data): devInfo = MessageSender.send(self.device, self.make_random_cmdcode(), {'IMEI': self._device['devNo'], "funCode": '0100' + funCode, 'data': 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'充电桩忙,无响应,请您稍候再试'}) result = devInfo['data'][10:12] if result == '00': raise ServiceException({'result': 2, 'description': u'充电桩设置失败,请您重试'}) # 获取电流标准 def get_elec_config(self): data = self.get_info_base('C3') standElec = int(data[12:14], 16) # 单位毫安 maxElec = int(data[14:16], 16) # 单位毫安 return {'standElec': standElec, 'maxElec': maxElec} def set_elec_config(self, infoDict): data = fill_2_hexByte(hex(int(infoDict['standElec'])), 2) data += fill_2_hexByte(hex(int(infoDict['maxElec'])), 2) self.set_info_base('A4', data) # 获取消费标准 def get_consume_config(self): data = self.get_info_base('B8') mobilePrice = int(data[12:16], 16) mobileTime = int(data[16:20], 16) mobileOnsale = int(data[20:22], 16) icPrice = int(data[22:26], 16) icTime = int(data[26:30], 16) coinPrice = int(data[30:34], 16) coinTime = int(data[34:38], 16) return {'mobilePrice': mobilePrice, 'mobileTime': mobileTime, 'mobileOnsale': mobileOnsale, 'icPrice': icPrice, 'icTime': icTime, 'coinPrice': coinPrice, 'coinTime': coinTime} def set_consume_config(self, infoDict): data = fill_2_hexByte(hex(int(infoDict['mobilePrice'])), 4) data += fill_2_hexByte(hex(int(infoDict['mobileTime'])), 4) data += fill_2_hexByte(hex(int(infoDict['mobileOnsale'])), 2) data += fill_2_hexByte(hex(int(infoDict['icPrice'])), 4) data += fill_2_hexByte(hex(int(infoDict['icTime'])), 4) data += fill_2_hexByte(hex(int(infoDict['coinPrice'])), 4) data += fill_2_hexByte(hex(int(infoDict['coinTime'])), 4) self.set_info_base('B7', data) # 获取设备断电时长 def get_line_poweroff_time(self): data = self.get_info_base('B2') return {'poweroffTime': int(data[12:20], 16)} # 设置设备断电时长 def set_line_poweroff_time(self, infoDict): data = fill_2_hexByte(hex(int(infoDict['poweroffTime'])), 8) self.set_info_base('B1', data) # 下发断电自停标记 def set_fullstop(self, setConf): data = fill_2_hexByte(hex(int(setConf['fullstop'])), 2) self.set_info_base('D8', data) def get_dev_version(self): data = self.get_info_base('F4') return {'version': str(data[12:28])} # 恢复出厂设置 def recover_factory_set(self): self.set_info_base('F5', '01') # 清除通道时间 def clear_line_time(self): self.set_info_base('D6', '01') # 复位设备 def reboot_dev(self): self.set_info_base('D7', '01') # 查询浮充功率 def get_fuchong_power(self): data = self.get_info_base('D2') return {'fuchongPower': int(data[12:16], 16)} # 下发浮充功率 def set_fuchong_power(self, setConf): data = fill_2_hexByte(hex(int(setConf['fuchongPower'])), 4) self.set_info_base('D1', data) # 查询4.5A AD功率 def get_45AD_power(self): data = self.get_info_base('E2') return {'power45': int(data[12:16], 16)} # 下发浮充功率 def set_45AD_power(self, setConf): data = fill_2_hexByte(hex(int(setConf['power45'])), 4) self.set_info_base('E1', data) # 查询空载断电功率值 def get_emptyoff_power(self): data = self.get_info_base('E4') return {'emptyPower': int(data[12:16], 16)} # 设置空载断电功率值 def set_emptyoff_power(self, setConf): data = fill_2_hexByte(hex(int(setConf['emptyPower'])), 4) self.set_info_base('E3', data) # 查询空载断电时间值 def get_emptyoff_time(self): data = self.get_info_base('E6') return {'emptyTime': int(data[12:16], 16)} # 设置空载断电时间值 def set_emptyoff_time(self, setConf): data = fill_2_hexByte(hex(int(setConf['emptyTime'])), 4) self.set_info_base('E5', data) def get_dev_time(self): data = self.get_info_base('E7') year = '20' + str(int(data[12:14], 16)) month = str(int(data[14:16], 16)) day = str(int(data[16:18], 16)) hour = str(int(data[18:20], 16)) minute = str(int(data[20:22], 16)) second = str(int(data[22:24], 16)) return {'devTime': '%s-%s-%s %s:%s:%s' % (year, month, day, hour, minute, second)} def get_device_function_by_key(self, keyName): resultDict = {} if 'power45' in keyName: resultDict.update(self.get_45AD_power()) if ('mobilePrice' in keyName) or ('mobileTime' in keyName) \ or ('mobileOnsale' in keyName) or ('icPrice' in keyName) \ or ('icTime' in keyName) or ('coinPrice' in keyName) \ or ('coinTime' in keyName): resultDict.update(self.get_consume_config()) if 'standElec' in keyName or 'maxElec' in keyName: resultDict.update(self.get_elec_config()) if 'emptyPower' in keyName: resultDict.update(self.get_emptyoff_power()) if 'emptyTime' in keyName: resultDict.update(self.get_emptyoff_time()) if 'fuchongPower' in keyName: resultDict.update(self.get_fuchong_power()) if 'poweroffTime' in keyName: resultDict.update(self.get_line_poweroff_time()) if 'version' in keyName: resultDict.update(self.get_dev_version()) return resultDict def get_dev_setting(self): resultDict = self.get_45AD_power() tempDict = self.get_consume_config() resultDict.update(tempDict) tempDict = self.get_dev_consume_count() resultDict.update(tempDict) tempDict = self.get_elec_config() resultDict.update(tempDict) tempDict = self.get_emptyoff_power() resultDict.update(tempDict) tempDict = self.get_emptyoff_time() resultDict.update(tempDict) tempDict = self.get_fuchong_power() resultDict.update(tempDict) tempDict = self.get_line_poweroff_time() resultDict.update(tempDict) tempDict = self.get_dev_version() resultDict.update(tempDict) return resultDict def set_coin_card_enable(self, infoDict): pass def set_IC_coin_power_config(self, infoDict): pass def set_fullstop_cardrefund(self, infoDict): pass def set_gear_conf(self, infoDict): pass def set_dev_setting(self, setConf): keys = setConf.keys() if 'putCoins' in keys or 'icCard' in keys: self.set_coin_card_enable(setConf) if 'maxPower' in keys or 'icMoney' in keys or 'time1' in keys or 'time2' in keys or 'time3' in keys: self.set_IC_coin_power_config(setConf) def set_device_function(self, request, lastSetConf): if request.POST.has_key('recover'): # recover = True if request.POST.get('recover') == 'true' else False recover = request.POST.get("recover", False) if recover: self.recover_factory_set() if request.POST.has_key('clearLineTime'): # clearLineTime = True if request.POST.get('clearLineTime') == 'true' else False clearLineTime = request.POST.get("clearLineTime", False) if clearLineTime: self.clear_line_time() if request.POST.has_key('reboot'): # reboot = True if request.POST.get('reboot') == 'true' else False reboot = request.POST.get("reboot", False) if reboot: self.reboot_dev() if request.POST.has_key('cardRefund'): # cardRefund = True if request.POST.get('cardRefund') == 'true' else False cardRefund = request.POST.get("cardRefund", False) lastSetConf.update({'cardRefund': cardRefund}) self.set_fullstop_cardrefund(lastSetConf) def set_device_function_param(self, request, lastSetConf): if request.POST.has_key('maxPower') and request.POST.has_key('icMoney'): lastSetConf.update({'maxPower': int(request.POST.get('maxPower', 0))}) lastSetConf.update({'icMoney': int(request.POST.get('icMoney', 0))}) self.set_IC_coin_power_config(lastSetConf) if request.POST.has_key('time1') and request.POST.has_key('time2') and request.POST.has_key('time3'): lastSetConf.update({'time1': int(request.POST.get('time1', 0))}) lastSetConf.update({'time2': int(request.POST.get('time2', 0))}) lastSetConf.update({'time3': int(request.POST.get('time3', 0))}) self.set_IC_coin_power_config(lastSetConf) if request.POST.has_key('power1') and request.POST.has_key('power1ratio'): lastSetConf.update({'power1': int(request.POST.get('power1', 0))}) lastSetConf.update({'power1ratio': int(request.POST.get('power1ratio', 0))}) lastSetConf.update({'power2': int(request.POST.get('power2', 0))}) lastSetConf.update({'power2ratio': int(request.POST.get('power2ratio', 0))}) lastSetConf.update({'power3': int(request.POST.get('power3', 0))}) lastSetConf.update({'power3ratio': int(request.POST.get('power3ratio', 0))}) self.set_gear_conf(lastSetConf) if request.POST.has_key('mobilePrice') and request.POST.has_key('mobileTime') and request.POST.has_key( 'mobileOnsale'): lastSetConf.update({'mobilePrice': int(request.POST.get('mobilePrice', 0))}) lastSetConf.update({'mobileTime': int(request.POST.get('mobileTime', 0))}) lastSetConf.update({'mobileOnsale': int(request.POST.get('mobileOnsale', 0))}) self.set_consume_config(lastSetConf)