この手順の目次
SH-02Eのアプリから家電を操作でき、Wi-Fi ADBと中継APIが稼働していること。中継はLinuxホストの127.0.0.1:8766で待ち受ける。以下の配布ファイルはHome Assistant側の接続例で、端末初期化・アプリ・中継サーバーそのもののインストーラーではありません。
1. 設定例を取得する
このページは新規のテスト用Home Assistantを使う例。既存のHome Assistantが動いている場合、同じ8123番で二つ起動せず、rest_commandとscriptなど必要な項目だけを既存設定へ統合する。公式のLinux導入手順でDocker Engineを準備しておく。
mkdir -p ir-lab/ha-config
cd ir-lab
curl -fSLo compose.yaml \
https://hacks.hacci.dev/sh-02e-ir-remote/examples/compose.example.yaml
curl -fSLo ha-config/configuration.yaml \
https://hacks.hacci.dev/sh-02e-ir-remote/examples/configuration.example.yaml
curl -fSLo ha-config/ui-lovelace.yaml \
https://hacks.hacci.dev/sh-02e-ir-remote/examples/ui-lovelace.example.yaml
# 実行前にファイル内容を読む
cat compose.yaml
cat ha-config/configuration.yaml
cat ha-config/ui-lovelace.yaml
docker compose version配布ファイルのSHA-256一覧も用意した。ファイル内容を読んでから使用する。
コンテナはLinuxのhost networkを使うため、コンテナからの127.0.0.1が中継ホストと一致する。Docker Desktopや別ホストの中継へ、同じ前提を当てはめない。サーバーには空いている8123番が必要。
compose.yamlの内容
# Linux Docker Engine. Requires an existing relay on host loopback:8766.
# This example does not install the Android app, kernel module or relay.
name: ir-lab-ha
services:
homeassistant:
image: ghcr.io/home-assistant/home-assistant:2026.9.4
restart: unless-stopped
network_mode: host
environment:
TZ: Asia/Tokyo
volumes:
- ./ha-config:/config
security_opt:
- no-new-privileges:true
mem_limit: 2g
logging:
driver: json-file
options:
max-size: 10m
max-file: '3'2. 自分のIP・トークン・機器IDを設定する
中継APIの既存トークンと、LAN上のサーバー自身のIPを入力する。ここで新しいトークンを勝手に生成すると、稼働中の中継と一致しない。機器IDはAndroidアプリと中継の両方が許可した値を使う。
umask 077
read -rp 'Server LAN IP (bind address): ' IR_HA_IP
read -rsp 'Existing relay token: ' IR_RELAY_TOKEN; echo
read -rp 'Registered light device ID: ' IR_LIGHT_ID
export IR_HA_IP IR_RELAY_TOKEN IR_LIGHT_ID
python3 - <<'CONFIG'
import ipaddress, json, os, re
from pathlib import Path
ip = str(ipaddress.ip_address(os.environ['IR_HA_IP']))
token = os.environ['IR_RELAY_TOKEN']
if not re.fullmatch(r'[0-9a-f]{64}', token):
raise SystemExit('Expected the existing 64-character relay token')
identifier = os.environ['IR_LIGHT_ID']
if not re.fullmatch(r'[A-Za-z0-9_-]+', identifier):
raise SystemExit('Invalid device ID')
p = Path('ha-config/secrets.yaml')
p.write_text('ha_bind_ip: ' + json.dumps(ip) + '\n' +
'ir_relay_authorization: ' + json.dumps('Bearer ' + token) + '\n')
p.chmod(0o600)
p = Path('ha-config/ui-lovelace.yaml')
p.write_text(p.read_text().replace('REGISTERED_LIGHT_ID', identifier))
CONFIG
unset IR_RELAY_TOKEN
# secrets.yamlの内容を画面に出したり、公開ディレクトリへ置かない
ls -l ha-config/secrets.yaml機器IDを誤った場合、表示名だけが正しくても送信は400で拒否される。このサンプルには家庭内の実IP・実トークン・部屋名を含めていない。
3. RESTコマンドとスクリプトの役割
rest_commandが中継へJSONを送り、script.ir_sendが失敗応答をエラーとして扱う。照明には温度を付けず、cool / heatだけに整数温度を付ける。端末アプリ側でも値を検証する。
# New Home Assistant test instance only. Merge sections into existing installations.
# Prerequisite: initialized SH-02E, registered device IDs, and a running relay on this host.
homeassistant:
name: IR Lab
time_zone: Asia/Tokyo
unit_system: metric
frontend:
config:
http:
server_host: !secret ha_bind_ip
server_port: 8123
lovelace:
mode: yaml
rest_command:
ir_relay_send:
url: http://127.0.0.1:8766/send
method: POST
headers:
Authorization: !secret ir_relay_authorization
content_type: application/json
payload: >-
{% if command in ['cool', 'heat'] %}
{{ dict(device=device, command=command, temperature=temperature | int) | to_json }}
{% else %}
{{ dict(device=device, command=command) | to_json }}
{% endif %}
timeout: 12
script:
ir_send:
alias: IR signal send
mode: parallel
max: 10
sequence:
- action: rest_command.ir_relay_send
data:
device: "{{ device }}"
command: "{{ command }}"
temperature: "{{ temperature | default(26) }}"
response_variable: reply
- if: "{{ reply.status | default(0) | int != 200 }}"
then:
- stop: "IR send failed or outcome unknown. Not retried."
error: true4. 設定を検証して起動する
# 先に設定検証する。コンテナの起動・公開はまだ行わない
docker compose run --rm --no-deps homeassistant \
python -m homeassistant --script check_config --config /config
# 成功したら起動する
docker compose up -d
docker compose ps
docker compose logs --tail=50 homeassistant同じLANのブラウザーでhttp://<SERVER_LAN_IP>:8123/を開き、初回だけローカルアカウントを作る。ダッシュボードに点灯/全灯・常夜灯・消灯が表示される。実際に送信する前に、次の準備確認を行う。
5. APIの準備状態を確認する
# 中継ホスト上で実行。トークンを再入力する
read -rsp 'Relay token: ' IR_RELAY_TOKEN; echo
export IR_RELAY_TOKEN
curl --fail-with-body --max-time 20 \
-H "Authorization: Bearer ${IR_RELAY_TOKEN}" \
http://127.0.0.1:8766/health{"ready":true,"busy":false,"last_sent":null}200であってもready=falseなら端末準備が整っていない。busy=trueなら別処理中で新しい端末確認を省略している。last_sentがnull以外でも、家電の現在の状態を示すものではない。
6. まず1つの信号を送る
SH-02Eの背面赤外線ポートを家電へ向ける。次のコマンドは実際の送信を伴う。IR_LIGHT_IDは手順2で入力した値である。
IR_BODY=$(python3 -c 'import json,os; print(json.dumps({"device":os.environ["IR_LIGHT_ID"],"command":"nightlight"}))')
curl --fail-with-body --max-time 15 \
-X POST http://127.0.0.1:8766/send \
-H "Authorization: Bearer ${IR_RELAY_TOKEN}" \
-H 'Content-Type: application/json' \
--data "$IR_BODY"
unset IR_RELAY_TOKEN IR_BODY{"sent":true,"appliance_response_verified":false}確認は「APIが成功した」と「家電が常夜灯になった」の2段階で記録する。400は入力、401は認証、409は同時実行、503は失敗または結果不明。503やタイムアウトを見て自動再試行しない。
7. Web UIでボタンとして操作する
次のカードはオン・オフの状態を持たず、押すたびに操作する。常夜灯にしてから、別の操作をしても表示をリセットする必要がない。AlexaのHue互換トグルとは異なり、Home AssistantではこのボタンUIを直接使える。
ダッシュボードの3ボタン設定
# Replace REGISTERED_LIGHT_ID with the ID allowed by your relay and Android app.
title: IR Lab
views:
- title: リモコン
path: remote
cards:
- type: markdown
content: >-
ボタンは信号を1回実行します。家電の実際の状態は検知しません。
- type: grid
columns: 3
square: false
cards:
- type: button
name: 点灯/全灯
icon: mdi:lightbulb-on
show_state: false
tap_action:
action: perform-action
perform_action: script.ir_send
data:
device: REGISTERED_LIGHT_ID
command: 'on'
hold_action: {action: none}
- type: button
name: 常夜灯
icon: mdi:weather-night
show_state: false
tap_action:
action: perform-action
perform_action: script.ir_send
data:
device: REGISTERED_LIGHT_ID
command: nightlight
hold_action: {action: none}
- type: button
name: 消灯
icon: mdi:lightbulb-off
show_state: false
tap_action:
action: perform-action
perform_action: script.ir_send
data:
device: REGISTERED_LIGHT_ID
command: 'off'
hold_action: {action: none}機器IDはダウンロード後に設定した値へ置き換わる。ボタンを増やすなら、同じ形でcommandをmemory1、brightness_upなど許可済みの操作に変更する。エアコンでは入力値を変更しただけで送信せず、最後に送信ボタンを押す設計にする。
8. 別プログラムからHome Assistant APIを使う
Home Assistantのプロフィールで長期アクセストークンを作成する。中継トークンとは別物。APIの詳細は公式REST API資料を参照。
read -rp 'Home Assistant base URL: ' HA_BASE_URL
read -rsp 'Home Assistant access token: ' HA_TOKEN; echo
# 例: 信頼するLAN内の http://<SERVER_LAN_IP>:8123
IR_BODY=$(python3 -c 'import json,os; print(json.dumps({"device":os.environ["IR_LIGHT_ID"],"command":"nightlight"}))')
curl --fail-with-body --max-time 20 \
-X POST "${HA_BASE_URL%/}/api/services/script/ir_send" \
-H "Authorization: Bearer ${HA_TOKEN}" \
-H 'Content-Type: application/json' \
--data "$IR_BODY"
unset HA_TOKEN IR_BODYHome Assistantの応答は中継のsent JSONとは異なり、変更された状態のリストなどが返る。/api/states/...へonと書き込むだけでは家電操作にならない。スクリプトのサービスを呼ぶ。
9. 自作Web UIと端末内HTTPサーバー
自作画面なら、ブラウザー → ログイン管理する自作バックエンド → 中継APIという順に接続する。中継トークンはバックエンドだけで保持する。ブラウザーの127.0.0.1は閲覧端末自身なので、中継のループバックへ直接fetchする実装にはしない。
SH-02Eの中にHTTPサーバーを置く方式は未実装の拡張案。API16対応のHTTP実装、INTERNET権限、認証、送信排他、foreground service、CPU / Wi-Fiロックが必要になる。今回のダウンロード例はその実装ではない。