Cisco Meraki MV カメラのAPIで遊ぶ 第2弾　〜自動化で母の小言を解消しよう〜

# はじめに
この記事はシスコの有志による Cisco Systems Japan Advent Calendar 2022 （一枚目） の 21日目の記事として投稿しています。

2017年版: https://qiita.com/advent-calendar/2017/cisco
2018年版: https://qiita.com/advent-calendar/2018/cisco
2019年版: https://qiita.com/advent-calendar/2019/cisco
2020年版: https://qiita.com/advent-calendar/2020/cisco
2020年版(2枚目): https://qiita.com/advent-calendar/2020/cisco2
2021年版: https://qiita.com/advent-calendar/2021/cisco 
2021年版(2枚目): https://qiita.com/advent-calendar/2021/cisco2
2022年版: https://qiita.com/advent-calendar/2022/cisco ⇦今ここ

今年も早いものでAdvent Calendarの時期がやってきました。
今年は[2020年のMeraki MV 記事](https://qiita.com/naixia/items/b110def990cd69377d07)の第２弾としまして、Meraki カメラを使った１ネタをお届けしたいと思います。

# きっかけ
私には男の子の子供2人がいますが、とにかく言うことを聞かない、、、聞いたとしてもすぐ忘れて同じことを繰り返してしまいます。。笑
毎日毎日、同じことを子供にガミガミと言ってるなあ〜。。。とよく思いますし反省します。
その中の１つで、テレビを見ているうちに夢中になって、ついテレビ画面に近づいてしまう子供に対して「テレビに近づきすぎだよ！！目が悪くなるよ。もう少し離れて。」とよく注意しています。そこで、これをなんとか自動化で解消できないか！？と思い立ちました。

注）　世の中には、既に、人感センサーで画面に近づき過ぎたら警告してくれる優秀な製品も存在しますので、、そんなのテレビの機能で既に解決済みだよ！と言う方も多いかもしれませんが、我が家のテレビにはそのような機能はございません！！笑


# 実現したいこと!!
母がぷんぷん怒ることなく、自動的に子供がテレビから離れることを学習してもらうシステムを目指します。
![スクリーンショット 2022-12-18 12.12.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/d2979bf7-746c-2082-6ca7-1c25c730ef10.png)

# 実現方法
子供が画面に近づいたことをMeraki MVカメラで検知できないか検討したところ、Meraki MVでサポートされる[MQTT](https://developer.cisco.com/meraki/mv-sense/#!mqtt/what-is-mqtt) で検知した人の位置（座標）情報をリアルタイムに取得できることがわかったため、今回はMQTTで取得した座標情報を元に近づいたことを検知させることにしました。
![スクリーンショット 2022-12-18 12.14.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/e51c16a8-c426-1dfd-b9d5-6959f879ee12.png)
![スクリーンショット 2022-12-18 12.15.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/dd486125-af44-9f88-28e1-563064f1de4a.png)
# 構成
今回は、MQTTブローカーとしてオープンソース実装の Mosquitto（モスキート)をラズパイにインストールして使用します。また、データをPythonスクリプトで扱うためにMQTTサブスクライバーとしてPythonにおけるMQTTのクライアントであるPaho Python MQTT ClientをPCにインストールして使用しました。
PCにてPythonスクリプトを実行し、MQTTでブローカーから得た子供の位置情報を元にSwitchbot APIを介してテレビ電源を操作します。
![スクリーンショット 2022-12-18 12.12.37.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/da82e677-ccc1-4d03-55cd-973110669b04.png)

# 動作結果
詳細説明は下に書きますが、長くなったので、先に動作結果はこんな感じになりました。
MVのMQTTで取得した座標を元に子供が画面に近づいたことを判断します。
子供がテレビ画面（MVカメラ）に近付くと、テレビの電源をオフ、遠ざかると、テレビの電源をオンにしています。
![2022_qiita.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/a57b2f8a-9f21-21c3-3bbe-a9648f99ef14.gif)

では、詳細な説明をしていきます。
# Meraki MV の API について
MVのAPIについては、[こちら](https://developer.cisco.com/meraki/mv-sense/#!overview)に詳細な記載がありますが、下記の３種類のものがあります。今回使用するものはMV Sense APIのMQTTになります。
1. [MV Sense API](https://developer.cisco.com/meraki/build/mv-sense-documentation/): REST 及び MQTT API 。人および車両を検出し、リアルタイムのデータの読み取り値を提供。
2. [Live Link API](https://developer.cisco.com/meraki/api-v1/#!get-device-camera-video-link): 指定したカメラのダッシュボード リンクを返す REST API。
3. [スナップショット API](https://developer.cisco.com/meraki/api-v1/#!generate-device-camera-snapshot): 特定の時間における指定されたカメラの視野のスナップショットを生成し、その画像へのリンクを返す REST API。


# MQTT (Message Queuing Telemetry Transport) とは？
[OASIS](https://docs.oasis-open.org/mqtt/mqtt/v5.0/mqtt-v5.0.html) によって標準化されたパブリッシュ/サブスクライブ(Publish/Subscribe)型のメッセージングプロトコルです。軽量、オープン、シンプルで、実装が簡単であることが特徴です。最小限のプロトコル オーバーヘッドで設計されているため、M2Mや、IoTアプリケーションに適したプロトコルだと言われています。
![スクリーンショット 2022-12-18 12.17.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/7ace47ed-67cc-74f1-0eb5-4fa27d022341.png)
パブリッシュ/サブスクライブ(Publish/Subscribe)型のモデルでは、メッセージの送信側がパブリッシャー、メッセージの受信側がサブスクライバーとなり、ブローカーがメッセージの中継を行います。パブリッシャーはブローカーに特定のトピックのメッセージを発行（publish）し、サブスクライバーはブローカーから特定のトピックを購読（subscribe）します。パブリッシャーはサブスクライバーを意識することなく、ブローカーにメッセージの送信ができる一方で、ブローカーは、それらのメッセージを一旦預かり、管理し、適切にサブスクライバーに配信する責任を持ちます。

メッセージには「トピック」と呼ばれる属性情報を追加することができ、何についてのデータかを記述することができます。トピックはファイルシステムのパスのような階層構造で記述され、サブスクライバーはどのトピックのメッセージを受信するか選択できます。

# Merakiでサポートされる MQTT Topic
Topicはダッシュボードからもいくつか確認できますが、詳細は[こちら](https://developer.cisco.com/meraki/mv-sense/#!mqtt/what-is-mqtt)で確認が可能です。
MQTTはMVカメラだけではなく、[MR（アクセスポイント）](https://documentation.meraki.com/MR/Other_Topics/MR_MQTT_Data_Streaming)や[MT（センサー）](https://documentation.meraki.com/MT/MT_General_Articles/MT_MQTT_Setup_Guide)でもサポートされています。
今回使用するTopicはMVの”/merakimv/(MVのシリアルナンバー)/raw_detections”です。

-MVカメラのTopic例
![スクリーンショット 2022-12-18 12.14.05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/f593d095-352e-69ac-105b-4fe207644c17.png)

#  事前準備
### 1.MQTT ブローカー
Mosquittoをラズパイへインストールします。

インストール
```
sudo apt install mosquitto
```
サーバ起動
```
sudo systemctl start mosquitto
```
ステータス確認
"active(running)"と表示されればOK
```
sudo systemctl status mosquitto
```
### 2. MQTT サブスクライバー
Mac PCへpaho-mqttをインストールします。
```
$ python3 --version
Python 3.11.1

$ pip3 install paho-mqtt
Collecting paho-mqtt
  Downloading paho-mqtt-1.6.1.tar.gz (99 kB)
     ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━ 99.4/99.4 kB 1.9 MB/s eta 0:00:00
  Preparing metadata (setup.py) ... done
Installing collected packages: paho-mqtt
  DEPRECATION: paho-mqtt is being installed using the legacy 'setup.py install' method, because it does not have a 'pyproject.toml' and the 'wheel' package is not installed. pip 23.1 will enforce this behaviour change. A possible replacement is to enable the '--use-pep517' option. Discussion can be found at https://github.com/pypa/pip/issues/8559
  Running setup.py install for paho-mqtt ... done
Successfully installed paho-mqtt-1.6.1

```
### 3. MQTT パブリッシャー
パブリッシャーとなるMeraki MVの設定をします。 Meraki ダッシュボードでMV Sense APIを有効化して、MQTTブローカーを追加します。
![スクリーンショット 2022-12-18 12.13.57.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/6f912a13-f730-f5a7-9328-4eeeecd45993.png)

詳細手順は[こちら](https://developer.cisco.com/meraki/mv-sense/#!mqtt/what-is-mqtt)も参照してください。


### 4. SwitchbotのAPIの準備
[Switchbot](https://www.switchbot.jp/)の説明は割愛させていただきます。シスコ製品ではありません。
離れた場所や外出先から照明のスイッチや家電の電源操作ができ便利なため我が家では活用しています。APIの使用方法については[昨年の記事](https://qiita.com/naixia/items/1f97d39893d3fa75ffb8)に記載してますのでご参照ください！

# MQTTの動作テスト
まずは、下記のスクリプトを使い、MQTTで値が取得できるかどうかテストします。
```test-mqtt.py
import paho.mqtt.client as mqtt
import json

host = '192.168.0.16' #MQTTブローカーであるラズパイのIP
port = 1883 #MQTTのデフォルトのポート番号
topic= '/merakimv/<MVのシリアル番号>/raw_detections'　#MQTTのトピックの指定

def on_connect(client, userdata, flags, respons_code):
   print("Cinnected wuth result code" + str(respons_code))
   client.subscribe(topic)

def on_disconnect(client, userdata, flag, rc):
  if  rc != 0:
    print("Unexpected disconnection.")

def on_message(client, userdata, msg):
  data = json.loads(msg.payload)
  print("{}".format(json.dumps(data,indent=4))) #取得したトピックのデータを出力
 
if __name__ == '__main__':
   client = mqtt.Client()
   client.on_connect = on_connect
   client.on_disconnect = on_disconnect
   client.on_message = on_message
   client.connect(host, port=port, keepalive=60)
   client.loop_forever()
```

#### 動作結果

子供の動きに伴い、座標が変動していることがわかります。
この結果を元に、変動が大きいy1座標の値を閾値として使い子供がテレビ画面に近づいたことを判断し、Switchbot APIでリモコンを操作することにしました。

取得データを見ると、座標の他にも、個体を識別するOIDや、検出された物体のタイプも取得できていることがわかります。物体のタイプはデフォルトで人物以外にも車両などを識別できます。また、このAdvent Calendarの[2日目の記事](https://qiita.com/dahirata/items/a79a50206db0c254dfd9)に書かれている[Custom Computer Vision](https://documentation.meraki.com/MV/Video_Analytics/MV_Sense_Custom_Computer_Vision)を使って学習させることにより、任意のものを識別することも可能です。
![スクリーンショット 2022-12-18 12.13.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/13e60bde-fd78-bb89-79b7-4c7c412bb80d.png)
![スクリーンショット 2022-12-18 12.13.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/f1a326b5-e173-cd53-49f6-0331ff620a05.png)
![スクリーンショット 2022-12-18 12.13.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/217351/fe9568c1-11ef-d8c6-4859-f4b0f592d112.png)


# Switchbotと連携する
最後にSwitchbotと連携！！　
子供がテレビ（MVカメラ）に近付くいたことを座標で判断し、SwitchbotのAPIでテレビの電源をオフ、遠ざかると、テレビの電源をオンにします。
```tv-auto.py
import paho.mqtt.client as mqtt
import json
import requests

host = '192.168.0.16'
port = 1883
topic= '/merakimv/<MVのシリアル>/raw_detections'

i=0

switch_url='https://api.switch-bot.com/v1.0/devices/<テレビリモコンのdebice ID>/commands'

switch_headers= {
       'Content-Type': 'application/json',
       'Authorization': '<Switchbot 開発者コード>'}

payload_on='{"command":"turnOn","parameter":"default","commandType":"command"}' #テレビ電源オン
payload_off='{"command":"turnOff","parameter":"default","commandType":"command"}'　#テレビ電源オフ

def on_connect(client, userdata, flags, respons_code):
   print("Cinnected wuth result code" + str(respons_code))
   client.subscribe(topic)

def on_disconnect(client, userdata, flag, rc):
  if  rc != 0:
    print("Unexpected disconnection.")

def on_message(client, userdata, msg):
  data=json.loads(msg.payload)
  obj=data['objects']
  global i
  y1 = [d['y1'] for d in obj]
  if y1:
   print("y1の座標は{}".format(y1[0]))
   if y1[0] < 0.1:
    print("!!テレビに近寄りすぎです！！離れましょう！！")
    if i==0:
     print("!!テレビをオフにします!!")
     requests.post(switch_url, headers=switch_headers, data=payload_off)　#テレビ電源オフ
     i=1

   if y1[0] > 0.5:
    if i==1:
     print("!!十分離れたので、テレビをオンします！！")
     requests.post(switch_url, headers=switch_headers, data=payload_on)#テレビ電源オン
     i=0
 
if __name__ == '__main__':
   client = mqtt.Client()
   client.on_connect = on_connect
   client.on_disconnect = on_disconnect
   client.on_message = on_message
   client.connect(host, port=port, keepalive=60)
   client.loop_forever()
```
# 終わりに
本記事では、MerakiでサポートされているMQTTのご紹介と使い方、また、取得データを活用した自動化のユースケースをご紹介しました。MVのMQTTは、他にも弊社製品[Cisco Space](https://www.cisco.com/c/ja_jp/solutions/enterprise-networks/dna-spaces/index.html)との[インテグレーション](https://www.cisco.com/c/en/us/td/docs/wireless/spaces/config-guide/ciscospaces-configuration-guide/m_camera.html)により、Cisco Space上でMVで検知されたロケーションに入退場した訪問者や滞在している訪問者の情報を表示することもできたりします。MQTTは非常にシンプルですので、他のアプリケーション連携にも色々と活用できそうです。本記事で少しでも興味を持っていただけたら幸いです。

# 免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。