- 前端
- 智能家居
- UI组件
【免费下载链接】frontend
:lollipop: Frontend for Home Assistant
本文以 landing-page/README.md 为核心骨架,结合 frontend 仓库(Home Assistant 官方前端)中landing-page/目录的源码实现,系统讲解 Home Assistant OS(HAOS)首次启动时下载 Home Assistant Core 期间的过渡页面:它的下载进度条、Supervisor 日志展示、DNS 故障处理、错误处理等核心功能如何工作,以及如何在前端仓库与独立的 landingpage 仓库之间搭建本地开发环境。读完本文,你将掌握这一过渡页的完整技术脉络与一套可复现的开发调试流程。
一、背景:为什么需要 Landing Page
HAOS 在首次启动(initial startup)时,必须先从网络下载 Home Assistant Core,下载完成前整个系统的初始化流程还无法开始。在这一段时间内,需要一个独立于 Core 的轻量页面来向用户反馈进度,这就是 Landing Page 的职责——它负责托管一个 "Preparing Home Assistant"(正在准备 Home Assistant)页面,直到 Core 就绪、浏览器自动跳转进入正式的引导流程(onboarding)。
这个页面并非独立项目,而是以子目录形式存在于本 frontend 仓库中(landing-page/),并且与正式前端共享同一套 UI 组件与国际化基础设施。从 landing-page/src/entrypoint.js 可以看出它的入口非常轻量:先加载ha-landing-page自定义元素,再通过import("../../src/resources/append-ha-style")注入前端仓库共享的基础样式。
整个页面最终渲染在 landing-page/src/html/index.html.template 定义的 HTML 骨架中:页面头部展示favicon-192x192.png图标,正文仅包含一个<ha-landing-page></ha-landing-page>自定义元素,并复用前端仓库的_header、_style_base、_js_base、_preload_roboto、_script_loader等 HTML 模板片段,同时对prefers-color-scheme: dark做了暗色适配。
二、五大核心功能拆解
原文档将 Landing Page 的功能归纳为五类,逐一结合源码展开如下。
1. 下载进度条(Progress bar)
进度条用于直观展示 Home Assistant Core 的下载进度。它的数据来源并非浏览器猜测,而是由 Supervisor 的任务系统提供:
- 页面轮询
/supervisor-api/jobs/info接口(见 landing-page/src/data/supervisor.ts),在返回的任务列表中查找名为home_assistant_core_install的任务; - 取到该任务后,用其
progress字段(0~100 的浮点数)更新进度条;取不到则把进度重置为-1,此时进度条显示为不确定(indeterminate)状态(见 landing-page/src/ha-landing-page.ts)。
页面顶部文案来自国际化文件 src/translations/en.json,其中subheader明确提示用户:"The latest version of Home Assistant is being downloaded. This may take 20 minutes or more."(正在下载最新版本,可能需要 20 分钟甚至更久)。
轮询节奏由常量控制(landing-page/src/ha-landing-page.ts):
| 常量 | 值 | 含义 |
|---|---|---|
ASSUME_CORE_START_SECONDS | 60 | 假定 Core 正在启动的宽限秒数 |
SCHEDULE_CORE_CHECK_SECONDS | 1 | 假定 Core 启动期间,每秒探测一次 |
SCHEDULE_FETCH_NETWORK_INFO_SECONDS | 5 | 常规状态下每 5 秒刷新一次网络信息 |
SCHEDULE_FETCH_JOBS_INFO_SECONDS | 2 | 每 2 秒刷新一次 Supervisor 任务进度 |
值得注意的是_checkCoreAvailability()(landing-page/src/ha-landing-page.ts)这个"核心就绪探测"逻辑:页面会尝试fetch("/manifest.json"),一旦请求成功,说明 Core 已经接管了服务,立即location.reload()触发页面刷新进入正式引导;若失败,则开启_coreCheckActive标志,进入 60 秒的密集探测窗口,并在窗口结束后自动关闭。这套机制保证了"下载完成 → 页面自动切换"的无缝体验。
2. 显示 / 隐藏 Supervisor 日志(Show / hide supervisor logs)
日志面板由 landing-page/src/components/landing-page-logs.ts 实现,其工作方式值得展开:
- 默认通过
getSupervisorLogsFollow()拉取/supervisor-api/supervisor/logs/follow?lines=500的流式接口(见 landing-page/src/data/supervisor.ts),用ReadableStream的 reader 持续读取,配合TextDecoder逐块解码,实现接近实时的日志滚动; - 日志内容通过
ha-ansi-to-html组件做 ANSI 颜色转换与高亮; - 每次解析日志时用正则
/^[\d\s-:]+(ERROR|CRITICAL)(.*)/gm检测错误级别行,一旦命中就触发landing-page-error事件并自动展开日志面板——这正是"安装出错时自动展示日志"的实现基础; - 若 Supervisor 日志流不可用(例如 Supervisor 自身还没起来),会回退到
/observer/logs拉取 observer 日志,并且每 5 秒检查一次 Supervisor 日志是否恢复,恢复则切回流式模式; - 日志面板支持下载:点击下载按钮会以
observer_${时间戳}.log为文件名下载完整日志(时间戳中的冒号会被替换为-,避免文件名非法)。
此外,日志面板还实现了"滚动到底部"交互细节:通过IntersectionController监听底部标记元素的可见性,用户未处于底部且出现新日志时,会显示"New logs - Click to scroll"悬浮按钮;自动滚动到日志末尾时该指示自动消失。
3. 外部链接(Links)
页脚提供三个对外入口:Read our Vision(阅读我们的愿景)、Join our community(加入社区)、Download our app(下载我们的 App)。这些入口直接复用了正式 onboarding 流程中的onboarding-welcome-links组件(见 landing-page/src/ha-landing-page.ts),因此文案与正式引导页保持完全一致,翻译均指向 src/translations/en.json 中ui.panel.page-onboarding.welcome下的共享键。
组件还通过extractSearchParam("redirect_uri") === "homeassistant://auth-callback"判断当前是否来自移动端 App 的授权回调(见 landing-page/src/ha-landing-page.ts),据此调整移动端链接的展示策略,实现"Web 浏览器与 App 场景差异化引导"。
4. DNS 问题处理器(DNS issue handler)
当 Supervisor 无法连接互联网时,页面需要引导用户自助修复。核心判定逻辑在 landing-page/src/ha-landing-page.ts:只要_networkInfo.host_internet为false,就渲染landing-page-network子组件;_networkInfoError为真时同样渲染(但展示的是"无法获取网络信息"的报错样式)。
landing-page-network组件(landing-page/src/components/landing-page-network.ts)的处理流程:
- 从网络信息中筛选出
primary && enabled的主网络接口,汇总其 IPv4 与 IPv6 的 nameserver 并展示在告警文案中; - 若找不到主接口,则提示用户"无法检测到主网络接口,因此无法修改 DNS",并禁用修复按钮;
- 提供两组备选 DNS 一键切换(定义于 landing-page/src/data/supervisor.ts):
| 方案 | IPv4 | IPv6 |
|---|---|---|
| Cloudflare DNS | 1.1.1.1/1.0.0.1 | 2606:4700:4700::1111/2606:4700:4700::1001 |
| Google DNS | 8.8.8.8/8.8.4.4 | 2001:4860:4860::8888/2001:4860:4860::8844 |
- 点击后调用
setSupervisorNetworkDns(),即向/supervisor-api/network/interface/{主接口}/update发送POST请求,同时设置 IPv4/IPv6 的method: "auto"与对应 nameserver(见 landing-page/src/data/supervisor.ts); - 成功后触发
dns-set事件,通知主页面立即重新拉取网络信息;失败则弹出showAlertDialog告警对话框,提示查看日志后重试。
5. 错误处理器(Error handler)
当安装过程出现问题时,页面的处理方式与日志面板联动:
- Supervisor 日志流中出现
ERROR/CRITICAL行时,landing-page-logs触发landing-page-error事件,主组件据此把_supervisorError置为true; - 此时卡片主体会切换渲染一个
ha-alert(alert-type 为error),标题为 "Error installing Home Assistant",描述为"安装出错,请查看日志获取更多信息"(对应 src/translations/en.json),同时日志面板保持展开,让用户能直接看到报错现场。
三、页面基础架构与源码级细节
组件树与生命周期
ha-landing-page(landing-page/src/ha-landing-page.ts)继承自LandingPageBaseElement(landing-page/src/landing-page-base-element.ts),后者又混入了themesMixin与ProvideHassLitMixin,使得这个未登录场景的页面也能复用前端的主题与语言基础设施。
firstUpdated阶段做了三件事(见 landing-page/src/ha-landing-page.ts):
makeDialogManager(this)注册对话框管理器,供 DNS 失败时的告警对话框使用;- 窗口宽度大于 450px 时动态加载
particles粒子背景资源(移动端窄屏不加载以节省带宽); - 立即发起 Supervisor 网络信息与任务信息的首次拉取,并进入各自的轮询循环。
国际化与语言切换
由于 Landing Page 出现在登录之前,它不能依赖用户配置,因此直接读取浏览器语言:
LandingPageBaseElement用getLocalLanguage()初始化language,通过getTranslation(null, language)拉取对应语言的翻译资源,再用computeLocalize生成localize函数;- 页脚内置
ha-language-picker语言选择器,切换后通过_languageChanged写入localStorage的selectedLanguage键,实现语言记忆; - 同时依据
translationMetadata判断该语言是否为 RTL(如阿拉伯语、希伯来语),自动应用computeDirectionStyles适配从右到左的排版。
对前端共享能力的复用
整个 Landing Page 大量复用正式前端的既有资产,这是它能在极小代码量下保持高质量 UI 的关键:ha-card、ha-progress-bar、ha-alert、ha-button、ha-spinner、ha-language-picker等组件,以及haStyle和onBoardingStyles样式集合,全部来自src/components、src/resources、src/onboarding等共享模块。可以说,Landing Page 是"以前端仓库为底座、叠加少量过渡页专属逻辑"的典型实现。
四、本地开发环境搭建(原文档实操指南)
原文档给出的开发方案是"双仓库协作":frontend 仓库负责构建前端资源,独立的 landingpage 仓库负责托管服务并把请求代理到 frontend 的开发服务器。整体思路与核心前端开发流程一致。
步骤一:配置 landingpage 开发服务器
- 克隆
home-assistant/landingpage仓库; - 在它的 devcontainer 配置中,把本 frontend 仓库以 bind mount 方式挂载进去,例如:
"mounts": ["source=/path/to/hass/frontend,target=/workspaces/frontend,type=bind,consistency=cached"]原文档特别提醒:不要提交这个 mount 改动。首次构建 devcontainer 后即可移除,因为只要不重建容器,构建产物会保留这些选项。
- 使用 dev container 进入开发环境;
- 启动开发服务器时可配置以下可选环境变量:
| 环境变量 | 作用 | 示例 |
|---|---|---|
SUPERVISOR_HOST | 使用真实 Supervisor 数据时填写 Supervisor 的地址(需先按官方文档开启 Supervisor 远程 API 访问) | SUPERVISOR_HOST=192.168.0.20:8888 |
SUPERVISOR_TOKEN | 从 Remote API proxy 加载项日志中获取的 Supervisor API 令牌 | SUPERVISOR_TOKEN=abc123 |
FRONTEND_PATH | 容器内 frontend 仓库的路径 | FRONTEND_PATH=/workspaces/frontend |
三者组合的完整启动命令示例:
SUPERVISOR_TOKEN=abc123 SUPERVISOR_HOST=192.168.0.20:8888 FRONTEND_PATH=/workspaces/frontend go run main.go http.go mdns.go原文档同时提示:这些变量也可以写进 devcontainer 设置,但那样灵活性较差——当你想临时切换测试不同的目标环境时,命令行方式随时可改。
步骤二:启动 frontend 开发服务器
在前端仓库一侧,完成依赖安装后,只需运行仓库内现成的脚本:
landing-page/script/develop该脚本(landing-page/script/develop)实际执行的是./node_modules/.bin/gulp develop-landing-page。这个 gulp 任务(定义于 build-scripts/gulp/landing-page.js)依次完成:
- 设置
NODE_ENV=development; - 清理
landing-page的旧构建产物(见 build-scripts/gulp/clean.js 中的clean-landing-page); - 构建 landing-page 专属翻译(
build-landing-page-translations),该翻译切分逻辑位于 build-scripts/gulp/translations.js,专门把顶层landing-page键提取出来,并确保base翻译中剔除 landing-page 部分以免重复打包; - 拷贝翻译与静态资源(
copy-translations-landing-page、copy-static-landing-page,见 build-scripts/gulp/gather-static.js),同时拷贝字体与 locale 数据; - 生成开发用 HTML 页面(
gen-pages-landing-page-dev); - 启动 rspack 的 watch 模式持续编译(
rspack-watch-landing-page)。
这样,landingpage 开发服务器就能通过FRONTEND_PATH找到本仓库,为过渡页提供实时的前端资源与热更新。
五、生产构建与产物
生产构建通过 landing-page/script/build_landing_page 触发,内部执行gulp build-landing-page(build-scripts/gulp/landing-page.js)。与开发任务相比,它设置NODE_ENV=production,并用rspack-prod-landing-page做一次性的生产打包,最后用gen-pages-landing-page-prod生成正式 HTML。
打包配置位于 build-scripts/bundle.cjs 的landingPage()方法:入口固定为landing-page/src/entrypoint.js,并标记isLandingPageBuild: true以启用专属的构建分支。产物输出路径由 build-scripts/paths.cjs 定义,主要落在landing-page/build/与landing-page/dist/下(含 latest 与带哈希的版本目录、静态资源目录),与正式前端走同一套outputPath/publicPath逻辑,便于 HAOS 集成部署。
六、结语
Landing Page 虽然只是一个过渡页面,但它是 HAOS 首次启动体验的第一道门面,承担着进度反馈、故障自愈与错误可视化三重职责。从本文可以看到,它的实现哲学非常清晰:尽可能复用前端仓库的既有组件与基础设施,只编写最少的过渡页专属逻辑——轮询 Supervisor 任务接口驱动进度条、流式读取并着色渲染日志、检测主网卡 DNS 并一键切换 Cloudflare/Google、探测 Core 就绪后自动刷新跳转。对于想为这套过渡页贡献功能或排查问题(例如网络检测、日志回退策略、移动端场景)的开发者,按照上文第四节的"双仓库 + devcontainer + 环境变量"流程即可快速拉起完整开发环境。
如需继续深入,推荐阅读以下源码入口:
- 主组件与轮询逻辑:landing-page/src/ha-landing-page.ts
- 日志流与错误检测:landing-page/src/components/landing-page-logs.ts
- DNS 修复面板:landing-page/src/components/landing-page-network.ts
- Supervisor / Observer 数据层:landing-page/src/data/supervisor.ts、landing-page/src/data/observer.ts
- 国际化文案:src/translations/en.json
- 构建任务与打包配置:build-scripts/gulp/landing-page.js、build-scripts/bundle.cjs
- 前端
- 智能家居
- UI组件
【免费下载链接】frontend
:lollipop: Frontend for Home Assistant
相关推荐
Home Assistant light.turn_on 动作完全指南:开灯、调光、调色与过渡效果实战
Home Assistant light.turn_on 动作完全指南:开灯、调光、调色与过渡效果实战 light.turn_on 是 Home Assista
文档教程智能家居物联网Home Assistant 前端项目教程
Home Assistant 前端项目教程 1. 项目目录结构及介绍 Home Assistant 前端项目是一个开源项目,其目录结构如下: . ├── .gi
前端智能家居UI组件Home Assistant 用户文档站 home-assistant.io 源码解析与本地构建指南
Home Assistant 用户文档站 home assistant.io 源码解析与本地构建指南 导读 home assistant.io 是 Home A
文档教程智能家居物联网
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考