Skip to content

About

F1 赛事控制消息专用 Android App:直连 F1 官方公开流(不需要 Home Assistant、不需要令牌),蓝旗/黄旗/安全车/双旗分级强提醒,横屏看板。Android 6.0+,92.7 KB。

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

61 Commits

Folders and files

Repository files navigation

F1-RaceControl

把 F1 官方公开的赛事控制数据做成 Android 手机上的实时仪表。

比赛日你会盯着它看:红旗、安全车、双黄旗立刻强提醒;赛道当前状态一眼可见; 噪音默认过滤掉。

直连 Formula 1 官方的实时计时服务,不带任何令牌、不需要账号、不经过任何中间服务器。

给 Android 6.0 老设备做的:不经过 WebView、不依赖 Google 服务、零第三方依赖, APK 85 KB。

v3.0.0 起是「A 方案」——数据链从「F1 官方 → 上游集成 → Home Assistant → App」 缩成「App → F1 官方」。旧的 HA 版界面与代码仍保留在仓库里作为兜底, 但已不是启动入口。

上一代是 Android_HA_Viewer (通用的「任意实体变化流水」)。两者包名不同,可以同时装在一台手机上。


它解决什么问题

原始的 HA App 或者一个通用的实体列表,在比赛时会变成这样:

  • 一个比赛周末 697 条消息,其中 54.8% 是噪音(蓝旗、解除、删圈速通报); 正赛里这个比例高达 68.5% —— 蓝旗一项就占 42.9%
  • 双黄旗一个周末 142 条,但它只对应 24 个真实事件 (F1 的赛道系统会把一次事故扩散到几十个区段,最极端的一次:52 条消息、20 个区段、持续 284 秒)
  • 如果你让每条双黄都报警,一个周末会被自己的手机吓 146 次

这个 App 把这些都处理掉了。


数据从哪来

全部来自 livetiming.formula1.com 的公开流,不需要登录:

流 内容
RaceControlMessages 赛事控制消息(旗语、判罚、赛道状况)
TrackStatus 全赛道状态码(1/8 全清、2 黄、4 安全车、5 红旗、6 VSC、7 VSC 结束)
SessionInfo / SessionStatus 会议、赛道、环节、进行状态
LapCount 当前圈 / 总圈数
DriverList 车手、车队、车队配色
TimingData 名次、与领先者差距、与前车间隔、是否在维修区
TimingAppData 轮胎配方、每套胎的圈数(进站次数)
TimingStats 个人最快圈
TopThree / WeatherData / ExtrapolatedClock 前三名 / 气温赛道温湿度风雨 / 剩余时间

需要 F1TV 订阅的只有 CarData.z(遥测)、Position.z(赛道位置)、 TeamRadio(车队无线电)那几路 —— 本 App 一个都不用。

连接过程只做一次 POST 拿一个一次性令牌,再拿它开 WebSocket。令牌用第二次就失效, 所以每次重连都必须重新申请;App 里不保存任何凭据,你也不需要填任何东西。


功能

横屏:左边消息,右边面板

竖屏就是消息列表 + 顶部旗语栏。横屏变成左右分栏,最右侧一条窄框图标条切换 6 屏:

图标 面板 内容
◎ 赛道图 圆环 + 各区段旗语颜色
◍ 轮胎进站 22 个位置、三列每列 8 行、顺序按赛道位置
≡ 成绩 名次 + 差距 / 间隔 + 轮胎
☂ 天气 气温 / 赛道温 / 湿度 / 风 / 雨 + 全赛道状态
⏱ 最快圈 个人最快圈排行
ⓘ 环节 会议 / 赛道 / 环节 / 剩余 / 圈数 + 前三名

赛道图为什么是圆环:真形状要靠 Position.z(赛道位置流),那需要 F1TV, 实时拿不到。所以退而求其次用区段均布的圆环。环上的段数取「本场出现过的最大 区段号」,不依赖任何外部数据表 —— 官方没有任何文件写出过区段总数(FIA 每站 55 份文档都查过,编号只画在赛道图上)。

