7
7

More than 1 year has passed since last update.

この記事誰得? 私しか得しないニッチな技術で記事投稿!

RaspberryPiでMatter対応スマートライトを作った

Last updated at Posted at 2023-05-29

はじめに

Matter公式githubのコードを使ってスマートライトを作ってみました.
結果としてAlexaからのみですが普段使いできそうなものができました.

ポイント

できるだけシンプルかつ実用的に作るため以下のようにしています

  1. Matter over Wi-Fiを使用する
    Threadを使わないので外部モジュール不要
  2. 給電制御可能なUSBハブでライトのON/OFFを制御する
    市販のUSBライトが使用可能

使用した物

  1. Raspberry Pi 3 Model B
    Ubuntu Server 22.04 LTS (64bit)が動作するもの (おそらく3B以降であればどれでも動く)
  2. microSDカード 32GB
    16GBではギリギリかも
  3. BUFFALO 電源連動節電機能付き 4ポートセルフパワーハブ BSH4AE12BK
    libusbからUSBポートの給電ON/OFF制御ができるUSBハブ
  4. ダイソー テープライト(30LEDs、1m、ホワイト)
    USBに挿すだけで点灯するシンプルなLEDストリップ
  5. Amazon Echo
    Matter対応のもの

デバイス構築

OSのインストール

  1. Raspberry Pi ImagerなどでUbuntu 22.04 LTSをmicroSDカードに書き込む
  2. 起動してユーザやNWなどを設定

wpa_supplicantの設定

アプリからのデバイス追加の際に使用するWi-Fiを設定するので、設定内容を保存できるようにwpa_supplicantの設定を変更します

  1. serviceの修正
    /etc/systemd/system/dbus-fi.w1.wpa_supplicant1.serviceのExecStart=の行を以下のように変更
ExecStart=/sbin/wpa_supplicant -u -s -i wlan0 -c /etc/wpa_supplicant/wpa_supplicant.conf
  1. confの修正
    /etc/wpa_supplicant/wpa_supplicant.conf の内容を以下のように変更
ctrl_interface=DIR=/run/wpa_supplicant
update_config=1

必要なライブラリのインストール

sudo apt-get install -y git gcc g++ python pkg-config libssl-dev libdbus-1-dev libglib2.0-dev ninja-build python3-venv python3-dev unzip pi-bluetooth avahi-utils
# USBハブの給電制御用
sudo apt-get install -y libusb-dev

swapの追加

アプリのビルドにメモリを使用するのでswapを追加しておく
2GB以上のメモリがあればスキップしてOK(たぶん)

sudo dd if=/dev/zero of=/swapfile bs=1M count=2048
sudo chmod 0600 /swapfile
sudo mkswap /swapfile
sudo swapon /swapfile

コードのcloneと環境のセットアップ

git clone https://github.com/project-chip/connectedhomeip.git --branch v1.0.0
cd connectedhomeip
./scripts/checkout_submodules.py --shallow --platform linux
./scripts/build/gn_bootstrap.sh
source scripts/activate

サンプルアプリの変更

examples/lighting-app/linux以下のLinux用サンプルアプリをUSBハブの電源供給をON/OFFするように変更

diff --git a/examples/lighting-app/linux/BUILD.gn b/examples/lighting-app/linux/BUILD.gn
index 721f408437..edc31c6c39 100644
--- a/examples/lighting-app/linux/BUILD.gn
+++ b/examples/lighting-app/linux/BUILD.gn
@@ -94,6 +94,7 @@ executable("chip-lighting-app") {
    cflags = [ "-Wconversion" ]
  }

+  libs = [ "usb" ]
  output_dir = root_out_dir
}

diff --git a/examples/lighting-app/linux/include/CHIPProjectAppConfig.h b/examples/lighting-app/linux/include/CHIPProjectAppConfig.h
index e919666bb9..73a6984fdf 100644
--- a/examples/lighting-app/linux/include/CHIPProjectAppConfig.h
+++ b/examples/lighting-app/linux/include/CHIPProjectAppConfig.h
@@ -40,7 +40,13 @@
#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_TYPE 1

#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 257 // 0x0101 = 257 = Dimmable Bulb
+//#define CHIP_DEVICE_CONFIG_DEVICE_TYPE 256 // 0x0100 = 256 = Light Bulb

#define CHIP_DEVICE_CONFIG_ENABLE_COMMISSIONABLE_DEVICE_NAME 1

#define CHIP_DEVICE_CONFIG_DEVICE_NAME "Test Bulb"
+
+#define FATCONFDIR "/var/tmp"
+#define SYSCONFDIR "/var/tmp"
+#define LOCALSTATEDIR "/var/tmp"
+#define CHIP_CONFIG_KVS_PATH "/var/tmp/chip_kvs"
diff --git a/examples/lighting-app/linux/main.cpp b/examples/lighting-app/linux/main.cpp
index 7813c59979..42acfd8ab8 100644
--- a/examples/lighting-app/linux/main.cpp
+++ b/examples/lighting-app/linux/main.cpp
@@ -25,6 +25,13 @@
#include <app/clusters/network-commissioning/network-commissioning.h>
#include <lib/support/logging/CHIPLogging.h>
#include <platform/Linux/NetworkCommissioningDriver.h>
+#include <usb.h>
+
+#define USB_PORT_FEAT_POWER 8
+#define CTRL_TIMEOUT 1000
+#define USB_RT_PORT (USB_TYPE_CLASS|USB_RECIP_OTHER)
+#define HUB_ID_VENDOR 0x05e3
+#define HUB_ID_PRODUCT 0x0608

using namespace chip;
using namespace chip::app;
@@ -73,6 +80,55 @@ void ApplicationInit()
#endif
}

