起因#
借りているアパートには美的エアコンが設置されていますが、残念ながらスマートホームの接続には対応していません。
気温が上がるにつれて、毎日エアコンのスイッチを入れたり切ったりする微妙な手間に悩まされています。ほとんどの時間は手を伸ばすだけですが、それでもインターネットサーフィンの体験が中断されてしまいます。加えて、この不運なデバイスは前回の風速を自動的に記憶できないため、スイッチを切った後に自分の好みに合わせて風速を再調整する必要があり、その不満は日々増していきました。
ついに先週、仕事から帰ってきたときに外出時にエアコンを切り忘れたことに気づき、電気代が心配になりました。それで、棚の上でほこりをかぶっているラズベリーパイを見て、思い切っていじってみることにしました。
追加材料#
- 赤外線受信管(リモコンの赤外信号を記録)
- 赤外線発信管(制御信号を発信)
- デュポン線(接続用)
- トランジスタ(オプション、信号を強化できると言われていますが、私は使用しませんでした)
ソフトウェアのインストール#
私のデバイスとシステム情報は以下の通りです:
ubuntu@ubuntu:~$ uname -a
Linux ubuntu 5.15.0-1027-raspi #29-Ubuntu SMP PREEMPT Mon Apr 3 10:12:21 UTC 2023 aarch64 aarch64 aarch64 GNU/Linux
まず、lirc
関連のパッケージをインストールします。
sudo apt update
sudo apt install lirc
インストールが完了したら、config
を設定します。このステップのチュートリアルでは多くの場合/boot/config.txt
の位置が示されていますが、私の環境ではそうではないので、注意が必要です。
sudo vi /boot/firmware/config.txt
# 以下の内容を追加
dtoverlay=gpio-ir,gpio_pin=18
dtoverlay=gpio-ir-tx,gpio_pin=17
lirc の設定を変更します。
sudo vi /etc/lirc/lirc_options.conf
# 変更前
driver = devinput
device = auto
# 変更後
driver = default
device = /dev/lirc0
操作が完了したら、ラズベリーパイを再起動して設定を有効にします。
ハードウェア接続#
資料を調べると、ラズベリーパイの具体的なピン定義は以下の通りです:
赤外線受信管の接続#
赤外線受信管の凸部を上に向けて、左から右に、ピンはそれぞれデータ、負極、正極です。データピンはデュポン線で GPIO18 に接続し、負極はグラウンドに、正極は 3.3V 電源に接続します。
赤外線発信管の接続#
発信管の状態は図の通りで、長い脚が正極で GPIO17 に接続し、短い脚はグラウンドに接続します。
赤外線信号関連#
信号記録#
エアコンを制御するための最初のアイデアは、赤外線管を使ってリモコンのボタン信号を模倣し、その後エンコードして制御することです。
信号を模倣するためには、まずそれを記録する必要があります。ターミナルでmode2 -m -d /dev/lirc1
を実行すると、記録を開始できます。このとき、リモコンのボタンを押すと、画面に以下のような出力が表示されます:
ubuntu@ubuntu:/boot/firmware$ mode2 -m -d /dev/lirc1
Using driver default on device /dev/lirc1
Trying device: /dev/lirc1
Using device: /dev/lirc1
16777215
4475 4380 576 1580 574 497
579 1580 582 1576 571 500
584 498 576 1578 570 497
585 491 579 1575 580 498
580 496 580 1575 580 1585
570 496 581 1582 571 1575
583 493 586 1582 566 1582
573 1576 579 1575 579 1575
579 1581 573 497 579 1577
578 496 580 498 579 497
582 503 574 497 575 498
579 499 579 1575 578 498
580 498 584 491 580 497
578 498 578 507 579 1586
567 504 573 1581 588 1561
578 1575 583 1571 580 1576
579 1576 573 5184 4422 4409
573 1581 549 524 580 1577
576 1579 577 497 577 502
556 1600 553 568 505 543
558 1586 570 497 575 502
558 1597 550 1606 552 521
555 1629 549 1600 529 542
532 1605 552 1600 555 1624
530 1602 555 1625 550 1578
553 542 530 1627 554 520
530 545 533 545 528 546
533 542 549 529 531 547
533 1623 528 547 528 547
531 545 532 545 556 521
532 542 531 1631 528 545
529 1623 531 1624 532 1623
531 1625 555 1600 528 1626
532 5224 4401 4434 525 1627
529 1624 527 550 529 1626
522 545 531 1624 531 545
532 1624 530 545 532 1624
531 1624 531 545 532 545
532 1624 530 1630 525 545
531 545 531 548 529 545
531 546 531 547 532 552
535 538 531 548 530 544
532 545 529 548 530 543
532 547 532 549 529 547
531 538 531 553 523 546
531 546 530 546 534 543
530 546 532 553 528 543
534 543 531 546 530 1626
526 1624 530 1628 526 547
530 1625 536 1623 524 17394-pulse
最初の行の16777215
と最後の17394-pulse
を捨てると、残りのデータが現在のボタンが表す情報(例えば、ここでは冷房、24 度、風速 1%)になります。
設定ファイルの作成#
これをもとに、自分の設定を作成できます:
sudo vi /etc/lirc/lircd.conf.d/aircon.lircd.conf
# 内容は以下の通り:
begin remote
name aircon // デバイス名は自由に変更可能
flags RAW_CODES
eps 30
aeps 100
gap 19991
begin raw_codes
name c_25_1
4469 4386 578 1574 581 496 580 1577 577 1574 580 497 584 494 578 1574 580 497 580 497 580 1575 580 496 580 498 578 1575 580 1574 580 496 580 1575 579 1574 580 499 579 1575 579 1575 579 1575 580 1575 581 1573 580 1574 579 498 580 1577 577 498 579 497 582 508 570 493 580 497 581 496 579 1575 579 1575 580 498 579 497 580 496 556 521 579 498 581 496 580 497 579 497 580 1575 579 1577 578 1577 577 1575 579 1576 580 1576 580 5174 4449 4383 581 1574 555 520 579 1576 579 1577 577 501 577 496 579 1576 555 521 579 498 556 1598 580 499 578 497 556 1598 556 1599 555 521 556 1601 554 1599 579 501 554 1597 555 1599 579 1576 555 1599 578 1576 579 1575 556 521 579 1577 577 499 577 522 556 497 555 544 532 545 532 521 582 1575 554 1599 556 545 531 522 578 497 578 499 556 521 556 521 578 498 555 522 554 1600 578 1578 578 1576 554 1599 555 1623 531 1623 532 5201 4423 4408 555 1600 555 1623 531 545 531 1623 532 547 531 1622 555 521 532 1623 533 544 532 1623 532 1623 532 545 531 545 556 1599 531 1623 531 545 532 545 557 520 532 545 531 545 532 545 556 520 532 546 531 545 531 545 531 545 532 545 531 545 531 546 531 546 531 545 532 545 532 546 531 546 556 521 531 549 529 546 529 545 533 544 531 545 532 545 532 544 531 1623 532 1623 531 1629 526 546 531 1624 531 1623 531
name off
4465 4388 578 1574 580 496 583 1572 580 1577 580 496 578 497 580 1575 580 496 581 496 580 1574 581 496 581 496 581 1577 578 1574 581 502 574 1575 579 496 584 1571 581 1574 581 1574 581 1575 580 496 580 1575 580 1574 580 1575 583 494 582 495 580 497 580 498 578 1574 580 497 580 497 580 1575 580 1576 579 1574 580 498 582 495 580 497 581 497 580 499 578 497 581 497 578 497 582 1572 580 1576 581 1574 579 1576 579 1575 580 5179 4450 4382 579 1575 579 500 577 1575 580 1576 578 497 556 521 580 1577 580 496 580 497 579 1579 576 497 579 506 574 1576 552 1599 581 496 579 1576 579 498 581 1575 578 1579 576 1576 579 1577 578 498 579 1575 580 1575 579 1577 555 521 556 521 579 498 556 524 578 1576 577 498 579 498 556 1599 556 1599 579 1576 578 498 579 499 555 522 555 521 556 521 556 522 578 497 556 522 558 1597 579 1575 558 1597 555 1602 576 1576 579
end raw_codes
end remote
ここでは 2 つのコマンドを定義しています:c_25_1 は冷房、25 度、1% 風速を表し、off はエアコンをオフにします。
ファイルを保存したら、sudo systemctl restart lircd
を実行してサービスを再起動し、設定を有効にします。
これで、ターミナルでコマンドを送信することができます:irsend send_once aircon c_25_1
でエアコンを制御できます。
コードの理解#
無思考でコードをコピーするのは便利ですが、何かすっきりしない感じがあります。そこで、具体的な意味を分析してみましょう。
注意:以下の内容はすべて《美的 R05D/BG 型リモコン電控機能仕様書》に基づいて分析したものです。興味のある方は原文をお読みください。
具体的な構造#
収集した資料によると、温度
、モード
、風力強弱(具体的な風速ではない)
に関わる場合、エンコードの構造は大体次のようになります。
LAA'BB'CC'SLAA'BB'CC'Z
ここで、次のように設定できます:
L はガイドコードで、信号[4500, 4500]
に対応します。
S は区切りコードで、信号[540, 5200]
に対応します。
Z は終了識別子で、信号550
に対応します。
A は固定の識別コードで、バイナリシーケンス10110010
に対応します。
B は風速に関連し、C は温度やモードに関連します。
さらに、バイナリシーケンスと信号エンコードには相互関係があります:1 は高電圧を表し、信号[540, 1600]
に対応し、0 は低電圧を表し、信号[550, 550]
に対応します。
したがって、上記の A(識別コード)は次のデータに対応します:540 1600 550 550 540 1600 540 1600 550 550 550 550 540 1600 550 550
。
データ全体は 2 つのセクションに分かれ、ガイドコードと区切りコードを除いて、2 つのデータの内容は完全に一致します。ボタンを押すたびに、風速や温度を調整するための情報が含まれています。
エンコード領域の関係#
注意:ここでは図の仕様に基づいており、実際の状況については議論しません。
仕様書によると、大体次の関係が存在します:
これにより、データABC
を次のように記述できます:
10110010 10011111 01000000
これを翻訳すると、
固定識別コード 低風 冷房 24度
データ構造はAA'BB'CC'
であり、ここで X' は X の反コードを表します。したがって、次のように拡張できます:
10110010 01001101 10011111 01100000 01000000 10111111
上記の高低電圧ルールに従って変換すると、LAA'BB'CC'
のルールは次のようになります:
4500 4500 540 1600 550 550 540 1600 540 1600 550 550 550 550 540 1600 550 550 550 550 550 550 540 1600 550 550 550 550 540 1600 540 1600 550 550 540 1600 550 550 540 1600 550 550 550 550 540 1600 540 1600 540 1600 540 1600 540 1600 550 550 550 550 540 1600 540 1600 550 550 550 550 550 550 550 550 550 550 550 550 550 550 540 1600 550 550 550 550 550 550 550 550 550 550 550 550 550 550 540 1600 550 550 540 1600 540 1600 540 1600 540 1600 540 1600 540 1600 550
構造に従ってさらに拡張すると、LAA'BB'CC'SLAA'BB'CC'Z
のルールは次のようになります:
4500 4500 540 1600 550 550 540 1600 540 1600 550 550 550 550 540 1600 550 550 550 550 550 550 540 1600 550 550 550 550 540 1600 540 1600 550 550 540 1600 550 550 540 1600 550 550 550 550 540 1600 540 1600 540 1600 540 1600 540 1600 550 550 550 550 540 1600 540 1600 550 550 550 550 550 550 550 550 550 550 550 550 550 550 540 1600 550 550 550 550 550 550 550 550 550 550 550 550 550 550 540 1600 550 550 540 1600 540 5200 4500 4500 540 1600 540 1600 540 1600 540 1600 540 1600 550 550 540 1600 550 550 540 1600 540 1600 550 550 550 550 540 1600 550 550 550 550 550 550 540 1600 550 550 550 550 540 1600 540 1600 550 550 540 1600 550 550 540 1600 550 550 550 550 540 1600 540 1600 540 1600 540 1600 540 1600 550 550 550 550 540 1600 540 1600 550 550 550 550 550 550 550 550 550 550 550 550 550 550 540 1600 550 550 550 550 550 550 550 550 540 5200 4500 4500 550 550 550 550 550 550 540 1600 550 550 540 1600 540 1600 540 1600 540 1600 540 1600 540 1600 550
理解の進展#
ここまでのルールを理解した後、さまざまな組み合わせを自動生成するスクリプトを作成できると思いましたが、実際にはできません。
調べた資料の公開日は 2008 年で、今から 15 年も前のことです。部分的なルールは照合できますが、多くの詳細には違いがあります。
最も顕著な違いは、私のエアコンは具体的な風速レベルを調整できることです。1% から 100% まで調整可能です。この部分の赤外線エンコードをキャッチした後、フォーマットは次のようになっていることがわかりました:
LAA'BB'CC'SLAA'BB'CC'SLDEFNNGZ
これにより、データの長さが両端から 3 つのセクションに拡張され、3 つ目のセクションはもはやAA'BB'CC'
のような相互反転構造ではなくなりました。
そこで、mode2 -m -d /dev/lirc1 | tee -a output.conf
コマンドを使用して、同じモードと温度の下で風速を 1 から 100 まで記録し、スクリプトを使用してバイナリシーケンスに変換し、規則を探しました。
結論を直接述べると、追加データに関しては、大体次のような規則があります:
追加ブロックの最初の行は固定11010101
2 行目は風速のパーセンテージのバイナリ(左側を0
で埋める)
3 行目は固定で0
を埋める
4 行目は風速が100
のときのみ00000010
で、他の時は0
を埋める
5 行目は固定で0
を埋める
6 行目は 10 進数の214
から埋め始め、255
になると1
から始まり、99
まで埋めて56
になり、100
は特別な値で59
に対応します(実際にはすべてバイナリ表現に変換されます)。
私は個人的に
温度
、モード
、風速
の 3 つのパラメータが必要なだけなので、資料の欠如により、さらに深く研究することはありませんでした。
これにより、1~100
の風速、17~30
の温度、冷房/暖房
モードの異なる組み合わせコマンドを生成するスクリプトをかろうじて作成できるようになりました。
自動化の探求#
多くの研究を行いましたが、実際のニーズの推進には理想的ではありませんでした。結局、私が必要としているのはエアコンを便利に制御することであり、リモコンを模倣することではありません。
そこで、思考をさらに広げてみます:
API 呼び出し#
ある程度のスマート / 自動化を実現するための最も簡単で実現しやすい方法は、API インターフェースを公開して、サードパーティサービスが呼び出せるようにすることです。
時間の都合上、ここでは golang を使用して、できるだけ最小限の実装を行います:
// main.go ファイル
package main
import (
"net/http"
"github.com/gin-gonic/gin"
)
var isON = false
func setupRouter() *gin.Engine {
r := gin.Default()
r.GET("/aircon/:mode/:temp/:flow", func(c *gin.Context) {
mode := c.Params.ByName("mode")
temp := c.Params.ByName("temp")
flow := c.Params.ByName("flow")
cmd := mode + "_" + temp + "_" + flow
isON = true
IrsenAircon(cmd)
c.JSON(http.StatusOK, gin.H{"cmd": cmd})
})
r.GET("/aircon/off", func(c *gin.Context) {
IrsenAircon("off")
isON = false
c.JSON(http.StatusOK, gin.H{"cmd": "off"})
})
r.GET("/aircon/status", func(c *gin.Context) {
var result string
if isON {
result = "1"
} else {
result = "0"
}
c.String(http.StatusOK, result)
})
return r
}
func main() {
IrsenAircon("off")
r := setupRouter()
r.Run(":9997")
}
// aircon.go ファイル
package main
import (
"fmt"
"log"
"os/exec"
)
func IrsenAircon(cmd string) {
cmdOutput, err := exec.Command("irsend", "send_once", "aircon", cmd).Output()
if err != nil {
log.Fatal(err)
}
fmt.Printf("%s", cmdOutput)
}
上記のコードをラズベリーパイ 4B で実行可能なバイナリにコンパイルします:
export GOARCH=arm64
export GOROOT_BOOTSTRAP=/usr/local/go
export GOOS=linux
go build
コンパイルしたバイナリファイルをラズベリーパイにアップロードします。
これら 2 つのファイルが実現する内容は非常にシンプルです:9997 ポートでインターフェースを公開し、GET リクエストを通じて異なるコマンドを組み立て、システム内のirsend
バイナリファイルに渡して、対応する赤外線信号を送信します。
注意すべき点は、現在のシーン情報を含む信号を送信すると、エアコンが直接オンになります。したがって、単独のオン
コマンドは存在しませんが、固定のオフ
コマンドは存在します。
私のラズベリーパイの内部 IP は192.168.2.224
です。したがって、インターフェースに基づいて、3 つのコマンドがあります:
# エアコンを25度、冷房、風速1%に設定
➜ Desktop curl http://192.168.2.224:9997/aircon/c/25/1
{"cmd":"c_25_1"}⏎
# エアコンをオフにする
➜ Desktop curl http://192.168.2.224:9997/aircon/off
{"cmd":"off"}⏎
# ステータスを確認する(0はオフ、1はオンを表す)
➜ Desktop curl http://192.168.2.224:9997/aircon/status
0⏎
エアコンはラズベリーパイに自身の現在の状態をコールバックすることができず、またその現在の動作情報を積極的に探ることもできないため、信号を送信する操作が実行されると、それが成功したと見なされ、内部で維持されるオン / オフの状態が更新されます。状態の正確性をできるだけ保つために、プログラムを起動する際にエアコンを一度オフにする操作を実行してキャリブレーションを行います。
最後に、pm2 を使用して対応するプロセスを監視します:
pm2 --name lirc-web start /mnt/sda/Downloads/lirc-web
# 指示に従って自動起動を設定
pm2 startup
sudo env PATH=$PATH:/home/ubuntu/.nvm/versions/node/v18.13.0/bin /home/ubuntu/.nvm/versions/node/v18.13.0/lib/node_modules/pm2/bin/pm2 startup systemd -u ubuntu --hp /home/ubuntu
「スマートホーム」#
API インターフェースを実現しましたが、それがすべてのニーズを解決するわけではありません。エアコンをブラウザでURLにアクセスする
かコマンドラインでcurlを発行する
ことで制御するのでは、リモコンを使った方がまだ良いです。
macOS と iPadOS にはホーム
アプリが標準で搭載されており、スマートホームの連動制御が可能です。したがって、上記の簡素なインターフェースをHomeKit
に接続すれば、利便性をさらに向上させることができます。
HomeBridge#
このステップを完了するために、HomeBridge
アプリを使用します。公式の説明は以下の通りです:
Homebridge は、HomeKit をサポートしていないスマートホームデバイスと統合することを可能にします。2,000 以上の Homebridge プラグインがあり、数千の異なるスマートアクセサリをサポートしています。
無駄話はせず、直接Docker-Compose
で一気に進めます:
cd ~/docker/homebridge/
vi docker-compose.yml
# 以下の内容を記述:
version: '3'
services:
homebridge:
image: oznu/homebridge:ubuntu
container_name: homebridge
restart: always
network_mode: host
environment:
- HOMEBRIDGE_CONFIG_UI_PORT=10000
volumes:
- homebridge:/homebridge
volumes:
homebridge:
保存後、docker-compose up -d
を実行し、イメージのプルが完了するのを待つと、自動的に実行が開始されます。
このアプリのインストールと実行には NPM リポジトリへのアクセスが必要です。ネットワークに問題がある場合、アクセスに失敗すると起動できなくなります。プロキシを設定するか、ソースを変更するなどの操作を行ってください。ただし、サービスの起動に失敗しても、UI へのアクセスには影響がないため、ブラウザでログを確認することはできます。
少し待つと、http://<server ip>:10000
にアクセスしてバックエンドインターフェースに入ることができます。
アクセサリーの設定#
ここでは、最小限のニーズシナリオに従って、エアコンの複雑な操作を 2 つに簡素化します —— オンとオフ。オンは
25度、冷房、風速1%
に対応し、オフはエアコンをオフにします。より複雑な実装は自分で探求してください。
HTTP インターフェースを呼び出すために、プラグインhomebridge-http
をインストールする必要があります。
インストールが完了したら、バックエンドで以下の設定を行います:
{
"bridge": {
"name": "Homebridge",
"username": "1D:42:45:4B:E4:A4",
"port": 51177,
"pin": "XXX-XX-XXX",
"advertiser": "bonjour-hap"
},
"accessories": [
{
"accessory": "Http",
"name": "Media Aircon",
"switchHandling": "realtime",
"on_url": "http://192.168.2.224:9997/aircon/c/25/1",
"off_url": "http://192.168.2.224:9997/aircon/off",
"status_url": "http://192.168.2.224:9997/aircon/status"
}
],
"platforms": [
{
"name": "Config",
"port": 10000,
"platform": "config"
}
]
}
ここで主にaccessories
フィールドに新しいオブジェクトを追加します。on_url
、off_url
、status_url
はそれぞれオン、オフ、ステータス確認に使用するインターフェースを表します。もちろん、プラグインはさらに多くのパラメータをサポートしており、具体的な内容は GitHub リポジトリの説明を確認してください。
設定が完了したら、HomeBridge サービスを再起動し、家庭アプリを開いてバックエンドに表示される QR コードをスキャンすれば、デバイスを発見できます。
この時、状態を正常に取得し、オンオフ操作を行うことができます。
音声制御#
では、さらに進んで、例えばベッドに横になって手を上げたくないときに音声制御が非常に便利です。
非常に簡単で、ショートカット
を使用すれば完了します。
もちろん、HTTP API を提供しているため、複雑な方法は必要なく、直接呼び出すことができます:
エアコンをオンにする:
エアコンをオフにする:
これで、Siri にショートカットの名前を言うだけで使用できるようになります。
考察とまとめ#
もともとは Flutter を使用してアプリ + Web のフロントエンドアプリを実現する予定でしたが、突然 Apple 系のエコシステムを思い出し、途中でニーズを変更しました。しかし、これにより Android の携帯電話での操作が非常に便利ではなくなりました。とはいえ、HomeKit との組み合わせは比較的快適で、得るものと失うものがあるといえるでしょう。
時間の都合や、夜にまた空港で待機していることもあり、コードの面では粗雑で、動けば良いという原則に従っています。今後は少なくとも以下のいくつかの方向で改善が必要です:
-
API 層に認証システムを追加し、
Cloudflare-Tunnel
を使用して外部ネットワークにトンネルを通し、真のリモート制御を実現する。 -
赤外線エンコードの面で、より多くの一般的な組み合わせを完成させ、関連するライブラリを使用して、外部バイナリを粗暴に呼び出すのではなく、直接赤外線エンコードデータを送信する。
-
HomeBridge 層では、さらに多くの機能を拡張し、自動指令と組み合わせて、現在のように単なる電球として扱うのではなく、より精緻な制御を実現する。
-
定時タスクを設定し、指定された時間帯に自動的にオン / オフを行う:ラズベリーパイには
青龍面板
が展開されているので、簡単にスクリプトを書くだけで実現できます。 -
外観の修正:ええ、インダストリアルデザインが使えないわけではありませんが、実際にその才能がないので、諦めます。
総じて、波折は多かったものの、最終的な実現は急いで行ったものでしたが、意外にも自分自身は満足しており、少なくとも時間を無駄にしたわけではないと感じています。