顶部旗语栏:多旗语并存时纵向分隔

以前只显示优先级最高的那一个,会丢掉同时存在的其他旗语。现在按种类分段:

┌──────────┬──────────┬─────────┐
│ 黄旗     │ 双黄旗   │ 安全车  │
│ 3,7      │ 12       │ 全场    │
└──────────┴──────────┴─────────┘

轨道级的(红旗 / 安全车 / VSC / 全赛道黄旗)下面写「全场」,区段级的写区段号。 这个区分不是猜的:轨道级来自官方 TrackStatus 流,区段级来自消息的 Scope=Sector —— 实测消息里根本不存在 Scope=Track 的黄旗。

新消息闪动

到达的新消息先闪两下再定格到等级配色。

红旗 / 安全车 / VSC 强提醒

全屏横幅 + 循环警报音 + 震动 + 点亮屏幕。

  • 走 闹钟通道,突破系统静音/振动模式(可在设置里关)
  • 不同类型给不同震动节奏:红旗三长震、安全车两震、VSC 一长震、双黄三短震
  • 锁屏上也能看到(全屏横幅 + 通知栏各一条)
  • 「知道了」按钮停止;不点也会在 15 秒后自动停(可配)

订阅时官方会推一份历史全量快照。这些旧消息照常进列表,但不会触发提醒 —— 否则开机瞬间会弹几十次「几小时前的红旗」。

双黄旗:不会炸响你

双黄旗到达时先给轻提醒(一声短音 + 一短震),同时挂一个定时器; 存活超过 15 秒仍未清除才升级为全屏强提醒。

为什么要这样:实测双黄旗的存活时长是双峰的 ——

存活时长 次数 判读
0–5 秒 8 系统抖动
6–15 秒 21 测试或瞬时
16–60 秒 19 局部事故
1–5 分钟 21 真事故
> 5 分钟 14 重大事故

最短只有 1 秒。3 秒的双黄不可能是真事故。 所以「存活 ≤15 秒」是干净的判据。

警报的单位是「一次事故」而不是「一个区段」:事故之间用静默间隔划界 (45 秒 —— 实测双黄消息的间隔分布在 30 秒处有个天然断档)。

一个周末的警报次数:146 次 → 23 次(用真实客户端代码在真实数据上跑出来的)。

中文简述

仲裁消息又长又全是术语,比赛时根本没空读。所以列表里每条补一行中文:

FIA STEWARDS: TURN 1 INCIDENT INVOLVING CAR 5 (BOR) NOTED -
FAILING TO FOLLOW RACE DIRECTORS INSTRUCTIONS – ESCAPE ROAD INSTRUCTIONS (14:27:29)

1 号弯事故(博托莱托(5)):已记录 —— 未遵守赛会指令(逃生通道)

判罚尤其讲究,谁被罚、罚多少、为什么,一眼要能看出:

★ 判罚:塞恩斯(55) 罚时 5 秒 ★ 判罚:加斯利(10) 罚时 5 秒 —— 维修区超速 仲裁:塞恩斯(55) 已执行 5 秒罚时

覆盖情况:把 2024–2026 三个赛季全部 RaceControl 消息从官方归档拉下来 (16,517 条 → 6,825 个模板)逐个过一遍,该翻译却没有中文的缺口为 0; 剩下 87 个是纯旗语模板(CLEAR IN TRACK SECTOR 12 这种),徽标已经说全了, 有意不翻。有中文的模板占 98.7%。

翻不出来就不显示(宁可给原文,也不瞎猜)。规则全部是从真实数据的措辞反推的, 三位车手缩写会转成中文姓。

默认噪音过滤

顶部一键切换「精简 / 全部」。默认隐藏:蓝旗、解除、删圈速通报。

断线可见

这条比强提醒本身还重要。 比赛中掉线时,你会以为「赛道没消息」, 实际是漏了红旗 —— 静默失败比崩溃危险。所以顶部状态行常驻显示当前阶段 (未启动 / 连接中 / 已连上等数据 / 连接出错),连接出错时并附带最后一条错误原文。

