欲しいアプリは自分で作る!

Power Platform や Azure などを利用して作成した業務アプリや趣味アプリなどをご紹介します。

ヘラクレスオオカブトの状態をいつでも確認できる LINE ボット with ヘラクレス監視システムをローコードで作ってみた

(2023/01/27追記)
こちらの記事ですが、Qiita Advent Calendar 2022 プレゼントカレンダーにて Develop fun! 賞をいただきました。
栄えある賞をいただき、誠にありがとうございました!

blog.qiita.com




皆さんは動物や生き物は好きですか?
私は犬が死ぬほど大好きです。何時間でも犬と遊べます。

姉宅の飼い犬と戯れる私
なお妻は動物が苦手なため、我が家で犬を飼うことは許されません(画像は姉の飼い犬)。


そんな私ですが、この度息子(8)の要請により、ヘラクレスオオカブトというカブトムシ(以下、ヘラクレス)を飼うことになりました。

飼うことになったヘラクレス

今回、このヘラクレスの温度管理や生態観察を目的として、いつでもヘラクレスの状態を確認できる仕組みを作ってみましたので、紹介させてください。


本記事のゴールは以下を想定しております。

  • 生体監視システムを自分でも作れるようになる
  • 様々なシステムを API 連携できる面白さが分かる
  • ローコード・ノーコードの可能性の高さを実感できる
  • ヘラクレスオオカブトを飼ってみたくなる

ご興味ありましたら、是非ご覧いただけますと幸いです。


なおこの記事は、身の回りの困りごとを楽しく解決! by Works Human Intelligence Advent Calendar 2022 12月10日(Calendar1)担当分の記事です。 qiita.com


目次


1. ヘラクレスオオカブトとは

世界最大のカブトムシとして知られ、最大個体は全長180mm(ミリメートル)以上に達する、とても大きなカブトムシです。
参考:Wikipedia ja.wikipedia.org

ヘラクレスにはいくつか種類があるそうで、今回は2種類のヘラクレスを飼うことにしました。

左:ヘラクレスヘラクレス(以下、ヘラヘラ)   右:ヘラクレスレイディ(以下、レイディ)

角が曲がっている個体だったこともあり、かなり安く入手できました。
ふさふさな毛とくりくりな目がたまらなく可愛いです。


多くのカブトムシは冬が来る前に寿命を迎えますが、ヘラクレスは寿命が1年~1年半と長いのが特徴です。
熱帯の出身のため寒さに弱く、ヘラクレスを越冬させるには適切な温度管理が欠かせません。

また、ヘラクレスはどうやら普段は大人しい性格のようで、じーっと見ていてもなかなか動いてくれません。動いているところを見たいんだけどなぁ。
(ちなみに戦闘時はキュウリをへし折る力を持つほどの怪力の持ち主です)


ということで、ユーザー(私)の要望は以下の2つです。

上記の要望を満たすべく、ヘラクレスの状態をいつでも確認できる LINE ボット with ヘラクレス監視システムを作ってみました。

話しかけると現在のヘラクレスの様子と温度・湿度を教えてくれる(gif動画です)


ヘラクレスに動きがあると通知してくれる(静止画です)



2. システム概要

アーキテクチャ

LINE ボット with ヘラクレス監視システムのアーキテクチャは以下のようになりました。
昨今注目を集めているノーコード/ローコードですべての機能を実装可能です。


LINE ボット with ヘラクレス監視システムのアーキテクチャ


冬に保温する必要があることから、ヘラクレスのケースは温室の中に入れており、温室の外側から撮影することにしました。
今回のシステムでは、上段のヘラヘラのみを撮影対象にしています。

ヘラクレス監視システム


ちなみに、温室はカラーボックスをベースに自作しました。
今回のシステムでは制御しない温室単体の機能として、以下の機能を有しています。

  • 断熱(スタイロフォーム + アルミシート)
  • 温度調整(一定温度以下になると自動でヒーターが作動)
  • 曇り防止(PC用のファンを常時稼働)

なお、温室の作成方法につきましては本記事では割愛させていただきますm(__)m


まずは、本システムが有する2つの機能の概要をご紹介します。


機能① ヘラクレスの様子と温度・湿度を確認できる

1つ目は、LINE ボットに話しかけることで、ヘラクレスの様子を撮影した画像と現在の温度/湿度を返信してくれる機能です。

この機能を実現するために、カメラと温湿度計を使用します。
カメラは、Power Apps で作成したキャンバスアプリを遊休のスマホで動かすことで代用しました。
(静止画をクラウド上にアップロード可能な市販のカメラもあったのですが、予算の都合により断念)
温湿度計は、API 経由で温度と湿度を取得可能な SwitchBot 温湿度計 + SwitchBot ハブミニを使用しました。

