目的
M5StickCを使った玄関の鍵かけ忘れ防止システム(運用編) で作ったシステムに監視カメラ的な要素を追加するため、M5StickCからのMQTT通信をトリガーにラズパイでカメラ撮影ができる仕組みを構築する
環境
詳細
- Raspberry Pi 3 ModelB
- カメラモジュール:Raspberry Pi Camera Module V2(https://www.amazon.co.jp/Raspberry-Pi-Camera-%E3%82%AB%E3%83%A1%E3%83%A9%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB-Daylight/dp/B01ER2SKFS)
- M5StickC
- MQTT関連設定
- Publisher:M5StickC
- Broker:raspberry(mosquitto v1.5.7)
- Subscriber:raspberry(paho-mqtt v1.6.1)
作業メモ
M5StickC→ラズパイへMQTT通信("環境"の図の①)
参考サイト
https://yoshitaku-jp.hatenablog.com/entry/2019/06/30/210000
https://qiita.com/ekzemplaro/items/ab90dd630c3ad8e819ab
https://qiita.com/ekzemplaro/items/14ab3b599a6785187f6f
- ラズパイ側に必要なライブラリを導入(mosquitto, paho-mqtt)
まずは mosquitto を導入
$ sudo apt install mosquitto
$ sudo apt install mosquitto-clients
とりあえず起動して動作確認
(今回はmosquittoはBrokerとしてのみの動作のため、これで動作確認としては十分)
$ sudo systemctl start mosquitto
$ sudo systemctl status mosquitto
● mosquitto.service - Mosquitto MQTT v3.1/v3.1.1 Broker
Loaded: loaded (/lib/systemd/system/mosquitto.service; enabled; vendor preset: enabled)
Active: active (running) since Sat 2021-09-18 17:57:29 JST; 3min 53s ago
Docs: man:mosquitto.conf(5)
man:mosquitto(8)
Main PID: 1281 (mosquitto)
Tasks: 1 (limit: 1939)
CGroup: /system.slice/mosquitto.service
mq1281 /usr/sbin/mosquitto -c /etc/mosquitto/mosquitto.conf
9月 18 17:57:29 raspberrypi systemd[1]: Starting Mosquitto MQTT v3.1/v3.1.1 Broker...
9月 18 17:57:29 raspberrypi systemd[1]: Started Mosquitto MQTT v3.1/v3.1.1 Broker.
次に paho-mqtt を導入
(Pythonライブラリなので、pipでインストール)
$ sudo pip install paho-mqtt
- M5StickCからMQTT通信するコードを作成
今回はM5StickC(MQTT Publisher)起動時に1回ラズパイ(MQTT Broker)へMQTT通信させる
(「camera_start」というメッセージを送信)
#include <M5StickC.h>
#include <Wire.h>
#include <WiFi.h>
#include <PubSubClient.h>
/*---------------------------------------------
Global Data
-----------------------------------------------*/
/* -- 「*****」は環境に応じて設定必要 -- */
// For MQTT to raspberrypi
#define WLAN_SSID "*****"
#define WLAN_PASS "*****"
// MQTTの接続先のIP
const char *endpoint = "*****";
// MQTTのポート
const int port = 1883;
// デバイスID
char *deviceID = "*****";
// メッセージを知らせるトピック
char *pubTopic = "/pub/M5Stack";
// メッセージを待つトピック
char *subTopic = "/sub/M5Stack";
// 送信するメッセージ
char *pubMessage = "camera_start";
/* -- 環境に応じて設定必要(ここまで) -- */
WiFiClient client;
PubSubClient mqttClient(client);
void connectMQTT();
void setup() {
M5.begin();
Wire.begin(0,26);
// WiFi設定
WiFi.begin(WLAN_SSID, WLAN_PASS);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
}
// ラズパイへトリガー送信(MQTT)
mqttClient.setServer(endpoint, port);
connectMQTT();
}
void loop() {
}
void connectMQTT() {
// Server側(ラズパイ)と接続できるまで繰り返し
while (!mqttClient.connected()) {
if (mqttClient.connect(deviceID)) {
// メッセージ送信
mqttClient.publish(pubTopic, pubMessage);
int qos = 0;
mqttClient.subscribe(subTopic, qos);
}
else {
Serial.print("Failed. Error state=");
Serial.print(mqttClient.state());
// リトライ前に1[s]wait
delay(1000);
}
}
}
- MQTT通信で来ているか動作結果
とりあえず簡単に動作確認するため、mosquittoのSubscribe機能を使って通信確認
→ 送信したメッセージcamera_start
が受信できていることを確認
ラズパイ側のちゃんとした対応は次項で説明
$ mosquitto_sub -d -t /pub/M5Stack
Client mosqsub|1861-raspberryp sending CONNECT
Client mosqsub|1861-raspberryp received CONNACK (0)
Client mosqsub|1861-raspberryp sending SUBSCRIBE (Mid: 1, Topic: /pub/M5Stack, QoS: 0)
Client mosqsub|1861-raspberryp received SUBACK
Subscribed (mid: 1): 0
Client mosqsub|1861-raspberryp received PUBLISH (d0, q0, r0, m0, '/pub/M5Stack', ... (12 bytes))
camera_start
MQTT通信を検知→カメラ撮影("環境"の図の②、③)
参考サイト
https://qiita.com/ekzemplaro/items/14ab3b599a6785187f6f
https://www.raspberrypi.com/documentation/accessories/camera.html
- MQTT通信を検知するコードを作成(paho-mqttを利用)
broker
やtopic
を環境に応じて設定が必要
カメラモジュールのオプションなどは 参考サイト を参照
#!/usr/bin/python3
import random
import subprocess
import datetime
from paho.mqtt import client as mqtt_client
# brokerにはラズパイのIPアドレスを指定
broker = '*****'
port = 1883
# M5StickCで指定したトピックと同じトピックを指定
topic = "/pub/M5Stack"
# client IDをランダム生成
client_id = f'python-mqtt-{random.randint(0, 100)}'
def connect_mqtt() -> mqtt_client:
def on_connect(client, userdata, flags, rc):
if rc == 0:
print("Connected to MQTT Broker!")
else:
print("Failed to connect, return code %d\n", rc)
sys.exit(rc)
client = mqtt_client.Client(client_id)
client.on_connect = on_connect
client.connect(broker, port)
return client
def subscribe(client: mqtt_client):
def on_message(client, userdata, msg):
# 撮影した画像のファイル名:[year][month][date][time].jpg
t_delta = datetime.timedelta(hours=9)
JST = datetime.timezone(t_delta, 'JST')
now = datetime.datetime.now(JST)
date = now.strftime('%Y%m%d%H%M%S')
print(f"Received `{msg.payload.decode()}` from `{msg.topic}` topic")
if "camera_start" in msg.payload.decode():
try:
# 解像度1024x768/quality=75で撮影
cmd = "raspistill -o /home/pi/{0}.jpg -hf -vf -w 1024 -h 768 -q 75".format(date)
res = subprocess.check_call(cmd, shell=True)
except:
print("rasp camera error")
client.subscribe(topic)
client.on_message = on_message
def run():
client = connect_mqtt()
subscribe(client)
client.loop_forever()
if __name__ == '__main__':
run()
動作確認
M5StickCからのMQTT通信を受信できると、/home/pi
以下に撮影画像が保存される
$ ls ~/
20220220172347.jpg
....
- 作成したコードを常時動作させるようにService化
以前自分で書いた記事 を見つつ、常時動作ためのService登録をする
ここでは、先ほど作ったpahomqtt.py
を起動時に一度だけ実行する、Serviceを登録する
(pahomqtt.py
はloopしてMQTT通信を待つ作りになっているので、実行は一度だけでいい)
[Unit]
Description=MQTT SUBSCRIBE
After=multi-user.target
DefaultDependencies=no
[Service]
Type=simple
ExecStart=/usr/bin/pahomqtt.py
Restart=no
[Install]
WantedBy=multi-user.target
必要なファイルを必要な場所に配置
$ chmod u+x pahomqtt.py
$ sudo cp pahomqtt.py /usr/bin/
$ sudo cp mqtt_run.service /etc/systemd/system/
再起動してServiceが正常に動いていることを確認
$ sudo systemctl status mqtt_run.service
● mqtt_run.service - MQTT SUBSCRIBE
Loaded: loaded (/etc/systemd/system/mqtt_run.service; enabled; vendor preset:
Active: active (running) since Sun 2022-02-20 18:26:29 JST; 2min 25s ago
Main PID: 924 (pahomqtt.py)
Tasks: 1 (limit: 1939)
CGroup: /system.slice/mqtt_run.service
mq924 /usr/bin/python3 /usr/bin/pahomqtt.py
2月 20 18:26:29 raspberrypi systemd[1]: Started MQTT SUBSCRIBE.
- MQTT通信を検知 → カメラ撮影の動作確認
Service登録ができた状態でM5StickCを起動 → ラズパイでのカメラ撮影ができることを確認
$ ls ~/
20220220172347.jpg # こちらはお試し動作確認したときに撮った画像
20220220183642.jpg
....
まとめ
目標を達成!!
M5StickCを使った玄関の鍵かけ忘れ防止システム(運用編) で作ったシステムに監視カメラ的な要素を追加するため、M5StickCからのMQTT通信をトリガーにラズパイでカメラ撮影ができる仕組みを構築する
今後は M5StickCを使った玄関の鍵かけ忘れ防止システム(運用編) に今回の内容をマージしていきたい