【開発】ボトルの中身がなくなったら、通知するシステムを作ってみた

この記事では、Raspberry PiとHX711（重量センサー）を使って、物の重さを測定し、そのデータをリアルタイムでGoogle Spread Sheetに送信し、Gmailに通知する方法を紹介します。

# はじめに
大学のゼミ活動でIoT開発？をする事になったことがきっかけですが、以前IoT機器を用いた研修教材作成のアルバイトもしたことがあり興味があったことや、大学1年の時にサークル部屋に誰かいるかを外から分かるようにする時に、顔認証システムを作ったまま放置されたRasPiくんがいたので、丁度いい活用機会ということで、このようなIoT開発をしてみました。

# 必要なもの
* Raspberry Pi（これは小型のコンピューターです）
* HX711モジュール（これは重量を測定するためのデバイスです）
* インターネット接続（これはデータをGoogle Spread Sheetに送信するために必要です）
* Googleアカウント（これはGoogle Spread Sheetを使うために必要です）

# 構成図（概略）
これは、最初に頭の中で考えていけるのではと思っていた構成図です。( **考えのアウトプット大事！** )

画像は適当にパワポで作りました（笑）
![IoT構成図-GAS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/d5c7d5e7-956f-a141-8c54-6d4765fb246b.png)

**完成品がこちら↓↓↓（すごいかんたん！）**
![完成図.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/61ae55ec-2c8d-7e30-3e9c-b92da3433469.jpeg)

# 手順
## 1. HX711のセットアップ
まず、HX711とRaspberry Piを適切に接続します。これは、HX711が重量データをRaspberry Piに送信できるようにするためです。詳細な接続方法は、こちらを参照してください。

https://zenn.dev/kotaproj/books/raspberrypi-tips/viewer/270_kiso_hx711

### 1-1. Raspberry Piのセットアップ
Raspberry PiにはデフォルトでPythonがインストールされていますが、pip（Pythonのパッケージ管理ツール）がインストールされていない場合があります。以下の手順でpipをインストールすることができます。

ターミナルを開きます。

以下のコマンドを実行してpipをインストールします：

```bash
sudo apt update
sudo apt install python3-pip
```
これにより、Python 3用のpip（pip3）がインストールされます。

インストールが完了したら、以下のコマンドを実行してpipのバージョンを確認します：

```bash
pip3 --version
```
バージョン情報が表示されれば、pipのインストールは成功です。

これでpipがインストールされ、Pythonのパッケージをインストールすることができます。

### 1-2. 必要な機能をインストールする & HX711のリポジトリを複製する

