示例#1
0
    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
示例#2
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
示例#3
0
    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))