目录[-]

目录:

  1. 引言:连接车辆与云端的桥梁
  2. T-Box:远程信息处理器
    1. 什么是 T-Box?
    2. 核心功能
    3. 硬件构成
      1. 主控芯片
      2. 蜂窝通信模组
      3. C-V2X模组
      4. GNSS模块
      5. CAN控制器
    4. 软件架构简述
      1. 嵌入式os
      2. 通信协议栈
      3. 安全模块
    5. T-Box 安装位置
  3. TSP:远程服务提供商
    1. HTTP API 接口测试
    2. MQTT 接口测试
    3. 油车、电车的网联功能对比
    4. 电车哪些核心功能驱动了MQTT的应用?
    5. 什么时候建立 MQTT 连接?
  4. 业务逻辑测试(名词解释)
    1. 幂等性
    2. 车辆状态
    3. 安全行车逻辑
    4. 数据一致性
  5. 分布式系统故障排查
  6. 幂等性、业务校验、频率控制
  7. 车载网络对比
  8. 使用Python语言模拟MQTT协议的订阅者、发布者

————————————————————————————————

1.引言:连接车辆与云端的桥梁

 

本文解释智能网联汽车的“汽车中枢”T-Box与“云端大脑”TSP,重点在于测试工程师关心的测试方法与用例设计。

————

2.T-Box:远程信息处理器

 

2.1 什么是T-Box?

T-Box,Telematics Box:远程信息处理器,它是连接汽车内部网络与外部互联网的关键部件,负责车辆的远程通信和数据处理,是实现汽车联网的核心硬件。

通俗点理解,可以将它想象成公司前台,它负责接收外部的电话和访客,将信息翻译成各部门听得懂的语言,传递过去,并接收到各部门的反馈,将信息翻译成访客需要的内容,返回给访客。

————

2.2 核心功能

T-Box的核心功能是让汽车“上网”,并基于此实现一系列智能化服务。

  • 远程控制:用户通过手机APP远程控制车辆,如 解锁/打开后备箱/启动发动机等。
  • 数据采集:T-Box 持续从车辆内部的CAN总线等网络收集数据,如车速、油耗、电池电量、发动机状态、故障码等。
  • FOTA:全称 Firmware Over-The-Air,固件空中升级,它允许汽车制造商通过移动网络,远程为车辆的各个ECU(电子控制单元)下载和安装新的软件或固件,修复漏洞、增加新功能,车主不需要去4s店升级。常见的称呼就是OTA。
  • 定位:实时获取并上报车辆的地理位置信息,用于车辆追踪、导航、电子围栏等功能。

————

2.3 硬件构成

T-Box是一个复杂的嵌入式系统,硬件通常包含以下几个核心模块:

  • 主控芯片:T-Box的“大脑”,与计算机的CPU高度相似
    1. 核心计算单元:负责执行 T-Box 操作系统和应用程序的代码,处理来自蜂窝网络、GNSS、CAN总线等各模块的数据。
    2. 系统调度中心:负责任务调度、资源分配和管理内存,确保各任务顺利、高效运行。
    3. 控制中枢:向其他硬件模块发出指令,并协调它们之间的工作,例如:需要定位时,调用GNSS模块;需要联网时,调用蜂窝通信模组。
  • 蜂窝通信模组:T-Box的“移动网络模块”,连接到运营商,如中国移动、电信的4G/5G移动网络,实现与云端服务器的数据交换。
  • C-V2X模组:Cellular Vehicle-to-Everything,“基于蜂窝网络的车联万物”技术,它让车辆能够与周围环境进行通信,包括:
    1. V2V:车与车
    2. V2I:车与道路基础设施(如交通信号灯)
    3. V2P:车与行人
    4. V2N:车与网络
  • GNSS模块:全称 Global Navigation Satellite System,“全球导航卫星系统”,它通过接受GPS(美国)、北斗(中国)、GLONASS(俄罗斯)、Galileo(欧盟)等卫星信号,精准计算车辆的实时位置、速度和方向。
  • CAN控制器:CAN控制器是连接T-Box与车辆CAN网络进行通信的接口芯片,其功能类似于我们测试时使用的Vector CAN卡,但它是嵌入在T-Box内部的。