其它

  • 按车号筛选(输入 44 只看 Hamilton 相关)
  • 自由关键词排除
  • 看消息时不熄屏(窗口标志实现,不需要额外权限)

不回放不比赛?直接放一遍真实比赛

不用等比赛、不用网络 —— 从 Releases 下载一个 .rclog 示例文件, 在设置页 ->「回放测试(假数据)」->「选择 .rclog 文件…」 选上它, 保存返回,界面就会把一整场真实比赛完整跑一遍。

文件里是官方归档的一整场真实比赛(2026 巴林站正赛,10 月 4 日), 格式与线上 WebSocket 逐字节同构:先一条 type:3 完整快照, 之后逐条 type:1 增量,记录之间同样是 0x1e 分隔。 所以解析和渲染走的是和实时完全同一份代码。

两个示例文件,区别在「接上时那一刻」:

文件 接上时 模拟的场景
..._race.rclog 只有 1 条消息 比赛刚开始就打开 App,看着旗语栏逐步长出来
..._race_mid.rclog 194 条消息 + 22 辆车全字段 比赛过半才打开 App —— 也就是真机上最容易崩的那种负载

倍速 10 / 30 / 60 / 120 / 300,60 倍下一整场 4 小时只要 4 分钟。 放出来的消息时间会被改成「现在」,所以提醒、闪动、全屏横幅都会真的触发。

为什么示例数据不放在 APK 里:v3.1.0 放过,代价是 APK 从 85 KB 涨到 845 KB,其中 751 KB 全是示例数据 —— 而多数人一辈子用不上一次。 v3.2.0 起改成外置:APK 92.7 KB,想要示例的人自己下一个就行。 用系统的文件选择器读它,所以不需要任何存储权限,文件放哪儿都行。


安装

  1. 从 Releases 下载 APK,拷到手机,开启「未知来源」后安装
  2. 打开就能用 —— 不需要填任何东西

就这两步。没有服务器地址、没有令牌、没有实体 ID。


开发

构建、测试、发版都写在 docs/CONTRIBUTING.md; 使用说明见 docs/USAGE.md。

值得一提的两个坑(代码里都有回归测试钉住):

  1. 连接令牌是一次性的。 同一个 connectionToken 用第二次直接 404, 所以每次重连都必须重新 negotiate。
  2. 大消息会分片。 初始快照几十 KB,服务端按 FIN/续帧拆开,必须重组 (WsFrame.readMessage),否则只会拿到半截 JSON。

还有一个数据形状上的坑,同一种错犯了三次:Stints(轮胎套数)、Messages、 TopThree.Lines 在真实数据里list 和 dict 两种形状都会出现, 方向还不固定。手写的测试夹具发现不了这个 —— 仓库里的 tools/mock_data/f1_snapshot_real.json 是官方归档的真实快照, tools/mock_data/bahrain2026_race_mid.rclog 是整场时间线, 就是它们把这类问题抓出来的(TopThree 那次连"面板空着是因为没订流、 还是因为形状读错"都分得清)。

顺带一个教训:README 这张数据来源表早就写了 TimingStats 和 TopThree, 但 F1Feed.STREAMS 里其实没订这两条流 —— 文档比代码诚实。 现在两边的对账是单测里钉住的。


说明

  • 本应用不收集任何数据,所有通信只发生在你的手机与 F1 官方服务器之间
  • 不保存任何凭据:连接用的是一次性令牌,用完即弃
  • 内容版权归 Formula One World Championship Limited,请仅供个人非商业使用

同族的 Windows 版:F1-RaceControl-Desktop —— 同一份数据层源码编译两遍(不是照着重写),右侧面板可以各自拉成独立原生窗口同时显示, 并自带 Web 服务器,手机 / iPhone 打开浏览器看到的界面和 Windows 上完全一样。

许可证:MIT

About

F1 赛事控制消息专用 Android App:直连 F1 官方公开流(不需要 Home Assistant、不需要令牌),蓝旗/黄旗/安全车/双旗分级强提醒,横屏看板。Android 6.0+,92.7 KB。

Resources

Contributing

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages