|
|
電視是家裡最難接進 HA 的裝置之一。
這篇講兩種不用依賴廠商雲端的做法。

先看你的電視是什麼
- Android TV / Google TV → 用 ADB,功能最完整
- Sony / Philips 等有 REST API 的 → 用官方整合
- LG webOS → HA 有 webOS 整合,功能不錯
- Samsung Tizen → HA 有 SamsungTV 整合
- 沒有智能功能的舊電視 → HDMI-CEC 或紅外線
路線一:ADB(Android TV / Google TV)
ADB(Android Debug Bridge)是 Android 的除錯介面,
可以下指令、讀狀態、啟動 App。
設定步驟
1. 在電視上開啟開發者選項
- 設定 → 系統 → 關於 → 連續點「版本號碼」七次
- 會出現「開發人員選項」
- 進去打開 USB 偵錯 和 網路偵錯(有的話)
2. 固定電視的 IP
用 DHCP 保留(前面有一篇專門講)。
3. HA 加入整合
設定 → 裝置與服務 → 新增整合 → Android TV Remote
(這是 2023 之後的官方整合,取代了舊的 androidtv 自訂整合。)
輸入 IP,電視上會跳出配對碼,輸入即可。
能做什麼
- # 開關機
- - action: media_player.turn_on
- target: {entity_id: media_player.android_tv}
- # 送遙控按鍵
- - action: remote.send_command
- target: {entity_id: remote.android_tv}
- data:
- command:
- - DPAD_DOWN
- - DPAD_DOWN
- - DPAD_CENTER
- # 啟動特定 App
- - action: media_player.select_source
- target: {entity_id: media_player.android_tv}
- data:
- source: "Netflix"
- # 音量
- - action: media_player.volume_set
- target: {entity_id: media_player.android_tv}
- data: {volume_level: 0.3}
複製代碼
常用的按鍵代碼:
- HOME / BACK / MENU
- DPAD_UP / DOWN / LEFT / RIGHT / CENTER
- VOLUME_UP / VOLUME_DOWN / MUTE
- MEDIA_PLAY_PAUSE / MEDIA_NEXT / MEDIA_PREVIOUS
- POWER
狀態回報
Android TV Remote 整合可以知道:
- 電視開著還關著
- 目前在跑哪個 App(app_id 屬性)
- 播放狀態
- template:
- - binary_sensor:
- - name: 正在看 Netflix
- state: >
- {{ state_attr('media_player.android_tv', 'app_id')
- == 'com.netflix.ninja' }}
複製代碼
這個拿來做「看 Netflix 時自動調燈」很方便。

路線二:HDMI-CEC
CEC(Consumer Electronics Control)是 HDMI 線裡的一條控制線,
讓裝置之間可以互相控制。
你可能已經在用了:用機上盒的遙控器開電視、
或者插上 Chromecast 電視自動切換輸入 —— 那就是 CEC。
各廠牌的 CEC 名稱不同(這個很多人不知道):
- Sony —— BRAVIA Sync
- Samsung —— Anynet+
- LG —— SIMPLINK
- Panasonic —— VIERA Link
- Sharp —— Aquos Link
- Philips —— EasyLink
- Toshiba —— Regza Link
第一步:在電視設定裡把它打開(預設常常是關的)。
硬體:你需要一個 CEC 介面
- 樹莓派 —— 內建 CEC(HDMI 輸出本來就支援),最便宜
- Pulse-Eight USB-CEC Adapter —— 專用的,但比較貴
- 有些 HDMI 擷取卡
用樹莓派的話:
- sudo apt install cec-utils
- # 掃描 CEC 匯流排上有什麼
- echo 'scan' | cec-client -s -d 1
- # 開電視
- echo 'on 0' | cec-client -s -d 1
- # 關電視(待機)
- echo 'standby 0' | cec-client -s -d 1
- # 切換到某個輸入(把自己設為 active source)
- echo 'as' | cec-client -s -d 1
複製代碼
接進 HA
HA 曾經有內建的 HDMI-CEC 整合,
但它在較新的版本已經被移除了(維護困難)。
現在的做法有兩種:
做法 A:用 shell_command
- shell_command:
- tv_on: >
- ssh -i /config/ssh/id_rsa pi@192.168.1.60
- "echo 'on 0' | cec-client -s -d 1"
- tv_off: >
- ssh -i /config/ssh/id_rsa pi@192.168.1.60
- "echo 'standby 0' | cec-client -s -d 1"
複製代碼
做法 B:在樹莓派上跑一個小服務(推薦)
寫一個簡單的 HTTP 服務,接收指令並轉成 CEC:
- # /home/pi/cec_server.py
- from http.server import BaseHTTPRequestHandler, HTTPServer
- import subprocess, os
- TOKEN = os.environ.get('CEC_TOKEN', '')
- CMDS = {
- '/on': "on 0",
- '/off': "standby 0",
- '/active': "as",
- }
- class H(BaseHTTPRequestHandler):
- def do_POST(self):
- if self.headers.get('X-Token') != TOKEN:
- self.send_response(403); self.end_headers(); return
- cmd = CMDS.get(self.path)
- if not cmd:
- self.send_response(404); self.end_headers(); return
- subprocess.run(['cec-client', '-s', '-d', '1'],
- input=cmd.encode(), timeout=10)
- self.send_response(200); self.end_headers()
- self.wfile.write(b'ok')
- def log_message(self, *a):
- pass
- HTTPServer(('0.0.0.0', 8099), H).serve_forever()
複製代碼
加一個權杖檢查,不要讓內網任何人都能控制你的電視。
HA 這邊用 rest_command:
- rest_command:
- tv_on:
- url: "http://192.168.1.60:8099/on"
- method: POST
- headers:
- X-Token: !secret cec_token
- tv_off:
- url: "http://192.168.1.60:8099/off"
- method: POST
- headers:
- X-Token: !secret cec_token
複製代碼
比 shell_command 好:不依賴 HA 容器裡有沒有 ssh、
錯誤訊息清楚、而且可以加驗證。