————

2.4 软件架构简述:

硬件需要软件驱动,T-Box的软件系统同样复杂。

  • 嵌入式OS:嵌入式操作系统,把它理解为计算机的操作系统,它负责管理硬件资源(CPU、内存)、提供基础服务、为上层应用程序提供运行环境。
  • 通信协议栈:实现网络通信的软件协议集合。例如:数据传输的TCP/IP协议栈,应用层协议(MQTT、HTTP),确保T-Box与云端能够通信。
  • 安全模块
    • 数据加密/解密:保证传输数据不被窃取
    • 身份认证:确保与T-Box通信的云端服务器是合法的,防止“伪基站”攻击
    • 安全启动:确保T-Box启动时加载的软件是官方版本
    • HSM:硬件安全模块,为加解密等操作提供物理级别的安全保障

转自:https://www.bilibili.com/opus/643674134416457760

————

2.5 T-Box 安装位置:

不同厂家的设计不同,这就导致了 T-Box 硬件安装位置不统一,具体的位置有:

  1. 仪表盘后
  2. 油门踏板旁
  3. 主/副驾驶座下
  4. 中控内

由于厂家众多、车型众多,而且 T-Box 硬件的位置并不是车主关心的地方,官方也没有明确说明,所以,并不能用百分比的形式来说明,都有多少占比的汽车采用哪种安装位置,具体要看厂家的设计。

————

3.TSP:远程服务提供商

 

TSP,Telematics Service Provider,它是一个位于云端的服务平台,作为连接“用户终端”与“车辆”之间的桥梁。所有从手机APP、网站等发往车辆的指令、从车辆上传的数据,都需要经过 TSP 平台进行处理、转发和逻辑判断,没有 TSP ,远程控制、车辆状态查询等功能无法实现。

TSP 和手机端交互,需要遵循一套预定好的规则和协议,APP 向 TSP 发出一个请求,TSP 将报文解析处理后,发送给 T-Box,T-Box 通过CAN 网络与汽车交互,T-Box 接收汽车的响应报文再传给 TSP,TSP 将返回结果转换成 HTTP/HTTPS 协议的响应报文,返回给 APP,APP作为应用端,显示结果。

它的完整流程

下行:APP——》TSP(HTTPS请求)——》T-Box(转换为CAN报文)——》CAN总线——》VCU(车身域)

上行:VCU(车身域)——》CAN总线(返回处理结果)——》T-Box(转换为HTTPS报文)——》APP

————

3.1 HTTP API 接口测试

  • HTTP 状态码
    • 涵义:HTTP协议规定的标准代码,表示请求的大致结果,常见的有:
      • 200 OK:请求成功
      • 400 Bad Request:请求参数有误(如参数错误)
      • 401 Unauthorized:身份验证失败
      • 403 Forbidden:身份验证成功,但权限不足
      • 500 Internal Server Error:服务器内部发生未知错误
    • 测试意义
      • 简单的描述,4xx 开头的响应码,与客户端有关;5xx 开头的响应码,与服务器有关。2xx 开头的响应码,代表响应成功。
  • 业务状态码
    • 意义:TSP 在 HTTP 通信请求成功,也就是状态码200的基础上,在响应体(JSON)中自定义的“业务逻辑结果码”,例如
      • 0:指令执行成功
      • 1001:车辆不在线
      • 1002:指令执行超时
      • 2001:用户无此操作权限
    • 测试意义: 让APP能向用户展示更加精确的业务成功/失败原因。
  • HTTP/HTTPS请求详解
    • 请求方式:查询类通常是 GET,控制类通常是 POST
    • 请求地址:例如 https//api.example.com/v1.0/vehicles/{vehicle_id}/status
    • 请求参数:这里只说明必须项
      • Authorization:access_token:身份验证(APP登录及绑定车架号后的token)
      • Content-Type:application/json:请求和响应的格式为 JSON
      • vehicle_id:通常使用17位VIN(车架号)区分
  • 响应结果详解
    • {
        "response": {
          "tire_pressure": {
            "front_left": 235,
            "front_right": 232,
            "rear_left": 228,
            "rear_right": 231,
            "unit": "kPa"
          },
          "fuel": {
            "percent_remaining": 0.65,
            "amount_remaining": 42.5,
            "range": 380,
            "unit": "liter"
          },
          "oil_life_remaining": {
            "value": 0.15,
            "unit": "percent"
          },
          "vehicle_status": "asleep"
        },
        "error": null,
        "status":200
      }
    • status:200:响应码,200 代表响应成功
    • tire_pressure:胎压相关,unit的单位是kPa
    • fuel:燃油相关
      • percent_remaining:燃油剩余百分比,0.65 代表剩余 65%
      • amount_remaining:燃油剩余体积,42.5 代表剩余 42.5升
      • unit:liter:燃油体积单位,也就是“升”的意思
      • range:380:预估可行使里程,中国发行的车辆,通常单位是“公里”
    • oil_life_remaining:机油相关
      • value:0.15:剩余机油百分比,0.15 代表剩余 15%
      • unit:percent:百分比单位
    • vehicle_status:车辆状态
      • asleep:车辆处于休眠中,拿油车举例,通常熄火、下车并关闭车门,5分钟以后,仪表盘、中控等设备逐步休眠。