+void UsbPowerCtrl(int id_vendor, int id_product, bool pwr)
+{
+    struct usb_bus *busses;
+    struct usb_bus *bus;
+    busses = usb_get_busses();
+    for (bus = busses; bus; bus = bus->next)
+    {
+        struct usb_device *dev;
+        for (dev = bus->devices; dev; dev = dev->next)
+        {
+            usb_dev_handle *udh = NULL;
+            if (dev->descriptor.idVendor == id_vendor
+                && dev->descriptor.idProduct == id_product)
+            {
+                udh = usb_open(dev);
+                int request = pwr ? USB_REQ_SET_FEATURE : USB_REQ_CLEAR_FEATURE;
+                int feature = USB_PORT_FEAT_POWER;
+                for( int i = 1; i <= 4; i++)
+                {
+                    usb_control_msg(udh, USB_RT_PORT, request, feature, i, NULL, 0, CTRL_TIMEOUT);
+                }
+                usb_close(udh);
+            }
+        }
+    }
+}
+
+void ActionInitiated(LightingManager::Action_t aAction)
+{
+    if (aAction == LightingManager::ON_ACTION)
+    {
+       UsbPowerCtrl(HUB_ID_VENDOR, HUB_ID_PRODUCT, true);
+    }
+    else if (aAction == LightingManager::OFF_ACTION)
+    {
+       UsbPowerCtrl(HUB_ID_VENDOR, HUB_ID_PRODUCT, false);
+    }
+}
+
+void ActionCompleted(LightingManager::Action_t aAction)
+{
+    if (aAction == LightingManager::ON_ACTION)
+    {
+    }
+    else if (aAction == LightingManager::OFF_ACTION)
+    {
+    }
+}
+
int main(int argc, char * argv[])
{
    if (ChipLinuxAppInit(argc, argv) != 0)
@@ -80,7 +136,12 @@ int main(int argc, char * argv[])
        return -1;
    }

+    usb_init();
+    usb_find_busses();
+    usb_find_devices();
+    UsbPowerCtrl(HUB_ID_VENDOR, HUB_ID_PRODUCT, false);
    LightingMgr().Init();
+    LightingMgr().SetCallbacks(ActionInitiated, ActionCompleted);
    ChipLinuxAppMainLoop();

    return 0;
  • 簡単な説明
    • CHIPProjectAppConfig.h
      • (CHIP_DEVICE_CONFIG_DEVICE_TYPE: Dimmable Bulbから変更したかったが効果なしだった)
      • #define 〜DIR, ~PATH: 生成ファイルの場所を再起動しても消えない/var/tmpに変更
    • main.cpp
      • #define HUB_ID_VENDOR, HUB_ID_PRODUCT: 該当USBハブを特定するための製品固有値
      • UsbPowerCtrl(): 下記参考記載のhub-ctrl.cを参考にしたidVendor/IdProductを元に電源供給ON/OFFする関数
        (おそらくハブの実装起因で)USBポート毎のON/OFFがうまく動作しないので全ポート(1~4)を一括操作
      • LightingMgr().SetCallbacks(ActionInitiated, ActionCompleted)
        コントローラーからのON/OFF指示に対するCallbackにUsbPowerCtrl()を呼ぶ関数を登録

サンプルアプリのビルド

cd examples/lighting-app/linux
gn gen out/debug
ninja -C out/debug

サンプルアプリの自動起動の設定

# サンプルアプリのコピー
sudo mkdir /opt/lighting-app
sudo cp out/debug/chip-lighting-app /opt/lighting-app/
# systemdのサービスファイルの用意
cat <<EOF > chip-lighting-app.service
[Unit]
Description=CHIP lighting app
After=network.target

[Service]
Type=Simple
ExecStart=/opt/lighting-app/chip-lighting-app --wifi
Restart=on-failure

[Install]
WantedBy=default.target
EOF
sudo cp chip-lighting-app.service /etc/systemd/system
sudo systemctl daemon-reload
sudo systemctl enable chip-lighting-app.service

起動

事前にUSBハブ、テープライトを接続しておく

sudo systemctl start chip-lighting-app.service

(サンプルアプリが起動できればテープライトが消灯する)

Alexaアプリから作成したデバイスを登録

Alexaアプリのデバイス追加(+ボタン)からウィザードにしたがってデバイスを追加する

デバイスの操作

アプリ上から(他のデバイスと同じように)ON/OFFが可能
※アプリ上は照度やカラーも操作できるがサンプルアプリもハードウェアも対応してないので動作しない
※登録直後の数回はON/OFF操作が効かないことがある

その他

  • 一度設定すれば電源を切ってもOKだが操作可能になるまでかなり時間がかかる
    (コントローラー側がデバイスを認識し直すまでにラグがある...?)
  • サンプルアプリを初期化したい場合は/var/tmp/chip_*を削除する
  • Callbackに好きな処理書けば良いのでアイデア次第で何でもできそう...!

感想

Matterのおかげでデバイスだけの自作でAlexaから使えるスマートライトができました.
スマートデバイス作成にはデバイス管理のサーバ,Alexaスキル等のplatform連系アプリ, デバイスと管理サーバ連系まわりなどが必要だったのでMatterの登場によって非常に敷居が下がったんではないでしょうか.

追記

chi-lighting-appがかなり標準出力を吐くのでログまわりを抑制しないとディスクを使い切ります(ました).
以下の様に jounalログの最大サイズを制限し、rsyslog側へのログ転送も停止すると良いです.
/etc/systemd/journald.conf

[Journal]
SystemMaxUse=50M
ForwardToSyslog=no

変更後はOS/journaldの再起動で設定を反映させます.

参考

7
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
7