まず、ブラウザからGPIOを操作するために次のコマンドをターミナルで実行します。
```bash
sudo pip3 install requests RPi.GPIO
```
また[1.HX711のセットアップ](https://qiita.com/drafts#1-hx711%E3%81%AE%E3%82%BB%E3%83%83%E3%83%88%E3%82%A2%E3%83%83%E3%83%97)で使用されているリポジトリをローカル環境に複製します。
```bash
git clone https://github.com/tatobari/hx711py
```

:::note warn
このときクローンしたhx711フォルダを**Thonny**で保存されているフォルダに入れておいてください。
:::

### 1-3. キャリブレーションの実施

先程のURLで提供されているプログラムを**Thonny**で実行します。

https://zenn.dev/kotaproj/books/raspberrypi-tips/viewer/270_kiso_hx711

:::note warn
ここに乗っているキャリブレーションの結果が出たら、キャリブレーションしたときに**載せた重りの重さ**と**計算結果のキャリブレーション値**を覚えるか保存しておいてください。

私は重りがなかったので、**スマホ(151g)** を置きました。
:::

## 2. Pythonスクリプトの作成
次に、以下のPythonスクリプトを作成します。このスクリプトは、HX711から重量データを取得し、そのデータをPOSTリクエストとしてGoogle Apps Scriptに送信します。POSTリクエストとは、インターネットを通じて情報を送信する一種の方法です。

https://qiita.com/kanataxa/items/522efb74421255f0e0a1

Raspberry Piでスクリプトを書くと言ったら大体これです。

https://www.indoorcorgielec.com/resources/raspberry-pi/raspberry-pi-python/

```python
import sys
import time
import requests
from hx711py.hx711 import HX711

# プログラムが中断された時に呼び出される関数
def cleanAndExit():
    print("クリーニング中")
    hx.power_down()  # HX711をパワーダウンする
    hx.reset()       # HX711をリセットしてゼロにする
    print("終了！")
    sys.exit()  　　　# プログラムを終了する

# HX711とピンの設定
hx = HX711(5, 6)  # DTピン = 5, SCKピン = 6
hx.set_reading_format("MSB", "MSB")  # HX711の読み取り形式を設定

# 重量センサーのキャリブレーション値
hx.set_reference_unit(414)

hx.reset()  # HX711をリセットしてゼロにする
hx.tare()   # ゼロ点を設定する
print("ゼロ点設定完了！重量データを取得中")

while True:
    try:
        # HX711から重量データを取得
        weight = hx.get_weight(5)
        print(weight + 151)  # 重量をコンソールに表示 + キャリブレーションしたときの重さ（私の場合 151g）

        # 重量データを送信するためのGoogle Apps ScriptのURL
        url = "https://script.google.com/macros/s/your-script-id/exec" # デプロイ後のScript URLを設定
        params = {"weight": weight + 151}  # 送信する重量データ + 送信するようにも重さを追加

        # 重量データをGoogle Apps Scriptに送信
        requests.post(url, data=params)

        hx.power_down()  # HX711をパワーダウンする
        hx.power_up()    # HX711をパワーアップする
        time.sleep(0.1)  # 0.1秒待つ

    except (KeyboardInterrupt, SystemExit):
        cleanAndExit()   # クリーンアップしてプログラムを終了する

```
このスクリプトをRaspberry Piにコピーし、適当な名前（例えばweight_sensor.py）で保存します。

::: note info
**オススメ実装方法の提案**
Raspberry Pi 4Bで今回は開発をしています（**推奨**）が、Raspberry Pi pico w などを利用すれば、比較的安価に実装することができそうです（**未検証のため実際のところは不明 以後検証機会、検証した人はコメントお願いします。**）

|製品名（省略）|URL|値段(おおよそ)|
|:---|:---|---:|
|**RasPi 4B**|https://onl.bz/B9DYGCu|¥16,000|
|**RasPi Pico W**|https://onl.bz/JsFHzbh|¥1,500|

**値段は10倍違いますが、よく考えて選んでみてください。（やりやすさ、自身の環境）**

それぞれの使い方については調べてみてください。沢山載っています。
:::
このURL短縮サイトで短縮させています。

https://url.onl.jp/

## 3. Google Spread Sheetの設定
次に、Google Spread Sheetの設定をします。Google Spread SheetはGoogleアカウントがあれば誰でも使える、Excelのようなものです。URLはGoogle Spread Sheetへのアクセス用です。

https://docs.google.com/spreadsheets/create?hl=JA

![Photokako-mosaic-5lw31gn7l2epUJSz.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/74792775-d25a-57cc-f28b-8dca8538da50.png)


今回は、このように表を作成しました。

## 4. Google Apps Scriptの設定

次に、Google Apps Scriptを設定します。Google Apps Scriptは、Googleのサービス（この場合はGoogle Spread Sheet）を操作するためのプログラムを書くためのツールです。

Google Spread Sheetのメニューバーにある拡張機能にある **「Apps Script」** を選択してください。
![Photokako-mosaic-7cpgeU4q96HvyrCJ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/b38b6d92-d436-7904-f791-4aad7d233438.png)


以下のスクリプトを新しいGoogle Apps Scriptプロジェクトに追加します：

```javascript
function checkCellAndUpdate() {
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1"); // シート名を適切に変更してください
  // それぞれの変数にセルデータを代入
  var weight = sheet.getRange("C3").getValue();
  var threshold = sheet.getRange("D3").getValue();
  var url = sheet.getRange("F3").getValue();
  var status = sheet.getRange("E3").getValue();
  
　// 通知する重量を下回った & ある時間に状態(〇)であったら
  if(weight < threshold && status != "×") {
    sheet.getRange("E3").setValue("×");
    MailApp.sendEmail({
      to: "your-email@example.com", // 送信先のメールアドレスを適切に変更してください
      subject: "重量が指定値を下回りました",
      body: "重量が指定値を下回りました。商品URLは以下の通りです：" + url
    });
  // 重量が通知する重量を超えた & ある時間に状態(x)であったら
  } else if(weight >= threshold && status != "〇") {
    sheet.getRange("E3").setValue("〇");
  }
}

```
これは、手順3で作成した表のセルデータを取得し、現在の重量が通知する重量を下回った時に、Gmailで商品URLとともに、通知するというコードです。

何回も通知するのが個人的には要らないので、今回は`else if`に**状態が一度更新されていたら次に、重量データが指定値より上回ることがなければ、メールが送られない**という風に設計しました。(毎日送信されない)

このスクリプトは **「トリガー」** を設定する必要があります。**「メニューバーに時計マークでトリガー」**　というものがあると思いますので選択してください。そこから **「トリガーを追加」** を選択して設定をします。

![5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/d36f3ddf-bcb7-6152-8eed-a25675f4c4c0.png)


設定内容は以下のようになっています。
![1.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/ccf141ad-5540-7e44-6962-390883ebf13a.png)
<hr>

```javascript
// POSTリクエストを受け取った時に呼び出される関数
function doPost(e) {
  // アクティブなスプレッドシートとスプレッドシート内の最初のシートを取得
  var sheet = SpreadsheetApp.getActiveSpreadsheet().getSheetByName("シート1");

  // POSTリクエストから重量データを取得
  var weight = e.parameter.weight;

  // セルC3の値を重量データに設定
  sheet.getRange("C3").setValue(weight);
}

```
これは、Pythonスクリプトから送られてきた重量データを受け取り、Google Spread Sheetの特定のセル（この場合はC3）にその値を設定するスクリプトです。

そして、このスクリプトをウェブアプリケーションとして公開します。これにより、**Pythonスクリプトからこのスクリプトにアクセスできる**ようになります。

公開するには、スクリプトエディタの上部にある **「デプロイ」** メニューから **「新しいデプロイ」** を選択して **「種類の選択」の歯車マーク**を押し、そこからから **「ウェブアプリ」** を選択します。

以下は工程画像です。
![2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/07ebb177-3fbe-c9f4-c8f0-ccd16641ab86.png)
![Photokako-mosaic-8ia6JiECYRA6ZZ35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/f1cc484a-da62-0db1-193e-204bdee5d013.png)
![Photokako-mosaic-siNJQLojq8dWDOkN.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/66c22962-7e25-d6bf-9be8-832410a9b11a.png)



公開後、**得られるURLをPythonスクリプトのurl変数に設定**します。これにより、PythonスクリプトはこのURLにデータを送信できるようになります。

## 5. Pythonスクリプトの実行
最後に、以下のコマンドを使用してPythonスクリプトを実行します：

```bash
python3 /path/to/your/script.py
```
これで、Raspberry PiとHX711を使用して重量データを取得し、そのデータをリアルタイムでGoogleスプレッドシートに送信するシステムが完成します。

#### Option : 定期的な実行
Pythonスクリプトを定期的に実行するためには、cronというツールを使用します。以下のコマンドをRaspberry Piのターミナルで実行し、crontabを開きます：

```bash
crontab -e
```
初めてcrontab -eを実行すると、エディタを選択するように求められます。ここでは、nanoを選択します（通常はリストの一番上にあり、デフォルトで選択されています）。選択するには、エンターキーを押します。

次に、以下のような行を追加します。( 自分のpathを入力してください )：

```bash
0 * * * * python3 /path/to/your/script.py
```
これにより、Pythonスクリプトは毎時0分に実行されます。

最後に、変更を保存します。nanoでは、`Ctrl+O`を押して保存し、`Ctrl+X`を押してエディタを終了します。

# 実行結果
このように送信されました。

![Photokako-mosaic-cXa1V0pyXPYEIn11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2989040/6afaaf1c-b459-46ee-cfa0-5fafa025d0f1.png)

この商品を買って、重量データが1~2時の間に更新されれば、状態がまた変化するようになります。


# まとめ
この記事では、Raspberry PiとHX711を使用して重量データを取得し、そのデータをリアルタイムでGoogleスプレッドシートに送信する方法とGmailに通知するシステムを紹介しました。このシステムを使用することで、重量データのモニタリングが容易になります。

ということで、IoT開発の流れを記事にしてみましたがいかがでしょうか？
重量データということで、汎用性はとても高いと思います。
ここまで材料が届いてから半日程度で完成する事ができたので、余り難しく考えずに皆さんもぜひIoTに取り組んでみてください。

**お願い**
急いで書き上げたので、間違いがあるかもしれません。あれば報告をお願いします。