————

3.2 MQTT 接口测试

 

MQTT协议是一种基于“发布/订阅”模式的轻量级消息传输协议,它遵守的规则是:一次连接、持续监听、高效交互。它与Websocket协议非常相似,但是在汽车行业,使用MQTT更加常见,MQTT位于云端,通常与TSP在同一服务器。

将协议本身想象成一个“邮局系统”,核心角色有三个:

  1. 发布者:发送消息的一方,就像寄信的人。
  2. 订阅者:接收消息的一方,就像收信的人。
  3. 代理:MQTT服务器,负责接收所有消息,过滤并分发,就像邮政局的分拣中心。

————

MQTT协议的特点

  1. 一次连接,持久保持: 一次TCP握手建立连接,在整个会话期间保持持续监听,避免了HTTP短连接频繁的“握手-断开”开销。
  2. 双向通信:连接建立后,客户端和服务器可随时主动发送消息,与HTTP的“请求-响应”的被动模式完全不同。
  3. 低开销:在持续监听的过程中,消耗很少的流量和电量,却可以保持高效的通话,是最适合云端车载的协议。
  4. 协议本质:构建在 TCP/WebSocket 之上的应用层消息协议,它定义了消息的格式、路由和传递规则
  5. 通信模式:原生的“发布/订阅”模式,通过“主题”,可以轻松实现一对多、多对多的消息广播,天生解耦。
  6. 服务质量:提供三种 Qos 等级
    • QoS 0:最多一次,可能丢失
    • QoS 1:至少一次,可能重复
    • QoS 2:确保一次,可靠交付

T-Box 和 TSP 的订阅关系

使用上面的邮局举例,T-Box 既可以是发布者、也可以是接收者,TPS也是如此。

场景1:车辆上报数据

  • 发布者:T-Box
  • 订阅者:云端 TSP
  • 主题示例:vehicles/{车辆VIN}/telemetry/speed
  • 消息内容:{"value":65}

工作流程:

  1. T-Box(发布者)持续采集车辆数据(如车速、油耗、位置、发动机状态等)
  2. T-Box 将这些数据打包成消息,发布到主题上,比如主题:vehicles/AAA/telemetry
  3. 云端 TSP(订阅者)已经提前订阅了所有车辆的上报主题
  4. MQTT代理,收到 T-Box 的消息后,立即转发给订阅了该主题的 TSP
  5. TSP 收到数据后,进行存储、分析和处理

总结:在这个流程里,TSP 订阅了 T-Box 发布的消息,反之,比如 T-Box 订阅了 TSP 的“OTA升级”主题,当 TSP 发出一条OTA升级命令时,TSP 就是发布者,T-Box 变成了订阅者。

————

3.3 油车、电车的网联功能对比

 

油车的网联功能,本质是“工具型”,即“用户提交一次请求”、“服务器完成一次响应”(如:远程开门、查询车况)。这与 HTTP 的“请求—响应”模式完美契合。

电车的网联功能,本质是“服务型”,即“车辆作为一个智能终端,持续地与云端交互数据,以提供无缝的服务”。

