def init_rsu(self): """ 初始化rsu, 初始化耗时大约1s :return: """ # 天线开关开启 self.rsu_on_or_off = StatusFlagConfig.RSU_ON # if 'socket_client' in dir(self): # del self.socket_client # 创建一个客户端的socket对象 self.socket_client = socket.socket(socket.AF_INET, socket.SOCK_STREAM) # 连接服务端 self.socket_client.connect( (self.rsu_conf['ip'], self.rsu_conf['port'])) logger.info( '=============================天线初始化=============================') # 设置连接超时 # self.socket_client.settimeout(CommonConf.ETC_CONF_DICT['socket_connect_time_out']) # 天线功率, 十进制转16进制 tx_power = hex(self.rsu_conf['tx_power'])[2:] if len(tx_power) == 1: tx_power = '0' + tx_power # 发送c0初始化指令,以二进制的形式发送数据,所以需要进行编码 c0 = CommandSendSet.combine_c0( lane_mode=self.rsu_conf['lane_mode'], wait_time=self.rsu_conf['wait_time'], tx_power=tx_power, pll_channel_id=self.rsu_conf['pll_channel_id'], trans_mode=self.rsu_conf['trans_mode']).strip() logger.info('发送c0初始化指令: %s' % (c0, )) self.socket_client.send(bytes.fromhex(c0)) # 接收数据 msg_bytes = self.socket_client.recv(1024) msg_str = CommonUtil.transfer_recv_command(msg_bytes.hex()) # 字节转十六进制 logger.info('接收数据: {}'.format(repr(msg_str))) # b0 天线设备状态信息帧 if msg_str[6:8] == 'b0': self.command_recv_set.parse_b0(msg_str) # 解析b0指令 if self.command_recv_set.info_b0['RSUStatus'] == '00': self.rsu_status = StatusFlagConfig.RSU_NORMAL self.rsu_heartbeat_time = datetime.datetime.now() else: self.rsu_status = StatusFlagConfig.RSU_FAILURE elif msg_str == '' and self.recreate_socket_count < 2: # 可能由于上次没有正常关闭,导致mst_st为空 self.recreate_socket_count += 1 self.close_socket() logger.info('==============再试一次初始化天线==============') # 再试一次初始化天线 self.init_rsu() else: self.recreate_socket_count = 0
def recv_msg_max_wait_time(self): # 接收数据 msg_bytes_hex = self.socket_client.recv(1024).hex() msg_str = CommonUtil.transfer_recv_command(msg_bytes_hex) return msg_str
def fee_deduction(self, obu_body: ETCRequestInfoOrm): """ etc扣费, 正常扣费指令流程, 耗时大约700ms c0->b0->b2->c1->b3->c1->b4->c6->b5,其中 c0: 发送初始化指令 --> init_rsu()中已经初始化 b0: 接收设备状态信息帧 --> nit_rsu()中已经初始化 b2: 接收电子标签信息帧 c1: 发送继续交易指令 b3: 接收设备车辆信息帧 c1: 发送继续交易指令 b4: 接收速通卡信息帧 c6: 发送消费交易指令,出口消费写过站 b5: 接收交易信息帧,表示此次交易成功结束 :return: """ current_time = time.time() logger.info( '==========================================开始扣费==========================================' ) logger.info('订单号:{}, 车牌号:{}, 车牌颜色:{}'.format( obu_body.trans_order_no, obu_body.plate_no, obu_body.plate_color_code)) # self.etc_charge_flag=True表示交易成功,self.etc_charge_flag=False表示交易失败 self.etc_charge_flag = False obuid = None result = dict(flag=False, data=None, error_msg=None) # 统计扣费期间b2的数量,有时会遇到b2->c1-b2->c1->b2->c1这样的无限循环 count_b2 = 0 # 设置超时时间 while True: # 接收数据 try: msg_bytes = self.recv_msg() except: logger.error('搜索obu超时') result['error_msg'] = '没有搜索到obu' return result # 指令转义 msg_str = CommonUtil.transfer_recv_command( msg_bytes.hex()) # 字节转十六进制 logger.info('接收数据: {}'.format(repr(msg_str))) # b2 电子标签信息帧 if msg_str[6:8] == 'b2': if msg_str[8:16] == 'ffffffff': # 'ffffffff' 表示心跳 logger.info('心跳') elif msg_str[68:72] == '2001': info_b2 = self.command_recv_set.parse_b2(msg_str) # 解析b2指令 # 过期日期 data_of_expire = self.command_recv_set.info_b2[ 'DataOfExpire'] # 当前日期 data_of_now = CommonUtil.timestamp_format( int(time.time()), '%Y%m%d') if data_of_now > data_of_expire: result['error_msg'] = '过期日期:{}'.format(data_of_expire) return result # 电子标签mac地址 obuid = info_b2['OBUID'] # 获取c1指令 c1 = CommandSendSet.combine_c1( obuid, obu_div_factor=self.rsu_conf['obu_div_factor']) logger.info('b2后发送c1指令:%s' % (c1)) self.socket_client.send(bytes.fromhex(c1)) count_b2 += 1 if count_b2 > 3: result['error_msg'] = '无法扣费,陷入b2->c1-b2->c1->b2->c1循环' return result else: result['error_msg'] = 'obu卡有问题,obu状态码: {}'.format( msg_str[68:72]) return result # b3 车辆信息帧 elif msg_str[6:8] == 'b3': if msg_str[16:18] == '00': # obu信息帧状态执行码,取值00正常 self.command_recv_set.parse_b3(msg_str) # 解析b3指令 # TODO 车牌号,车颜色 需要校验, 不匹配需要返回 plate_no = self.command_recv_set.info_b3[ 'VehicleLicencePlateNumber'] try: plate_no = CommonUtil.parse_plate_code( plate_no).replace('测A', '鲁L') except: logger.error(traceback.format_exc()) logger.error('车牌号解析错误:{}'.format(repr(plate_no))) # 车牌颜色 obu_plate_color = str( int( self.command_recv_set. info_b3['VehicleLicencePlateColor'], 16)) # obu车颜色 if (obu_body.plate_no != plate_no): error_msg = '车牌号不匹配,监控获取的车牌号:{},obu获取的车牌号:{}'.format( obu_body.plate_no, plate_no) result['error_msg'] = error_msg return result elif int( obu_body.plate_color_code) != int(obu_plate_color): error_msg = "车牌号或车颜色不匹配: 监控获取的车牌号:%s, 车颜色:%s; obu获取的车牌号:%s,车颜色:%s" % ( obu_body.plate_no, obu_body.plate_color_code, plate_no, obu_plate_color) logger.error(error_msg) # todo 颜色不对,继续扣费 if obuid is None: # 如果没有获取到obuid,继续 logger.error( 'obuid is none =====================+++++++++++++++++++' ) continue # 再次获取c1指令并发送 c1 = CommandSendSet.combine_c1( obuid, obu_div_factor=self.rsu_conf['obu_div_factor']) logger.info('b3后发送c1指令:%s' % (c1, )) self.socket_client.send(bytes.fromhex(c1)) else: # 状态执行码不正常,发送c2指令,终止交易 c2 = CommandSendSet.combine_c2(obuid, stop_type='01') # logger.info('发送c2指令,终止交易: %s' % (c2,)) self.socket_client.send(bytes.fromhex(c2)) result['error_msg'] = '终止交易' return result # b4 速通卡信息帧 elif msg_str[6:8] == 'b4': if msg_str[16:18] == '00': # 状态执行码,00说明后续速通卡信息合法有效 logger.info('接收b4指令: {}'.format(msg_str)) self.command_recv_set.parse_b4(msg_str) # 解析b4指令 logger.info('b4解析后:{}'.format( json.dumps(self.command_recv_set.info_b4, ensure_ascii=False))) # 获取并发送c6消费交易指令 if CommonConf.ETC_CONF_DICT['debug'] == 'true': deduct_amount = CommonUtil.etcfee_to_hex(0.01) else: deduct_amount = CommonUtil.etcfee_to_hex( obu_body.deduct_amount) # 扣款额,高字节在前 purchase_time = CommonUtil.timestamp_format( int(time.time())) station = msg_str[132:212] # 过站信息,40个字节 c6 = CommandSendSet.combine_c6( obuid, card_div_factor=self.rsu_conf['obu_div_factor'], reserved='00000000', deduct_amount=deduct_amount, purchase_time=purchase_time, station=station) # 针对红门轮训模式 if CommonUtil.deduct_stop(obu_body.create_time): error_msg = '时间超时,终止etc交易' logger.info(error_msg) result['error_msg'] = error_msg return result logger.info('b4后发送c6指令,消费交易,出口消费写过站: {}, 其中扣除费用{}'.format( c6, obu_body.deduct_amount)) self.socket_client.send(bytes.fromhex(c6)) else: result['error_msg'] = 'b4指令有问题' return result # b5 交易信息帧,表示此次交易成功结束 elif msg_str[6:8] == 'b5': if msg_str[16:18] == '00': # 状态执行码,00说明正常 self.command_recv_set.parse_b5(msg_str) # 解析b5指令 # 获取并发送c1继续交易指令 c1 = CommandSendSet.combine_c1( obuid, obu_div_factor=self.rsu_conf['obu_div_factor']) logger.info('b5后发送c1指令:%s, 电子标签mac地址 obuid = %s' % (c1, obuid)) self.socket_client.send(bytes.fromhex(c1)) self.etc_charge_flag = True result['flag'] = True result['data'] = self.command_recv_set return result else: result['error_msg'] = 'b5指令有问题' return result elif not msg_str: result['error_msg'] = '接收到的指令为空' return result elif not msg_str.startswith('ffff'): logger.info('忽略指令: {}'.format(msg_str)) else: logger.error('未能解析的指令:%s' % (msg_str))