処理内容

Power Apps のキャンバスアプリでヘラクレスの様子を10分間隔で自動撮影し、Power Automate 経由で Azure Blob Storage に画像を格納します。

ユーザーから LINE 経由で何かしらメッセージが送信されたら、Azure Logic Apps を用いて SwitchBot から現在の温度と湿度を取得、Blob から画像を取得し、取得内容を LINE に応答メッセージで送信する、というものです。

機能①の部分


機能② ヘラクレスに動きがあった際に通知してくれる

2つ目は、ヘラクレスの動きを画像で検知して、一定以上の動きがあった場合に LINE ボット側から能動的に通知してくれる機能です。

この機能を実現するために、AI の機能(画像内の物体検知)を活用します。
今回は Azure Cognitive Services の Custom Vision を利用しました。
(人感センサ等の利用も検討したのですが、予算の都合により断念)

処理内容

機能①の Power Automate で、Custom Vision に対して画像データを送信し、画像内のヘラクレスの位置情報を取得します。
取得した位置情報を Microsoft Dataverse の位置情報テーブルに格納しておきます。
前回と今回の位置情報を用いた移動距離の計算は Microsoft Dataverse 側に自動計算させます。

機能①とは別の Logic Apps フローにて Microsoft Dataverse の位置情報テーブルへのレコード追加を監視し、追加されたレコードの移動距離が一定以上であった場合に「ヘラクレス動いたっぽいよ。見る?」と LINE に Push メッセージで送信する、というものです。

機能②の部分


以降では、これら二つの機能の実装方法についてご紹介していきます。



3. 作り方:機能① ヘラクレスの様子と温度・湿度を確認

まずはこちらから作成していきましょう。

3-1. ヘラクレスの様子を10分間隔で自動撮影する

まずは、ちゃちゃっと撮影機能を Power Apps で作るところから始めました。

必要なコントロールは、カメラコントロールとタイマーコントロールのみ。シンプルですね。

横向きに使いたかったので、タブレット形式にしました。
まず、カメラコントロールを配置します。

カメラコントロールを画面いっぱいに広げ、ストリームレートを適当に設定します。
ストリームレートとは画像を更新する頻度で、最小値は100(ms)です。
参考: Power Apps での Camera コントロール - Power Apps | Microsoft Learn

続いて、タイマーコントロールを配置します。

今回は10分(=60000s)間隔で自動撮影するので、期間を60000にします。
繰り返しと自動開始をオンにし、表示はオフにします。
(もし「次の撮影まであと何分かなー?」と画面上で確認したい方は、表示しておいても OK です)

最後に、タイマーが10分経過する度に、カメラの画像を Power Automate にアップロードするためにクラウドフローを呼び出します。
(つまり、自動撮影というよりは、10分毎に今カメラに写っている画像をアップロードするというイメージですね)

この記述は、クラウドフローを先に作成する必要がありますので、Power Apps の作成は一旦置いておいてクラウドフローの作成に移ります。

3-2. 撮影した画像を Azure Blob Storage に格納する

3-2-1. Blob Storage の作成

ここからクラウドフローの作成に入るのですが、画像を Azure Blob Storage に格納するので、先にBlob Storage の設定を行いましょう。

Azure ポータル(portal.azure.com)で検索窓に blob と入れると「ストレージアカウント」というものが表示されるので、それをクリック。

「+作成」をクリックし、ストレージアカウントの作成画面に移ります。
ストレージアカウント名はご自由に設定してください。
今回はなるべくコストをかけたくないので、パフォーマンスは Standard に、冗長性はローカル冗長ストレージにしました。

設定が終わったら、Review をクリックして、作成ボタンをクリックします。
(既定の設定だと、作成した Blob ストレージにはどこからでも匿名アクセスが可能になります。LINE からアクセスさせるために必要な設定ですが、念のため)

ストレージアカウントが作成されたら、リソースに移動し、

コンテナ―をクリックし、画像を格納するコンテナーを作成しておきます。

最後に、Power Automate の Blob Storage コネクタを利用するために、アクセスキーにあるストレージアカウント名とキーをコピーしておきます。


3-2-2. Power Automate の作成

ここから、Power Automate のクラウドフローの作成に入ります。

先ほどまで開いていた Power Apps の画面からフローを作成します。

Power Apps の画面上に、フローの作成画面が現れました。
まず、トリガを変更します。既存のトリガを削除し、

PowerApps (V2) トリガを追加します。

