これまでの LINE ボットの課題
2018 年に、家のエアコンを操作してくれる LINE ボットを作って以来、すでに一年半くらい運用しています。概要は 当時のエントリでも紹介しています が、LINE での会話を元に自宅のエアコンを操作してくれるものです。
これ、作った当初に想定していた以上にたいへん便利で、外出先で家族と『そろそろロボくんにお願いしておこう』などの会話が発生する程度には実際に活用されていました。この手の『作ってみた』系は、長期的な運用が定着する前に使わなくなることが多い印象もあり、これは小規模ではあるもののうまくいった例と言えるかと思います。
一方で、作りが甘い部分もあって、
- Lambda の Node.js のランタイムで EoL が迫っていた
- そもそも Node.js のランタイム側の更新に追従していくことに将来的にけっこう体力を使いそうな印象がある
- 当時 Node.js を選んだ理由は『とりあえずいちど触ってみたかった』からというだけで、すでにその目的は達成できた
- ひとつの Lambda に全機能を詰め込んでいて、どう考えてもイケてないアーキテクチャだ
- 機能が足りない
- エアコンのオンオフと温度の変更はできたが、冷房と暖房の切り替え機能を実装していない
など、長期的な運用に耐えられるよう全体を作り直したいモチベーションも強くなってきていました。
そんな中、あるイベントに参加して、『Raspberry Pi とセンサとクラウドサービスを使って何でもいいから個人で何かを作る』という活動をすることになり、タイミングもよかったので、この LINE ボットの作り直しを進めることにしました。
できたもの
で、こういう風に進化して、今も元気に動いています。
以下のような機能が付いています。
- エアコンの操作
- オンオフ、冷暖房の切り替え、温度の変更、現在の設定の確認をしてくれます
- 加湿器の操作
- オンオフをしてくれます
- 空調センサ
- 室内に設置したセンサを使って、気温、湿度、気圧、二酸化炭素濃度の現在の値を教えてくれます
- 任意の時間分の履歴をグラフ化して送ってくれます
- 家計簿の記録
- 支払者、使途、金額を Google Sheets に追記してくれます
- 毎朝の自動制御
- 毎朝、部屋が寒い(暑い)場合は、暖房(冷房)を付けてくれます
- 毎朝、部屋が乾燥している場合は、加湿器を付けてくれます
実装
実装を簡単に紹介します。末尾には GitHub へのリンクも載せています。
全体像
全体はこのような構成です。
参加したイベントの性質上、なるべくたくさんの要素技術を取り込んだほうが評価が上がる仕組みだったため、あえてまわりくどく冗長な構成になっている部分もあります。
センシングと蓄積
センシングと蓄積は、図の以下の部分です。これまで複数回にわたって紹介してきた EdgeX Foundry を中心に構成しています。
EdgeX Foundry 自体は、家庭内の IoT ゲートウェイサーバとして構築した Ubuntu 仮想マシン(ESXi 上で動作)の中で動いています。このゲートウェイサーバ上では MQTT ブローカも動かしています。
Raspberry Pi は、センサ値を読んで MQTT トピックにひたすら放り込み続けるだけの係です。EdgeX Foundry は、この Raspberry Pi を MQTT デバイスとして制御するよう構成されており、所定の MQTT トピックに投げ込まれたデータを取り込んで、アプリケーションサービスの機能を使ってクラウド上の所定の宛先にデータをエクスポートしています。
エクスポート先は、Mosquitto のパブリック MQTT トピックと、Pivotal Web Service(PWS)上のワーカアプリケーションで、なんやかんやされて最終的にデータは InfluxDB Cloud 2.0、Redis Cloud、MongoDB mLab に蓄積されます。
十数年前に PIC や Arduino でセンサやアクチュエータを操作していた頃は、データシートとにらめっこをしながら必要な抵抗を計算したり回路を考えたりしていましたが、最近のヤツは単にデータを読み取るだけなら恐ろしいくらい簡単ですね…… けっこう衝撃でした。
今回は BME280 と MH-Z19 を使っています。安いですし精度は悪いのでしょうが、厳密な値は必要としていないのでよしとしています。最初は DS18B20 も使っていましたが、BME280 を組み込んでからは使っていません。
アクチュエーション
最終的にはエアコンと加湿器が操作されるわけですが、この部分の実装は、前者は Nature Remo の API、後者は非公式の野良 API で制御しています。
Nature Remo の API を叩く役は、AWS の所定の Lambda に一任しています。加湿器も同様ですが、こちらは非公式 API の都合上、ローカルネットワーク内からしか制御できなかったので、Lambda からいちど IoT Core の MQTT トピックに命令をなげ、それをローカルネットワーク側から購読して後続の処理をトリガさせています。ここだけは Node.js です。
加湿器は、モデルの選定がなかなかたいへんでした。加湿器に限らず何らかの家電を外部から自動制御する場合、
- スマートコンセントを利用する
- コンセントが通電したら目的の動作が開始される仕様である必要がある
- スマートスイッチ(SwitchBot など)を利用する
- 目的のボタンが、物理的にスマートスイッチで押下できる形状であり、かつスマートスイッチの力で押せるだけの硬さである必要がある
- スマートリモコンを利用する
- RF ではなく赤外線を利用したリモコンで制御できる機器である必要がある
- 専用の API を利用する
- API が公開されている必要がある
のいずれかの条件を満たす必要がありますが、加湿器でこれに合致するモデルが全然見つけられませんでした。大体の加湿器は、コンセントの通電後にさらにボタンを押さないと動作しませんし、ボタンの周辺の形状や寸法やボタンの硬さは公開されていませんし、リモコン付きのモデルでも赤外線でなく RF ですし、公式の API はなさそうですし。
結局、公開されていない API を無理やり叩ける非公式のライブラリが存在していてハックの余地がありそう、ということがわかった Oittm のアロマディフューザー を採用しています。ただしこれも、
- 非公式のライブラリ で制御できるようにするには、公式アプリケーション Tuya Smart の旧バージョン(3.12.6 以前)を使って、MITM 攻撃的なヤツでアプリケーションの通信を自分で盗聴してキーを入手しないといけない
- ライブラリが Node.js 向けしかない
- そもそもの加湿器自体が小型でとても非力で、リビングなど広い空間の加湿には向かない
など、ベストとは言い難い状態です。改善の余地ありです。
インタフェイスとインタラクション
インタフェイス役の LINE ボットに話しかけると、LINE の Messaging API 経由で AWS の Lambda に届いて、メッセージ本文がパタンマッチされてその内容に応じて後続の処理がトリガされます。
エアコンの操作であれば Nature Remo を制御する Lambda を呼びますし、加湿器の操作であればそれ用の別の Lambda を呼びます。センサのデータが必要な処理であれば、外部のデータベースに必要なデータを取りに行く Lambda を呼びます。
グラフを要求された場合は、InfluxDB からデータを取ってきて matplotlib で描画したあとに S3 に保存し、それをプッシュでユーザに送ります。描画する対象(温度、湿度、気圧……)と長さ(N 分、M 時間)はメッセージ本文から都度判断します。
この辺りの処理では、
- グラフ要求のメッセージが来たら、受理した旨の返事を後続処理に先行して即座にしてしまい、画像の生成と送信はあとから非同期で行う
- グラフの生成に時間がかかるため、 同期的に処理させると(Lambda ではなく)API Gateway がタイムアウトする
- S3 のバケット名や画像ファイル名をなるべく短くする
- LINE で画像を送るときは、画像そのものではなく画像の URL を送る必要がある
- Lambda で発行する S3 の署名付き URL は 1,000 文字前後とめちゃくちゃ長い(x-amz-security-token が含まれるため)
- LINE 側の制約で、URL は 1,000 文字以内でないとエラーで送れない
- 署名付き URL ではなくパブリックな URL にしてしまうのは気が引ける
- バケット名やファイル名は URL に含まれるため、短くすることでギリギリ 1,000 文字以内になる
などの工夫が必要でした。特に二点目はひどい回避策ですが、あまり権限をがばがばにはしたくなかったので仕方なく……。
また、LINE とはまったく関係ないところで、Grafana を PWS で動かしており、そこでもグラフを見られるようにしています。
感触とロードマップ
センサの値がグラフで見られるのが、実際に使ってみると思っていた以上におもしろかったです。
例えばエアコンをつけてから温度が上がっていく様子や、朝起きて部屋で人間が活動しだしてから二酸化炭素濃度が一気に上がる様子、逆に家が無人になってから下がる様子、キッチンで火を使う調理を始めたタイミングなど、思っていた以上に生活パタンが可視化されることがわかりました。
また、二酸化炭素濃度や気圧の変化では眠気や頭痛の誘発なども懸念されるので、体調に違和感を覚えたときに客観的な変化をすぐ確認できるのはうれしく、体調管理面でも地味に役立っています。
運用面では、Lambda まわりをすべて CloudFormation で定義したことで、コードの管理とデプロイがだいぶに楽になりました。クラウド側がマネージドサービスとサーバレスアーキテクチャだけで組めているのも安心感があります。
ただ、本エントリの途中で、
参加したイベントの性質上、なるべくたくさんの要素技術を取り込んだほうが評価が上がる仕組みだったため、あえてまわりくどく冗長な構成になっている部分もあります
と書いた通り、正直なところ機能に比較して実装が大げさすぎるので、この辺はスリムにしたいと思っています。
イベントはもう終わったので、現状のゴテゴテ感を保つ意味はあまりなく、例えば、
- この規模だと EdgeX Foundry の恩恵は受けにくいので、まるっと削って Raspberry Pi から直接クラウドに投げてもよいだろう
- データの蓄積場所も AWS の DynamoDB などにしてしまえば、PWS も InfluxDB も Redis も MongoDB もいらなくなり、AWS に全部寄せられるだろう
- いっそ Raspberry Pi も AWS IoT Greengrass で AWS から管理させるとよいのでは
などのダイエットや試行錯誤を検討中です。とくに Greengrass は完全に未修分野なので純粋に興味もあり触ってみたいですね。
物理的には、加湿器をもう少し高機能(大容量)かつ自動制御しやすいものに替えたい気持ちがあります。オンオフは自動で制御できても、給水が自動化しづらいので、結局は人間の介入が必要な状態になってしまっており、人間が手を抜くにはタンクの容量がキモになりそうだと考えています。
関連リポジトリ
一覧します。
- raspi-airmeasurment
- Raspberry Pi 上で動作させる、各種センサ値を読み取って MQTT トピックに送る Python プログラム
- edgex-lab-raspi
- Raspberry Pi から MQTT トピックに送られた値の取り込みや、クラウドへのエクスポートを行えるように構成した EdgeX Foundry の Docker Compose ファイル
- edgex-lab-export2db
- PWS 上で動作させる、EdgeX Foundry からエクスポートされたデータを各種データベースに保存するためのプログラム群
- Telegraf 用のイメージは Docker Hub の kurokobo/edgex-lab-telegraf に配置済み
- grafana-with-flux
- PWS 上で動作させる Grafana
- sam-smarthome-api
- AWS 上で動作させる一連の Lambda 群
- tuya-mqtt
- MQTT の配信を受けて加湿器をコントロールする Node.js プログラム