功能场景 油车 (典型HTTP用例) 电车 (典型MQTT用例)
核心模式 用户主动控制 车辆主动服务 + 云端主动管理
通信方向 主要为 APP -> TSP 的下行指令 TSP <-> T-Box 双向高频数据流
数据特性 指令、一次性查询 连续的数据流、事件流、状态流
具体例子 远程开锁、远程启动 电池状态实时监控、充电管理、故障预警、自动驾驶数据回传

————

3.4 电车哪些核心功能驱动了MQTT的应用?

  1. 持续且高频的车辆监控
    • 电池包状态(电量、温度、健康度)、电驱系统温度、车载充电机状态等。
  2. 实时远程诊断与预警
    • 电池热失控预警、高压系统漏电报警等。
  3. 智能充电管理与V2G
    • APP预约充电:比如,设置10点开始充电,使用 MQTT 协议更加流畅
    • 充电状态实时推送:充电过程中,在APP上可以实时查看,这也是MQTT的优势
    • V2G:车辆对电网送电,电网调度指令需要毫秒级下发,车辆当前可放电功率也需要实时上报,这种“双向、高频的指令流”HTTP 协议并不适合做。
  4. 自动驾驶数据回传
    • 数据采集:算法训练,需要持续将大量传感器数据,如摄像头、雷达、激光雷达等信息,回传到云端,MQTT可以建立一条稳定、高吞吐量的数据上行通道。
  5. OTA升级
    • 如果是传统的油车,OTA升级除了在线下4s店刷机之外,如果支持远程OTA,那么也是需要用户发起(HTTP协议的特殊性)。但是使用 MQTT 协议的电车,当 TSP 推送给 T-Box 一条固件升级消息,用户可立即同意或推迟升级。
  6. 哨兵模式
    • 车辆锁车停放后,通过摄像头和传感器持续监控周边情况,当出现碰撞或威胁时,自动录制视频并通过T-Box向云端发送一条最高级别的警报。而这条警报由TSP推送服务通知车主APP。
  7. 电池智能管理与预热
    • 云端智能充电:车主在APP上设置一个出发时间,TSP根据当前电价、电池状态等,通过云端计算,在最优时间,主动下发指令给车辆充电,确保触发时电池电量充满且温度适宜。
    • 出发前预热:在冬季,车主可以提前计划出发前,提前预热电池。

————

3.5 什么时候建立 MQTT 连接?

 

电动汽车 MQTT 连接的生命周期,通常是在以下时刻开始建立:

  1. 车辆上电/启动时(常见)
    • 当驾驶员点击ON给车辆上电或启动车辆时,T-Box 开始工作并建立 MQTT 连接
  2. 特定事件触发
    • 远程控制请求(如手机APP发送指令:远程启动车辆)
    • 警报时间(如非法入侵、碰撞检测)
    • 定时任务(如定期数据上报)
  3. 休眠模式
    • 即使熄火,甚至好几天都不启动,T-Box 可能进入低功耗模式,维持心跳,便于下次快速连接

熄火后,可能传输的数据:

  1. 心跳包:每隔5分钟,几十字节(维持连接,确保设备在线)
  2. 定位数据:每隔15分钟,200字节(车辆位置追踪)
  3. 电池状态:每1个小时,几十字节(监控电池健康度)
  4. 警报事件:事件触发,数据量可变(碰撞、非法进入等)
  5. OTA准备:定时检查,数据量可变(检查是否存在软件更新)

————

4. 业务逻辑测试(名词解释)

  • 幂等性:
    • 意义:同一个请求被重复执行多次产生的效果,与仅执行一次的效果完全相同
    • 测试意义:在网络不稳定,或用户着急点击,多次发送同一个请求,如果每次都按照顺序执行,可能会导致系统逻辑混乱或安全风险,所以,设计点击两次“开锁”,仅会
  • 车辆状态
    • 熄火OFF、通电 ACC、启动 ON、行驶中 Driving,它们是 TSP 进行逻辑判断的核心依据,也是判断事件和逻辑的前提条件。
  • 安全行车逻辑
    • 当车辆行驶中,需拦截某些影响行车安全的指令,如:远程打开车门、远程打开后备箱、远程开锁,行车安全永远是优先级第一。
  • 数据一致性
    • 意义:TSP 下发的指令状态、车辆的实际状态、以及最终反馈给 App 的状态,三者必须保持一致。
    • 测试意义:防止出现“TSP 显示指令成功,但车辆未执行命令”或 APP 显示“执行中”但车辆已执行,各种不一致的情况,直接影响用户体验和有效性。

