场景 scene 与脚本 script 的分工
都是「一组动作」,分工在哪
写到某个量级你会发现,很多自动化都在重复同一套动作组合:「关灯 + 关空调 + 关窗帘」既是离家模式的一部分,也是睡眠模式的一部分,又可能是「出门前一键」按钮的内容。HA 提供两个工具来复用这类组合:scene(场景)与 script(脚本)。
一句话区分:scene 是「快照」,描述一组设备的目标状态;script 是「剧本」,描述按顺序执行的动作序列。scene 没有「过程」概念,它就是一张目标清单;script 有先有后,还能带参数、有模式。知道这一点,90% 的选择困难就解决了。
再打个比方帮你记住:scene 像一张照片——拍下「全屋此刻该长什么样」,谁来看都一样;script 像一份菜谱——先热锅、再下油、最后放盐,步骤错了味道就不对。家里「来客人了把灯调暗」是照片,「做饭」是菜谱,分清这两类需求,工具就选对了。
场景 scene:快照式状态
scene 的核心是 entities + 目标状态。激活场景时,HA 把这些实体一次性设到指定状态。三个特点:
| 特点 | scene | script |
|---|---|---|
| 有执行顺序 | 否,并行下发 | 是,从上到下 |
| 可带参数 | 否 | 是 |
| 有 mode | 否 | 是 |
| 状态恢复 | 天然支持快照对比 | 需自己写回滚 |
| 适合 | 灯光氛围、设备预设 | 流程、编排、分支 |
scene 最擅长的是「氛围」:观影、吃饭、阅读、睡前,每个场景记住一组灯的亮度色温、窗帘位置、空调温度。家人点一下场景卡片就完成切换,不需要理解自动化。场景给人用,脚本给自动化用——这条经验比任何技术细节都好使。
创建场景有两条路:在「场景」编辑器里逐个添加实体并填目标状态;或者用快照功能「把当前状态存成场景」。后者最方便:先把全屋调到你满意的样子,一键存为场景即可。
场景的短板也要正视:它没有办法「撤销」。激活另一个场景并不会自动记录上一个状态,所谓「恢复」其实是激活另一个场景。所以成熟的用法是成对建场景:观影灯光配一个日常灯光,睡前灯光配一个起夜灯光,来回切换永远有落点。
脚本 script:可执行的动作序列
script 的 YAML 骨架:
script:
leave_home:
alias: 离家模式
mode: restart
sequence:
- service: light.turn_off
target:
entity_id: all
- service: climate.set_hvac_mode
target:
entity_id: climate.ac
data:
hvac_mode: "off"
- service: cover.close_cover
target:
entity_id: cover.all
脚本的关键能力有四样:
- mode:与自动化相同的 single/restart/queued/parallel,决定重叠调用时的行为。
- 参数(fields):调用时可传变量(
variables或旧式fields),同一个脚本可被多处复用。 - 被调用方式:既能在自动化里
script.turn_on,也能在仪表盘放按钮,甚至让语音助手调用。 - 支持所有动作结构:delay、wait_template、choose、repeat 都能用。
脚本是把自动化「模块化」的主要手段:公共逻辑抽成一个脚本,十条自动化调它,以后改逻辑只改一处。
脚本调用时还能带参数,这是脚本区别于场景的又一大杀器。带参数的脚本长这样:
script:
set_room_light:
alias: 设置房间灯光
mode: single
variables:
room: living
brightness: 50
sequence:
- service: light.turn_on
target:
entity_id: "light.{{ room }}"
data:
brightness_pct: "{{ brightness }}"
调用方传不同的 room 和 brightness,一个脚本就能服务所有房间。参数化是脚本规模的分水岭:不会带参数的脚本写到二十个就乱,会带参数的三个脚本管全屋。
场景与脚本的联用
最常见的组合是「脚本调用场景」。一个「观影模式」脚本可以先关窗帘、降投影幕布,等待幕布就绪后再激活「观影灯光」场景,最后打开播放器。复杂过程交给脚本,最终的氛围交给场景,各取所长。
反过来「场景调用脚本」不成立——场景只能设状态,不能执行动作。如果你发现某个「场景」需要流程,那它本质上是个脚本,改用脚本就对了。
一个联动示例:
script:
movie_time:
alias: 观影时间
mode: single
sequence:
- service: cover.close_cover
target:
entity_id: cover.living
- wait_template: >-
{{ is_state('cover.living', 'closed') }}
timeout: "00:00:20"
- service: scene.turn_on
target:
entity_id: scene.movie_lights
- service: media_player.play_media
target:
entity_id: media_player.tv

scene注册的另一种方式:scene.from_state
除了手写场景,HA 还能通过 scene.from_state 服务把当前某些实体的状态直接存为新场景。一个典型场景:你把客厅调得很舒服,想存下来又懒得逐个填——直接调用这个服务、指定实体列表即可。配合一条自动化(比如「长按某个开关就存当前灯光」),家人也能随手存场景,这是提升家庭接受度的小技巧。
什么时候用哪个:三条判定
- 只关心最终状态 → scene:灯光、窗帘位置、空调温度。
- 有先后或条件 → script:等待设备就绪、循环检查、分支判断。
- 既复杂又想复用 → script 套 scene:流程用脚本跑,终点状态存成场景。
还有一个进阶用法:脚本里用 choose 按条件激活不同场景。比如「晚安脚本」按星期选择不同的空调预设场景,逻辑集中在脚本里,场景只管纯粹的灯光状态。
反过来,也可以用脚本做「场景无能为力的事」:场景灯亮的瞬间就是亮的,但如果你想要「开灯时从 10% 渐变到 80%、同时窗帘缓慢闭合」,这个动态过程只有脚本的 delay 与 service 数据里加 transition 参数才做得出来。一句话总结:静态结果用场景,动态过程用脚本。
使用上的坑
- 场景名别取「模式」:叫「观影灯光」比叫「观影模式」更准确,后者会让你误以为它也能关窗帘。
- 脚本默认 mode 是 single:调用的自动化重叠时会被忽略,该换 restart 别手软。
- scene 不持久化「谁改变了」:场景激活后某盏灯被人手动改了,场景不会自己恢复;需要的话写自动化监听。
- 脚本可被仪表盘直接调用:给家人放按钮时,配上图标和友好名称,体验不输任何原生 App。
- 变量与模板在脚本里要小心引号:
variables段的默认值是 YAML 字符串,拼接实体 ID 时"light.{{ room }}"的内外引号一个都不能少,错了报错还不太好定位。

延伸阅读
- helper 与脚本的参数传递见本系列「helper 实体」一篇。
- 状态恢复与持久化见本系列「状态持久化与开机还原」。
- 部署与备份策略可参考 《群晖 DSM 指南》 与 《NAS 搭建指南》。
