道阻且长

道阻且长

问君西游何时还,畏途巉岩不可攀。
twitter
github

ラズベリーパイ+赤外線管に基づく擬似スマートホームの実現

起因#

借りているアパートには美的エアコンが設置されていますが、残念ながらスマートホームの接続には対応していません。

気温が上がるにつれて、毎日エアコンのスイッチを入れたり切ったりする微妙な手間に悩まされています。ほとんどの時間は手を伸ばすだけですが、それでもインターネットサーフィンの体験が中断されてしまいます。加えて、この不運なデバイスは前回の風速を自動的に記憶できないため、スイッチを切った後に自分の好みに合わせて風速を再調整する必要があり、その不満は日々増していきました。

ついに先週、仕事から帰ってきたときに外出時にエアコンを切り忘れたことに気づき、電気代が心配になりました。それで、棚の上でほこりをかぶっているラズベリーパイを見て、思い切っていじってみることにしました。

追加材料#

  • 赤外線受信管(リモコンの赤外信号を記録)
  • 赤外線発信管(制御信号を発信)
  • デュポン線(接続用)
  • トランジスタ(オプション、信号を強化できると言われていますが、私は使用しませんでした)

ソフトウェアのインストール#

私のデバイスとシステム情報は以下の通りです:

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

操作が完了したら、ラズベリーパイを再起動して設定を有効にします。

ハードウェア接続#

資料を調べると、ラズベリーパイの具体的なピン定義は以下の通りです:

image

赤外線受信管の接続#

image

赤外線受信管の凸部を上に向けて、左から右に、ピンはそれぞれデータ、負極、正極です。データピンはデュポン線で GPIO18 に接続し、負極はグラウンドに、正極は 3.3V 電源に接続します。

赤外線発信管の接続#

image

発信管の状態は図の通りで、長い脚が正極で 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 つのデータの内容は完全に一致します。ボタンを押すたびに、風速や温度を調整するための情報が含まれています。

エンコード領域の関係#

注意:ここでは図の仕様に基づいており、実際の状況については議論しません。

仕様書によると、大体次の関係が存在します:

image

これにより、データ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_urloff_urlstatus_urlはそれぞれオン、オフ、ステータス確認に使用するインターフェースを表します。もちろん、プラグインはさらに多くのパラメータをサポートしており、具体的な内容は GitHub リポジトリの説明を確認してください。

設定が完了したら、HomeBridge サービスを再起動し、家庭アプリを開いてバックエンドに表示される QR コードをスキャンすれば、デバイスを発見できます。

image

この時、状態を正常に取得し、オンオフ操作を行うことができます。

音声制御#

では、さらに進んで、例えばベッドに横になって手を上げたくないときに音声制御が非常に便利です。

非常に簡単で、ショートカットを使用すれば完了します。

もちろん、HTTP API を提供しているため、複雑な方法は必要なく、直接呼び出すことができます:

エアコンをオンにする:

image

エアコンをオフにする:

image

これで、Siri にショートカットの名前を言うだけで使用できるようになります。

考察とまとめ#

もともとは Flutter を使用してアプリ + Web のフロントエンドアプリを実現する予定でしたが、突然 Apple 系のエコシステムを思い出し、途中でニーズを変更しました。しかし、これにより Android の携帯電話での操作が非常に便利ではなくなりました。とはいえ、HomeKit との組み合わせは比較的快適で、得るものと失うものがあるといえるでしょう。

時間の都合や、夜にまた空港で待機していることもあり、コードの面では粗雑で、動けば良いという原則に従っています。今後は少なくとも以下のいくつかの方向で改善が必要です:

  • API 層に認証システムを追加し、Cloudflare-Tunnelを使用して外部ネットワークにトンネルを通し、真のリモート制御を実現する。

  • 赤外線エンコードの面で、より多くの一般的な組み合わせを完成させ、関連するライブラリを使用して、外部バイナリを粗暴に呼び出すのではなく、直接赤外線エンコードデータを送信する。

  • HomeBridge 層では、さらに多くの機能を拡張し、自動指令と組み合わせて、現在のように単なる電球として扱うのではなく、より精緻な制御を実現する。

  • 定時タスクを設定し、指定された時間帯に自動的にオン / オフを行う:ラズベリーパイには青龍面板が展開されているので、簡単にスクリプトを書くだけで実現できます。

  • 外観の修正:ええ、インダストリアルデザインが使えないわけではありませんが、実際にその才能がないので、諦めます。

総じて、波折は多かったものの、最終的な実現は急いで行ったものでしたが、意外にも自分自身は満足しており、少なくとも時間を無駄にしたわけではないと感じています。

読み込み中...
文章は、創作者によって署名され、ブロックチェーンに安全に保存されています。