————

5. 分布式系统故障排查

APP 端提交一次“远程启动车辆”命令,过了30秒,APP 显示“操作失败”,但是车辆实际已启动,那么如何排查问题?

排查流程如下

  1. TSP:检查 TSP 日志,作为远程服务端,它的日志最容易获取。
    • 情况1:显示报文成功信息,下一步排查 APP 端,问题可能出现在 TSP——》APP,也可能出现在 APP 端,解析错误导致的问题。
    • 情况2:没有报文成功信息,下一步排查 T-Box日志,问题可能出现在 T-Box——》TSP,为什么没有返回报文给TSP。
    • 情况3:存在报文失败信息,下一步排查 T-Box日志,问题可能出现在 T-Box——》TSP
      • T-Box 上传状态错误
      • TSP 解析状态错误
  2. T-Box:精准定位,是 T-Box 没有上传报文,还是 TSP 没有收到报文。
  3. VCU:当前面几步都是正常的,那就要考虑底层,使用 CAN 报文,抓取“远程启动车辆”命令下发后,CAN总线的响应报文,也有可能是因为VCU没有将返回状态传给CAN总线,导致T-Box和TSP在没有收到响应报文时,以超时失败回传状态。

————

6. 幂等性、业务校验、频率控制

场景:我在使用 APP ,下发一个“远程启动”命令,怎么判断是哪种机制驳回了我的请求?

幂等性:APP第一次发送请求后,在整个下行、上行的过程中,用户并没有收到结果,所以再次发送了一次相同的请求。此时,第一次的请求并没有执行完毕,所以它会直接拦截了请求,并返回上一次成功的响应或当时的状态数据,也就是说,第二次请求,根本就没有生效。

业务状态校验:APP第一次发送请求后,返回了1个值,接着,APP第二次发送请求,此时,第二次的请求和第一次的请求,是完全不同的,如果第一次命令“远程启动”已成功,那么第二次提交时,tsp判断车辆状态后,直接返回失败“车辆已启动”。

频率控制:当用户不停在刷新页面,比如,点击“远程启动”按钮,返回到上一页,再回来点击一次,反复操作,系统会拒绝新的请求,APP 端可以加入前端限制,比如点击一次按钮后,将按钮置灰或置为无法点击状态直到返回上一次处理结果或是对整个页面遮罩。但如果前端无法强制限制玩家,后台代码应处理每分钟的并发量是多少,进而避免重复发送报文。

图中这种情况,每隔1分钟提交1次申请,而每次都是等到上一次APP返回了结果申请的下一次。

  1. 它不是“幂等性”:幂等性是“同一个请求”,这里很明显区分开了,每次执行都是上一次结果出来之后再申请的。
  2. 它不是典型的“业务状态校验”:“车况刷新”是一个只读操作,无论车辆状态(启动、熄火、行驶中),查询语句都不会影响安全,系统没有理由拒绝申请。
  3. 它不是“并发连接”限制:
    • 同一时间,只有车主提交请求,不存在同一时间或是无限接近的时间,多个请求同时提交数据。
  4. 有可能的是“频率控制”:
    • 服务器触发了计数器阈值:比如,5分钟内,只允许查询几次接口,且每次查询之间需大于1分钟。
    • TSP后端服务故障:某个服务出现故障,导致处理请求超时或失败。
    • 车辆 T-Box  网络不稳定:车辆所在位置的 4G/5G 信号很差,导致 TSP 与车辆之间指令不通古,所有需要车辆实时响应的结果都失败。

————

7.车载网络与测试工具

 

协议类型 典型速率 主要应用场景 特点成本
LIN 1 - 20 kbps 车身低速控制:
  车窗、雨刮、门锁、座椅调节、空调面板
低成本,辅助总线
低速CAN 10 - 125 kbps 车身控制:
  灯光、门窗、仪表盘、故障诊断