CEC 的限制(要有心理準備)
- 各廠牌實作不一致 —— 同樣的指令在不同電視上行為可能不同
- 有些功能只有單向 —— 可以開機但不知道現在是開是關
- 會有意外的連動 —— 關電視的時候可能把音響也一起關了
- HDMI 線材品質會影響 —— 便宜的線可能沒接 CEC 那條腳位
- 切換器 / 分配器常常會斷掉 CEC
所以我的建議是:
- 有 ADB 或官方整合就用那個,CEC 當備案
- CEC 適合「只想要開關機」的簡單需求
- 舊電視沒有別的辦法時才用
路線三:紅外線(最後手段)
用萬用紅外線遙控器(Broadlink、或 ESP32 + IR 模組)學碼。
優點:什麼電視都能用。
缺點:
- 完全單向 —— 不知道電視現在是開是關
- 要對準(或者裝在電視附近)
- 切換輸入之類的多步驟操作容易失步
補救單向問題的方法:
- 配一個功率監控插座(電視開著功率明顯不同)
- 或者一個光敏電阻貼在電視的電源指示燈上
- template:
- - binary_sensor:
- - name: 電視開著
- unique_id: tv_is_on
- state: >
- {{ states('sensor.tv_power') | float(0) > 30 }}
- delay_off: "00:00:30"
複製代碼
有了這個之後,紅外線的「切換」就可以變成「確保開/關」:
- script:
- ensure_tv_on:
- sequence:
- - if:
- - condition: state
- entity_id: binary_sensor.電視開著
- state: "off"
- then:
- - action: remote.send_command
- target: {entity_id: remote.ir_blaster}
- data:
- device: tv
- command: power
- - wait_template: >
- {{ is_state('binary_sensor.電視開著','on') }}
- timeout: "00:00:20"
複製代碼
實用的自動化
看電視時自動調燈:
- alias: 看電視調燈
- triggers:
- - trigger: state
- entity_id: binary_sensor.電視開著
- to: "on"
- for: "00:02:00"
- conditions:
- - condition: sun
- after: sunset
- actions:
- - action: light.turn_on
- target: {entity_id: light.living_room_main}
- data: {brightness_pct: 25, transition: 5}
- - action: light.turn_on
- target: {entity_id: light.screen_bias}
- data: {brightness_pct: 12, color_temp_kelvin: 6500}
- mode: single
複製代碼
太晚了提醒:
- alias: 看太晚提醒
- triggers:
- - trigger: time
- at: "23:30:00"
- conditions:
- - condition: state
- entity_id: binary_sensor.電視開著
- state: "on"
- actions:
- - action: media_player.volume_set
- target: {entity_id: media_player.tv}
- data: {volume_level: 0.15}
- - action: script.smart_announce
- data:
- area: 客廳
- message: 已經十一點半了
- mode: single
複製代碼
(降低音量比直接關掉溫和多了,而且不會被家人討厭。)
---
我家的電視是 Android TV,所以用 ADB 整合,功能最完整。
但我還是留了一個紅外線遙控器的備案,
因為 ADB 整合偶爾會在電視系統更新後失效。
任何單一控制路徑都會有失效的一天,留個備案比較安心。 |
|