GASとラズパイで定期監視システムを作ってみた話
個人でちょっとした開発をして日々遊んでおります。
そのうちの1つとして、GAS,ラズパイ,Linebotを組み合わせた簡単な開発物を作成したのでざーっくり紹介します。
簡単な自己開発経験として。拡張すれば色々な用途に使えるかもしれません。
私もここをベースにして、追加開発を行う予定です。
また、自己解釈等入っている部分もあるかもしれないので、もし修正すべき点等見つけた場合遠慮なく教えてください。感謝します。質問も歓迎します。
自己紹介
- name -> Tackky
- work -> 業務系ソフトウェアの開発(?)部門4年目のまだ新しい米
- suki -> car, alchol, book, technology, game, etc
作ったもの
3Dプリンターで作成した鉢に種を植えて、水耕栽培で植物を育てています。毎日は観察できないので、経過を記録したいと考えました。
- ラズパイ:毎日一定時刻に写真を撮影し、
- ラズパイ:クラウドへ送信。
- GAS:Linebotとして写真を毎日送信する
というものです。
必要なもの
No. | 品目 |
---|---|
1. | ラズパイ(ネット接続可能なもの)一式 |
2. | ラズパイに接続するカメラ(ここではPiCamerav2を使用) |
仕組み
開発作業手順
上記画像の1→2→3の順番で実行されるが、ここでは逆順で説明していく。
(紐付け先のアクセスURLがわからなくなりがちなので。)
1. Linebot側の設定
こちらはアカウント作って紐付け先を取ってきます。
providerの作成
サービスを作成する事業主=providerを作成します。ここでは、個人開発なので自分専用のProviderを作成します。
channelの作成
メッセージを送信するアカウントを作成します。用途ごとに色々作ってみると楽しいと思います。providerが無事作成されると、このようなページに飛ぶので、Line Messaging APIを選択します。
channelの初期設定画面に入るので、ここでLinebotのアイコン・説明等を追加します。
Company regionは日本でいいと思います。
channel icon, channel name, channel descriptionは好きに設定してください。カテゴリーとEmail addressは必須入力なので近しいものを選択します。
channel access tokenの取得
この後のGAS側の設定で使うのでこれをコピーします。これはLine Messaging APIを使ってGASからメッセージを送るためのエンドポイントになっています。
2. GAS側の設定
GASに入る前に
ラズパイで撮影した画像を保存するフォルダーを作成します。
今回はGoogleDriveを使用しました。(相性もよさそうだし…)GASからドライブにアクセスできるものであればなんでも問題ないと思います。
ここで、共有リンクを取得しておきます。この際、リンクを知っている人は誰でも閲覧可能にしておきます。
GAS
以下のリンクにアクセスして、GASの画面を開きます。(ログインが必要かも?)
ここで、画面左上のNew Projectをクリックして、新しいプロジェクトを作成します。
GASでは、プログラムが走ったら、本日日付で撮影された画像を取得し、LinemessagingAPIを経由してLinebotに送信してくれるプログラムを書いていきます。
Script Properties
まず、シークレットキー等の他人に公開できない部分をプロジェクト内のProject settingsからScript Propertiesに設定します。
Script PropertiesはProject settingsの下部にあります。
Property項目 | Value項目に入れる内容 |
---|---|
CSVFILE_ID | 温湿度センサ情報を共有する場合のファイルパス |
IMGFOLDER_ID | GoogleDriveから取得した共有リンク |
LINE_ACCESS_TOKEN | Linebotを作成した際に取得したchannel access token |
LINE_USER_ID | 自分だけ等の特定のユーザーのみに送信したい場合に使用 |
mainprocess
ここでは、25行目で送信する画像のURLを取得し、26行目で送信する文章を作成し、30行目以降で、送信する画像がある場合、Lineにメッセージを送信するという流れです。
getIMGURL
var folder = DriveApp.getFolderByID(this.IMGFOLDER_ID);
でGoogleDriveのフォルダの場所をIDから取得し、
var files = folder.getFiles();
でフォルダ内にあるファイルを全取得しています。
40~45行目で、本日日付で作成されたファイルのみをreturnしています。
詳細なリファレンスはここにあります。
getText
画像を送信するだけでは少し物寂しいので、日付も送信するために、送信文字列を作成する関数です。
sendMessageToLine
今回は、作ったBotを知り合いなどにも送信したかったため、Linebotに登録してくれた人全員に一斉送信を行うBROADCASTでメッセージを送信します。messagesの中を{}で区切れば、異なるタイプのメッセージでも同時に送信してくれます。
参考URL
全体のコードは以下から参照してください。
3. ラズパイ側の設定
初期設定は省略します。
実行環境は以下です。
raspberry pi | Raspberry Pi 4 Model B |
OS | Linux raspberrypi 6.1.21 |
camera | Camera v2.1 |
Python | Python 3.9.2 |
カメラモジュールの設定
クラウドアップロードの設定
ラズパイ側からGoogleDriveにアップロードする際に、1回目はOAuth2の設定をする必要があります。
OAuth2による認証
client_secret.jsonという名称で保存し、ラズパイ側にsshを使って送信します。
定期実行プログラムとタスクの設定
-
撮影+GoogleDriveへの送信プログラム
解説がめんどくさいので貼ります
# -*- coding: utf-8 -*- from __future__ import print_function import httplib2 import os import sys import datetime import configparser from picamera import PiCamera from glob import glob from apiclient import discovery from apiclient.http import MediaFileUpload from oauth2gdrive import get_credentials # OAuth 2.0で設定するApplication ID APPLICATION_NAME = 'Upload files' # OAuth 2.0で設定するSCOPE:Google Driveにおいてファイル単位のアクセスを許可 SCOPES = 'https://www.googleapis.com/auth/drive.file' # アップロードするファイルが格納されているディレクトリ IMG_DIR = 'Pictures/' # アップロードするファイルの拡張子 FILE_EXTENSION = '.jpg' # ファイルを格納するGoogle Driveのフォルダ DRIVE_DIR = 'SAVED_IMAGE_HYDRO' # Google DriveのフォルダのmimeType FOLDER_MIME_TYPE = 'application/vnd.google-apps.folder' # アップロードするファイルのmimeType FILE_MIME_TYPE = 'image/jpeg' CLIENT_SECRET_FILE = 'client_secret.json' def upload_file(drive_service, drive_folder_id, upload_file_path): ''' Google Driveの指定したフォルダにファイルをアップロードする 指定のファイルをアップロードする Returns: void ''' # upload_file_pathがらファイル名を抽出する file_name = os.path.split(upload_file_path)[-1] # Google Driveの指定したフォルダへファイルをアップロードする media = MediaFileUpload(upload_file_path, mimetype=FILE_MIME_TYPE, resumable=True) file_metadata = { 'mimeType': FILE_MIME_TYPE, 'name': file_name, 'parents': [drive_folder_id], } created_file = drive_service.files().create(body=file_metadata, media_body=media, fields='id, name').execute() print('Upload sucssesful:' + created_file.get('name')) def uploadfiles(): ''' 指定したディレクトリ配下の全てのファイルをGoogle Driveへアップロードする 指定するディレクトリは、ホームディレクトリ配下のディレクトリとする 指定した拡張子を持つファイルのみをアップロードする Returns: void ''' # OAuth 2.0の認証プロセスを実行する credentials = get_credentials(APPLICATION_NAME, SCOPES) http = credentials.authorize(httplib2.Http()) drive_service = discovery.build('drive', 'v3', http=http) # アップロードする全てのファイルパスを取得する home_dir = os.path.expanduser('~') img_dir = os.path.join(home_dir, IMG_DIR) #upload_files_path = glob(os.path.join(img_dir, '*.' + FILE_EXTENSION)) #if not upload_files_path: # 該当するファイルが存在しない場合は終了する # print('File does not exist. It does not upload.') # sys.exit() dt_now = datetime.datetime.now() now = dt_now.strftime('%Y%m%d%H%M%S') upload_file_path = img_dir+now+FILE_EXTENSION camera=PiCamera() camera.resolution = (1920,1080) camera.awb_mode = 'incandescent' camera.brightness = 55 camera.contrast = 20 #camera.framerate=Fraction(1,) #フレームレート設定 camera.capture(upload_file_path) config_ini = configparser.ConfigParser() config_ini.read('config.ini', encoding='utf-8') DRIVE_ID = config_ini['default']['Drive_id'] print('Upload file:' + upload_file_path) upload_file(drive_service, DRIVE_ID, upload_file_path) if __name__ == '__main__': uploadfiles()
-
定期実行の設定
cron を使用して設定します。
上記で設定したプログラムをこれを参考に設定する
https://www.express.nec.co.jp/linux/distributions/knowledge/system/crond.html
できたもの
これのお陰でレタスが枯れかけていることに気付けました。よかったね。
さいごに
APIリファレンスや言語リファレンス等は公式のものを読め。それが一番だ。
Discussion