今回は Power Apps 側から画像データと画像ファイル名を取得するようにするので、以下のように入力を2つ追加します。 種類はどちらもテキストでOKです。

続いて、Power Apps 側から受け取った画像データをバイナリイメージに変換します。 データ操作の作成を追加し、式に「dataUriToBinary()」と入力したら、

dataUriToBinary関数の引数に、先ほどのFileDataを選択します。

最後は Blob Storage に画像データを格納するアクションを追加します。

先ほどコピーしておいたアカウント名とキーを入力して接続を作成します。

パラメータは以下のようになるかと思います。

ここまで作成できたら、フローに名前をつけて、保存してください。

自動的に Power Apps の画面に戻ります。
先ほど作成したフローが Power Apps 上に追加されていることが分かります。

なお、上記のフローでは、Blob Storage 上の画像データが増え続ける設計となっています。
Blob Storage のデータ量を抑えたい場合は、古いものから削除するなど、フローを工夫してみてください。


3-2-3. Power Apps への追記

最後に、Power Apps から Power Automate に対して画像データとファイル名を送信する部分を作ります。
タイマーコントロールの OnTimerEnd に、以下のように記載します。
第一引数のファイル名には現在時刻を使用して「yyyymmddhhmmss.png」のようにし、
第二引数の画像データにはカメラコントロールのStreamプロパティの値をそのまま指定します。


ここまでで、Power Apps、Power Automate、Blob Storage の設定・作成は終了です。
10分間隔で画像がBlob Storage に格納されることを確認してみてください。
(下記画像は、時間を短縮するため2秒間隔で画像ファイルを保存したものです)


3-3. LINE からのリクエストを受けて画像と温度・湿度をユーザーに返送する

続いて、先ほど保存した画像と、SwitchBot の温度・湿度を取得し、LINE で問い合わせてきたユーザーに返信する処理を作ります。
まずは、LINE の設定から。

3-3-1. LINE の設定

ここでは、ユーザーとのコミュニケーションの窓口となる LINE 公式アカウントを作成します。

LINE 公式アカウントの作成方法は、以下をご参照の上、1. ~ 10. まで実施ください。 7. で取得したアクセストークンは、この後の処理で必要になりますので、コピーしておきます。 jn.hateblo.jp

私はこんな感じにしました。


上記10. の手順まで終わったら、一旦次の実装に移ります。
途中でもう一度 LINE 側の設定がありますので、画面はそのままにしておくとよいです。


3-3-2. Logic Apps の作成

続いて、実際の処理フローを作成します。
今回は、この処理を Azure Logic Apps で実装することにしました。

まずは Azure ポータルからロジックアプリを選択し、

+作成をクリックして、作成画面に移ります。
以下のような設定にし、確認および作成をクリックします。

作成をクリックし、デプロイが完了したらリソースに移動します。

「空のロジックアプリ」をクリックし、フローの作成画面を表示します。

まずトリガですが、HTTP 要求の受信時を使用します。

HTTP 要求の受信時を追加したら、一度保存ボタンを押してみてください。
HTTP POST の URL に URL が自動設定されますので、これをコピーしてください。

コピーした URL を、LINE の設定画面の Webhook URLに貼り付けて更新し、Webhook の利用をオンにします。

こうすることで、ユーザーが LINE にメッセージを送信した際に、LINE がメッセージの内容を Logic Apps の HTTP POST の URL に送信してくれるようになります。
ここで一度、作成した LINE 公式アカウントと友だちになり、適当にメッセージを送信してみてください。
(現時点では、何も応答がないと思います)


Logic Apps に戻ります。

うまくいっている場合は、先ほど適当に送信したメッセージが Logic Apps 側に届いているはずですので、実行履歴を確認してみましょう。 フローの概要画面に戻り、実行の履歴タブをクリックし、一番最後の実行履歴をクリックしてみます。

HTTP 要求の受信時の出力部分で、LINE から送信されたメッセージ情報が JSON 形式で取得できていることが確認できます。
確認できたら、この出力の本文を次の作業で使いますので、コピーしておきます。

フローの編集画面に戻ります。
HTTP 要求の受信時の「サンプルのペイロードを使用してスキーマを生成する」をクリックし、表示される画面に先ほどコピーした出力本文を張り付けて完了をクリックします。

こうすることで、要求本文の JSON スキーマを設定することができます。