可靠、成本低、抗干扰强
高速CAN 125 kbps - 1 Mbps 动力总成、底盘控制:
  发动机、变速箱、刹车、EPS
汽车网络主干
以太网 100 Mbps - 10 Gbps 高带宽要求:
  车载信息娱乐系统、摄像头、雷达、激光雷达、网关、OTA
带宽极高、支持复杂数据、成本高
FlexRay 10 Mbps 线控系统:
  主动悬挂、高级刹车
高确定性、成本高
MOST 25 - 150 Mbps 多媒体系统(早期):
  音频、视频传输

环境拓扑(可靠性低)、成本高、无法适应新型汽车、带宽虚假,

现逐步被以太网取代

车内网络:

  • 通信协议:CAN、LIN 等
  • 测试工具:CANoe、CAPL、Db++、Panel 等
  • 测试焦点:信号交互、时序、ECU逻辑、网络管理、诊断
  • 执行位置:车辆总线 / HIL 台架

车云网络:

  • 通信协议:MQTT、HTTPS
  • 测试工具:Python/JAVA(语言)、MQTT客户端、云端测试框架
  • 测试焦点:连接、订阅/发布、数据格式、安全、云端处理逻辑
  • 执行位置:T-Box硬件 / 云端服务器

————

8.使用Python语言模拟MQTT协议的订阅者、发布者

 

订阅者:subsciber.py

# 订阅者
# coding=utf-8
import paho.mqtt.client as mqtt
import time

# 连接回调函数
def on_connect(client, userdata, flags, reason_code, properties):
    print(f"连接结果码: {reason_code}")
    if reason_code == 0:
        print("订阅者连接成功!")
        # 订阅主题
        client.subscribe("test/car/speed")
        client.subscribe("test/car/status")
        print("已订阅主题: test/car/#")
    else:
        print(f"连接失败,错误码: {reason_code}")

# 消息接收回调函数
def on_message(client, userdata, msg):
    print(f"\n收到消息:")
    print(f"  主题: {msg.topic}")
    print(f"  内容: {msg.payload.decode()}")
    print(f"  QoS: {msg.qos}")

# 创建客户端 - 使用新版本API
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, "PythonSubscriber")
client.on_connect = on_connect
client.on_message = on_message

print("正在连接MQTT代理...")
client.connect("broker.hivemq.com", 1883, 60)

# 保持监听
print("开始监听消息... (按 Ctrl+C 退出)")
try:
    client.loop_forever()
except KeyboardInterrupt:
    print("\n断开连接...")
    client.disconnect()

发布者:publisher.py

# 发布者
# coding=utf-8
import paho.mqtt.client as mqtt
import time
import json


# 连接回调函数
def on_connect(client, userdata, flags, reason_code, properties):
    if reason_code == 0:
        print("发布者连接成功!")
    else:
        print(f"连接失败,错误码: {reason_code}")


# 创建客户端 - 使用新版本API
client = mqtt.Client(mqtt.CallbackAPIVersion.VERSION2, "PythonPublisher")
client.on_connect = on_connect

print("正在连接MQTT代理...")
client.connect("broker.hivemq.com", 1883, 60)
client.loop_start()  # 后台循环

try:
    counter = 0
    while True:
        # 模拟车辆数据
        speed = 60 + (counter % 20)  # 60-80之间变化
        status = "normal" if counter % 5 != 0 else "warning"

        # 发布车速信息
        speed_msg = f"当前车速: {speed} km/h"
        client.publish("test/car/speed", speed_msg, qos=0)
        print(f"已发布: {speed_msg}")

        # 发布状态信息 (JSON格式)
        status_msg = json.dumps({
            "vehicle_id": "CAR_001",
            "status": status,
            "timestamp": time.time(),
            "counter": counter
        })
        client.publish("test/car/status", status_msg, qos=1)
        print(f"已发布状态: {status_msg}")

        counter += 1
        time.sleep(3)  # 每3秒发布一次

except KeyboardInterrupt:
    print("\n停止发布...")
    client.loop_stop()
    client.disconnect()

打开两个终端,分别执行2个py文件后,如下图,PowerShell 显示的是订阅者的日志;Pycharm 显示的是发布者的日志。它们只要不关闭,就会一直发送和接收消息。

 

END