続いてアクションを作成していきます。
まずは、応答アクションを追加し、LINE に対してステータスコード 200 を返してあげます。
(参考:https://developers.line.biz/ja/reference/messaging-api/#response

続いて、Blob Storage から画像情報を取得するアクションを追加します。
Blob Storage に格納された画像のリストを取得します。
こんな感じに設定します。

次は、SwitchBot 温湿度計からデータを取得する作業に入ります。

SwitchBot 側の準備等については、こちらの記事を参考にされるとよいです。
(SwitchBot のデータを API 経由で取得するには、温湿度計の他にハブが必要になりますのでご注意ください) qiita.com

上記記事の「認証用トークンの取得」、「SwitchBotの設定」、「deviceIdの取得」を実施iいただきましたら、フローに HTTP アクションを追加し、以下のように設定します。
ヘッダーの Authorization の黒塗りの箇所には認証用トークンを貼り付けます。

URIは以下のようになります。"デバイスID"にはお手元の温湿度計のdeviceId(上記で取得したもの)を設定してください。 これで、温湿度計から温度・湿度データを JSON 形式で取得できます。

https://api.switch-bot.com/v1.0/devices/バイスID/status

取得したデータにアクセスしやすくするよう、JSON の解析アクションを追加します。
スキーマは、LINE の時と同じように、一度保存&実行させて実行履歴から実データをコピーし、サンプルとして貼り付けると楽です。


ここまでで必要なデータをすべて取得できましたので、最後に LINE に応答メッセージを返します。
HTTP アクションを追加し、以下のように記述します。

URI は応答メッセージ専用の URIhttps://api.line.me/v2/bot/message/reply」を固定値として使用します。
ヘッダーの認証トークン(Authorization)は、LINE の設定時に取得したチャネルアクセストークンを貼り付けます(画像の黒塗りの箇所)。

本文は、リファレンスを参考に記載します。

リファレンス:
応答メッセージ:https://developers.line.biz/ja/reference/messaging-api/#send-reply-message
画像メッセージ:https://developers.line.biz/ja/reference/messaging-api/#image-message

SwitchBot 温湿度計から取得した温度は temperature から、湿度は humidity から取得します。

LINE で画像メッセージを送信する場合は、オリジナルとプレビューでそれぞれ画像の URL を指定する必要があります。
今回、画像は Blob Storage に格納してあり、URL は以下のようになりますので、コンテナ名まで固定値で入力し、ファイル名は「Blob を一覧表示する」アクションで取得した情報を利用します。

https://ストレージアカウント名.blob.core.windows.net/コンテナ名/ファイル名

「Blob を一覧表示する」アクションで取得したデータは、複数の画像情報が配列で入っており、最後に保存された画像情報は配列の末尾に格納されています。
そこで、Last 関数を用いて配列の末尾にアクセスし、そこのファイル名(Name列)を指定します。
今回は、オリジナルもプレビューも同じ画像としました。

Last(body('BLOBを一覧表示する(V2)')?['value'])?['Name']

最後の replyToken は、以下の式を記述して取得します。
(LINE から送信されるメッセージ情報は1メッセージであっても配列で送られてくるため、first 関数を用いて配列内にあるトークンを取得している)

first(triggerBody()?['events'])?['replyToken']


これで、機能①は完成です。

LINE からメッセージを送信し、Power Apps アプリを作成した際に Blob Storage にアップロードした画像が LINE から送られてくることを確認してみてください。

なお、上記のフローでは、ユーザーからいかなるメッセージが送信されようとも応答する設計となっています。
ユーザーから送信されたメッセージに応じて処理を変更したい場合は、条件分岐を追加するなど工夫してみてください。



4. 作り方:機能② ヘラクレスに動きがあった際に通知

続いて、こちらを作成していきます。
物体の動きを検知する方法は色々あると思うのですが、AI も使ってみようかなーと思い、今回は画像内のヘラクレスの位置を Azure Cognitive Services の Custom Vision に判断してもらうことにしました。


4-1. (事前作業)Custom Vision の設定

ということで、まずは Custom Vision を使えるように設定していきます。

Azure ポータル(portal.azure.com)から Custom Vision を探してクリック。

「+作成」をクリックし、Custom Vision の作成画面に移ります。
作成オプションは「両方」を選択します(Custom Vision ではまずトレーニングを行い、その後実際に利用(予測)するという、2つの利用フェーズがあり、今回は両方使用するため)。
リソースグループとインスタンスの名前はご自由に設定してください。

レーニングと予測の価格レベルは、どちらも Free F0 にしました。
(すでにご利用のサブスクリプションで Free F0 の Custom Vision を作成されている方は、F0 を選べないかも)

ちなみに、Free F0 は以下のようなプランです。
今回は10分間隔で撮影し予測させるので、6回/時、144回/日、最大4,464回/月。大丈夫そうですね。
(ここまで無料で使えるの神)

あとは作成して完了です。デプロイが完了したら、リソースグループに移動します。
インスタンス名そのもの、インスタンス名の後ろに「-Prediction」(予測という意味)とついたもの、計2つのリソースが作成されていると思います。
意味的にはPredictionとついているリソースはトレーニング後に使うものなので、ひとまずPredictionとついていない方をクリックしておいてください。
(なお私の認識では、どちらから辿ってもその先の手順に変わりはないはず)


4-2. (事前作業)ヘラクレスの形を Custom Vision にトレーニングさせる

Custom Visionヘラクレスの位置を判断してもらうには、まずヘラクレスとはどういう形なのかをトレーニングさせる必要があります。
そのため、まずはヘラクレスが映った画像を撮りためます。

レーニング精度を高めるために、可能な限り様々な位置&体制のヘラクレスを撮影しましょう。
最低15枚は必要みたいです。ちなみに私は100枚用意しました。

集まったら、早速トレーニングを開始します。
Custom Vision ポータルを開きます。

NEW PROJECT をクリックします。

プロジェクトを作ります。
今回は複数の物体を分類したいのではなく、物体の位置を検出したいので、Project Types は Object Detection にします。
Domains は画像の特徴や学習精度を定めるものですが、今回は「ヘラクレスって黒っぽくて検出しづらそうだよなー」という安易な考えのもと、汎用画像の検出精度の高いらしい General [A1] にしてみました。
設定したら Create project。

まずは、集めた画像をアップロードします。
画像1枚に月6MBまでですが、Power Apps で撮影した画像が6MBを超えることはきっとないはず。

アップロードできました。
次は Custom Vision に「これがヘラクレスだよ!」と教えてあげる作業です。

教えるために、まずタグを作成します。Tags の右の+をクリック。

タグ名を入力して Save。

ここから、各画像に対して「ヘラクレスを選択し、タグをつける」作業を行います。
1枚目の画像をクリックしてタグをつける画面を開き、ヘラクレスの四隅あたりからドラッグしてヘラクレスを選択します。

ちなみに、マウスオーバーするだけで、なんとなーく「これ何かの物体じゃね?」と位置を勝手に提案してくれることもあります。
「そうそう!それそれ!」という場合は、自動表示された点線(手動でドラッグして表示される点線より点線がちょっと細かい)をクリックするだけでよいです。

タグをつけるポップアップが表示されるので、先ほど作成したタグ名を選択。

こうなります。これで、1枚目のタグ付けが完了です。
とりあえず、あと14枚手作業でやりましょう。画面右側の > をクリックして次の画像へ。

地味に大変な作業です。
(でもヘラクレスかわいいので平気)

とりあえず15枚タグ付け完了。
タグを付けた画像と付けていない画像は、画面左側の Tagged と Untagged で表示を切り替えることができます。

まだ85枚残っていますが、ひとまずここで画面右上の Train をクリック。
Quick Training で Train をクリックしましょう。

終わるとこんな画面になります。
私の環境だと、15枚トレーニングするのに7分くらいかかりました。

レーニングが終わったら、このトレーニングの成果を利用して、残りの画像のタグ付けを自動化してしまいましょう。
(参考:Smart Labeler を使用して画像により早くラベルを付ける - Azure Cognitive Services | Microsoft Learn

画面上部の Training Images タブから画像一覧画面に戻り、Untagged の画像一覧で Get suggested objects をクリック。

Get started をクリック。

残りの85枚の画像のうち、51枚でヘラクレスらしきものが見つかったようなので、この Herchles (51) をクリック。

画面左側の Confidence Value(信頼度:これはヘラクレスだと思う割合)を調整してみます。どうやら信頼度99%でヘラクレスを検知できたのが51枚だったようです。
Confidence Value を下げると検知枚数が増えますが、その分誤検知も増えますので、いい塩梅で調整してみてください。

とりあえず、99%で51枚の画像を見ていきます。

「きっとこれがヘラクレスだよね?」と教えてくれるので、合っていれば「Confirm suggested objects」をクリックします。
間違っている場合は、提案された枠を調整したり、新たに枠を作ったりすると、自動でタグ付けされます。

これを繰り返します。地道な作業が続きます(これってまとめて Confirm できないのかな。ご存知の方いたら教えてくださいm(__)m)
しかし、すごい精度ですね。わずか15枚のトレーニングで、ここまで検知するとは。

一通り終わったら、Confidence Value を下げてみます。
94%まで下げたら、23枚出てきました。
このように、タグ付けしていない and 信頼度99%では検知できなかった残りの画像が表示されてきますので、同じように作業を続けます。

それは木だよ。ヘラクレスじゃないよ。

タグ付けが終わると、このように Tagged で Hercules 100 となります。  

ここまで終わったら、改めてトレーニングしましょう。

100枚トレーニングするのに、私の環境では15分ほどかかりました。

なお、ここに表示されている各種指標については、こちらの記事が分かりやすいです。
(ここでは説明を割愛します)
kdl-di.hatenablog.com

これでトレーニングは終了です。
これを外部サービスから利用できるように、公開することで Web API 化することができます。
画面上部の Publish をクリック。

予測用のリソースを指定します。おそらく -Prediction とついたもののみ表示されていると思いますので、それを選択して Publish。

公開したら、以下の4つの情報をコピーしておいてください(取得箇所は各々下図参照)。

  1. Prediction Key(画面上部の Prediction URL をクリックして取得)
  2. Site URL(画面上部の Prediction URL をクリックして取得。.com/ まで)
  3. Iteration Name(画面上部の Prediction URL をクリックして取得。URL の末尾あたりの iterations の後)
  4. Project ID(画面上部の歯車マークをクリックして取得)


4-3. 画像を Custom Vision に送信しヘラクレスの位置情報を取得する

事前準備が終わりましたので、ここから実装に入ります。
画像データを Custom Vision に送信するのは、Power Automate からでした。
機能①で作成した、Blob Storage に画像データを保存する Power Automate のフローに、機能を追加していきます。


作成済みのフローを開き、「作成」と「Blob を作成する(V2)」の間に並列分岐を追加します。

Custom Vision の「画像内のオブジェクトを検出する(V2)」を追加します。

接続を作成します。接続名は適当に。
予測キーには、先ほど取得した 1. Prediction Keyを、サイトの URL には、2. Site URL をペーストしてください。

プロジェクト ID には、先ほど取得した 4. Project ID を、パブリッシュされた名前には、3. Iteration Name をペーストします。
画像の内容は、「作成」の出力を指定します。

ひとまずここまででフローを保存し、最初に作成した Power Apps のアプリの編集画面を開きます。
フローの中身を変更したので、最新の情報に更新し、アプリを実行して画像を Power Automate にアップロードさせてみてください。
(タイマーコントロールの期間をわざと短くして、すぐにアップロードさせるようにするとよいかもです)

フローの実行履歴を確認し、予測結果が JSON 形式で取得できていることをご確認ください。


ここで、この後の作業内容をご理解いただくために、予測結果の中身を見てみます。

予測結果は複数のデータの配列構造になっており、信頼性(probability)の高い順に並んでいるようです。
ヘラクレスが映っている写真を予測すると、ヘラクレスの位置はおおよそ99%以上の信頼性で検出できているようで、配列の1番目を取得することでヘラクレスの位置を推定できそうです。

ひとつの予測値を抜粋して見てみます。

これは、「boundingBox の位置に Hercules と思われる物体があった。信頼性は 58.39%」という意味であることが分かります。
(この値は、ヘラクレスが映っていない写真を使用したため信頼性が低くなっています)

"probability": 0.58391815,
"tagId": "0c9dda2c-b789-4d9d-b1a1-04f4b132f0a3",
"tagName": "Hercules",
"boundingBox": {
    "left": 0.37704632,
    "top": 0.36941642,
    "width": 0.18787172,
    "height": 0.09630877
}

で、この boundingBox ですが、ヘラクレスを検知した箇所(トレーニング時に指示した時のように四角形で検知される)の左上の座標が left と top で表現され、そこから四角形の幅と高さが width と height で表現されています。
数値は画像の縦/横の長さを1とした割合で表されています。
今回はこれらの値を用いて四角形の中心位置を計算し、ヘラクレスの位置と定義することにしました。

そして、この中心位置を毎回計算し、前回の中心位置との距離を計算することで、ヘラクレスがおおよそどの程度動いたのかを求めることにしました。
(画像の縦と横の長さが異なることや、斜め上から撮影していることなどから、実際の移動距離を求められる式では決してないのですが、今回はざっくり動いたかどうかが分かればよかったので…)


4-4. 位置情報をデータベースに登録する

4-4-1. Microsoft Dataverse にテーブルを追加する

ということで、これらの位置情報や距離などの情報を格納するテーブルを作成します。
ヘラクレスの中心位置や移動距離の計算は、計算列を用いて可能な限りデータベース側に計算させるようにします。

テーブルをひとつ作成します。

プライマリ列は ID にし、自動で連番になるようにします。
一旦これで保存して、

オートナンバーに変更しておきます。

続いて、Left, Top, Width, Height を格納する数値列を追加します。
小数が入るので、型は小数にしました。

ここまで追加しました。

続いて、ヘラクレスの中心位置(x, y)を格納する列を追加します。
データの種類を計算式にし、先ほど追加した列の値を用いて中心位置を計算する式を記載します。

ここまで追加しました。
計算列にはマークがついています。

続いて、移動距離を計算するために、前回の中心位置を格納する列を追加します。
私が知る限り、数式で直前のレコードを参照する方法はない(はず)ので、ここでは通常の数値列にして Power Automate 側で登録してもらうようにします。
(もしご存知の方いましたら教えていただきたいです!)

これで「前回の中心位置」と「今回の中心位置」が集まりましたので、移動距離を格納する列を追加します。

計算式は以下の通りです。
2乗は Power 関数、ルートは Sqrt 関数を利用します。
(この計算、最初は Power Automate でやろうとしたのですが、私が調べる限り Power Automate でルート計算する方法が見つからず…)

Sqrt(Power(CenterX - LastCenterX, 2) + Power(CenterY - LastCenterY, 2))


最終的に、追加した列はこのようになりました。

列の追加が終わったら、1レコードだけ登録しておきます。
値は適当でOKです。


4-4-2. テーブルに位置情報を登録する

これまでの見解を踏まえて、実際にヘラクレスの画像を Custom Vision に送信し、予測結果をテーブルに格納する処理を追加します。

4-3. の Power Automate クラウドフローの編集画面を開き、Custom Vision アクションの下に「新しい行を追加する」アクションを追加します。

おっと、そういえば、前回の中心位置を取得しておく必要がありました。
ということで、今追加したアクションの前に「行を一覧にする」アクションを追加します。

詳細オプションを開きます。
前回の中心位置は、テーブルの最終レコードに格納されていますので、登録日時順に並び変えて1行のみ取得します。


「新しい行を追加する」アクションに戻ります。
まず、Custom Vision から取得した位置情報(Left, Top, Width, Height)を入れていきます。

Custom Vision から取得した位置情報は、以下のような構造になっていました。
predictions(予測)の配列があり、各レコード内に boundingBox があり、boundingBox の中に位置情報が格納されています。

で、ヘラクレスの位置はおおよそ1レコード目にあることから、以下のように記載します。

Left:
 First(outputs('画像内のオブジェクトを検出する_(V2)')?['body/predictions'])?['boundingBox']?['left']
Top:
 First(outputs('画像内のオブジェクトを検出する_(V2)')?['body/predictions'])?['boundingBox']?['top']
Width:
 First(outputs('画像内のオブジェクトを検出する_(V2)')?['body/predictions'])?['boundingBox']?['width']
Height:
 First(outputs('画像内のオブジェクトを検出する_(V2)')?['body/predictions'])?['boundingBox']?['height']


最後に、前回の位置情報を入れていきます。

Dataverse から取得した前回の位置情報は、1レコードのみ取得はしたものの、構造としては「1レコードのみ格納された配列」として取得します。
よって、こちらもFirst関数を用いるとフローの見た目がキレイです。

Left:
 first(outputs('行を一覧にする')?['body/value'])?['crea5_CenterX']
Top:
 first(outputs('行を一覧にする')?['body/value'])?['crea5_CenterY']

※列名の先頭に接頭辞が必要な点に注意


今回の中心位置(CenterX, CenterY)や移動距離(DistanceFromLastToCurrent)は Dataverse 側で勝手に計算してくれます。


これで、Power Automate の作成は完了です。

フローを保存したら、最初に作成した Power Apps のアプリの編集画面を開き、フローを最新の情報に更新してください。

あとは、キャンバスアプリで自動撮影する度に、Dataverse にそれっぽい値が格納されていくことをご確認ください。

※このデータは我が家のヘラクレスのデータ。この時間帯はほとんど動いてないですねw


4-5 ヘラクレスの移動を検知してユーザーに通知する

いよいよ最後の作業になります。
こんな長ーい記事をここまでお読みいただけただけで感無量です。本当にありがとうございます。

最後は、ヘラクレスが移動した際に、ユーザーに通知する機能を作ります。
仕組みとしては、Dataverse にレコードが追加される度に移動距離を確認し、一定以上の数値だった場合に LINE の友だちにメッセージを送信する、というものです。
ここでは、前半で作成したフローとは別のフローを Logic Apps で作成します。

(ブロードキャストメッセージとは、LINE公式アカウントのすべての友だちに一斉にメッセージを送信する機能のことです)


まずは新しいフローを作成します。
3-3-2. と同じ手順で、「Hercules_Detect」フローを作成しましょう。

デプロイが終わったらリソースに移動し、空のロジックアプリから作成画面に入ります。

トリガは Dataverse の「行の追加時」を使用します。
サインインし、必要な設定を行います。

設定タブをクリックし、トリガの発動条件を指定します。
動いていない時もフローを動かしてしまうと実行コストがかかってしまうため、移動距離(DistanceFromLastToCurrent)が一定以上の数値である場合にのみ発動させます。
今回は0.4以上にしてみました。ここの数値はお持ちのヘラクレスの性格に合わせてご自由に変更してみてください。

@greaterOrEquals(triggerBody()?['crea5_distancefromlasttocurrent'], 0.4)


発動した場合はあと通知するだけです。
HTTP アクションを追加し、以下のように記述します。

今回は「応答メッセージ」ではなく、一方的に全ての友だちに発信するメッセージ「ブロードキャストメッセージ」となります。
URI は、ブロードキャストメッセージ専用の URIhttps://api.line.me/v2/bot/message/broadcast」を固定値として使用します。
(友だち数だけ送信回数を一度に消費しますので、友だちが多い場合はご注意ください)

ヘッダーの認証トークン(Authorization)は、LINE の設定時に取得したチャネルアクセストークンを貼り付けます(画像の黒塗りの箇所)。

本文は、ボタンを押したら裏側で特定のメッセージを送信できる仕組みにしてみました。

{
  "messages": [
    {
      "altText": "ヘラクレス動いたっぽいよ。",
      "template": {
        "actions": [
          {
            "data": "見る",
            "label": "見る",
            "type": "postback"
          }
        ],
        "text": "ヘラクレス動いたっぽいよ。\n見る?",
        "type": "buttons"
      },
      "type": "template"
    }
  ]
}

リファレンス:
ブロードキャストメッセージ:https://developers.line.biz/ja/reference/messaging-api/#send-broadcast-message
ボタンテンプレート:https://developers.line.biz/ja/reference/messaging-api/#buttons
ポストバックアクション:https://developers.line.biz/ja/reference/messaging-api/#postback-action


これですべての実装が完了しましたので、保存終了します。
実際に稼働させてみて、動きがある度に LINE に通知がくることを確認してみてください。


ちなみに、この仕組みのままでは通知の頻度が高すぎる可能性があります。
ヘラクレスが隠れてしまった場合などで Custom Visionヘラクレスをうまく検知しなかった際に、ヘラクレスではない箇所を誤検知する場合があるからです。
この場合、位置情報がいきなりぶっ飛ぶ可能性があり、その度に通知される危険性があります。

そこで我が家では、例えば以下のような回避策を講じています。

  • テーブルに検知有無列を設け、Custom Vision の予測結果の信頼性が99%未満の場合は検知していないことにする
  • 前回と今回の両方で検知し、かつ移動距離が一定以上であった場合に通知する
  • 掃除する際にヘラクレスを手で移動させる場合があるため、撮影した時間間隔が11分以上だった場合も検知していないことにする(掃除する際にキャンバスアプリを停止させるため、掃除後は撮影時間間隔が伸びることを利用)

このあたりは皆さまの飼育環境によって異なると思いますので、色々と工夫してみてください。



5. まとめ

改めて、システム(?)の全体像をおさらいしてみます。
いわゆるコーディングで開発した部分はなく、パラメータや関数のレベルですべての機能を実装できたことがお分かりいただけたかと思います。


ぱっと見、自動化は全部 Power Automate でやったら?という感じもしなくもないですが、今回は以下の理由で細かくサービスを分けてみたのでした。

  • 内部処理とユーザー側の処理を分けたかった
  • きちんとお仕事としてシステムを作る際は友だち数の桁が違い API コール数の問題も出てくることを想定した
  • なるべく機能単位で分けて一機能の規模を小さくしたかった

もちろんこれが最適なアーキテクチャではないと思いますので、ご興味を持っていただけた方は、これをたたき台に、より素敵な監視システムを構築してみてください。


なお、現在はヘラクレスの静止画のみの提供ですが、近日中に「ヘラクレスが動いたら自動で動画を撮影し、実際に動いている動画を見られるようにする機能」を追加予定です。
今後も(思い付いたら)様々な機能を搭載していきますので、お楽しみに(?)



欲しいアプリは欲しい人が作る時代へ。
何かのご参考になれば幸いです。



参考記事

今回も沢山の記事に助けられました。ありがとうございました!

qiita.com qiita.com qiita.com

mofumofupower.hatenablog.com

learn.microsoft.com learn.microsoft.com learn.microsoft.com learn.microsoft.com

ja.wikipedia.org

developers.line.biz

jn.hateblo.jp