座りすぎ検知君

# 作品概要
1. Raspberryに接続した超音波センサからディスプレイから物体への距離を30秒毎に計測する。
2. 計測した距離情報をスプレッドシートに追記する。
3. スプレッドシートに距離情報を追記したタイミングで2時間で一度もディスプレイから1m以上離れていなければ、警告する内容をLINEに送信。
## 必要な物
- HC-SR04(距離センサー)
- Raspberry pi 4 
- LINE アカウント
- LINE Notify アカウント
## 利用するサービス
- Google スプレッドシート
- Google Apps Script
- LINE Notify
## 作り方の手順

### Google Apps Scriptの設定方法
1. 距離情報を記録するスプレッドシートの拡張機能からApps Scriptを選択する。![IMG_4521.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/0e070ea6-5019-4759-cc53-e232959a7011.jpeg)

2. コードを記載する。
```javascript
function doGet(e) {
  let distance = e.parameter.data1;


  //現在日時を取得
  let now = new Date();

  //スプレッドシートの最終行の1つ下の行に現在時刻と距離情報を追記
  let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = spreadsheet.getActiveSheet();
  sheet.appendRow([now,distance]);

  let lastRow = sheet.getLastRow();

  //const COUNT2H = 120;
  //const COUNT3H = 180;
  const COUNT2H = 5;
  const COUNT3H = 10;

  //配列初期化
  let baseArray = [];

  //直近の測定180回分(3時間分)の距離情報を取得して配列化
  for (let i = 0; i < COUNT3H; i++) {
    //取得対象のセルから値を取得
    let int = lastRow-i;
    let range = sheet.getRange("B"+int);
    let value = range.getValue();
    baseArray.push(value);
  }

  //二時間以内に席を立った回数
  let leave2h = 0;
  //三時間以内に席を立った回数
  let leave3h = 0;

  //取得した3個の距離情報のうち、距離が80以下の値の数を特定
  leave3h = baseArray.filter(function(item) {
    return item > 80;
  }).length;

  leave2h = baseArray.slice(0,COUNT2H).filter(function(item) {
    return item > 80;
  }).length;

  if (leave2h > 0) {
      // 通知を行わない
      console.log("警告通知不要");
  } else {
    // 通知を行う
    console.log("警告通知を行う");

    // LINEへ警告メッセージを送信する
    // 通知メッセージ設定
    let messageText = ''
    if (leave3h > 0) {
      messageText = '2時間以上座ってるよ！\nそろそろ体を動かそうね！'

    }else (
      messageText = '3時間以上座ってるよ！\nまずいよ!!!'
    )


    //LINEトークン設定
    //LINE Notifyの設定時に取得したトークンをここで設定する
    let token = ""

    //通知内容設定
    let options = {
      "method" : "post",
      "headers" : {
        "Authorization" : "Bearer "+ token
      },
      "payload" : {
        "message" : messageText
      }
    }
    //通知送信要求
    let url  = "https://notify-api.line.me/api/notify"
    UrlFetchApp.fetch(url, options)
  }
}


function del() {
  //スプレッドシート内の最終行を取得
  let spreadsheet = SpreadsheetApp.getActiveSpreadsheet();
  let sheet = spreadsheet.getActiveSheet();
  let lastRow = sheet.getLastRow();

  if(lastRow > 2000){
   sheet.deleteRows(1,1500);
   console.log("古い1500件の距離情報を削除しました。")
  }
}
```

3.コードを記載し、右上のデプロイから「新しいデプロイ」を選択する。
![IMG_4522.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/e45eebcd-2e36-f626-37b4-273a41c00f0a.jpeg)

4. 左メニューの歯車マークから「ウェブアプリ」を選択し、左メニューにウェブアプリが表示されていることを確認しデプロイを選択する。
![IMG_4524.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/85487208-e70f-5fae-2bf0-7e2ae7044fca.jpeg)

5. デプロイ実行後、表示される「ウェブアプリ」のURLをRaspberryPiのコードに貼り付けします。![IMG_4523.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/32830946-15a2-fc21-1589-84def62c5e3f.jpeg)

***※GASのコードを更新した場合はコードの保存だけではなく、「デプロイを管理」からバージョンを更新するようにする。***

### LINE Notifyの設定方法

1. LINE Notifyに通知対象のアカウントでログインし、「トークンを発行する」を選択する。
![IMG_4528.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/3c0b59aa-ec46-a9d7-136d-9561cb48c3ea.jpeg)

2. トークン名と通知対象アカウントを指定します。
トークン名は通知メッセージに含まれます。
通知対象のアカウントでログインしている場合、「1:1でLINE Notifyから通知を受け取る」を選択する。
![IMG_4527.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/bd8b6698-4d50-d49b-cab2-079ccfbe854b.jpeg)

3.画面に表示されたトークンをGASのコードにて設定する。
画面に記載の通り、ここで表示されるアクセストークンはこの画面を閉じると2度と表示されないので紛失しないように気をつけましょう。
ここで取得したトークンをGAS側のコードに設定する。
![IMG_4530.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/4d2ea8ec-fc47-e181-d576-4f358a1922e8.jpeg)

### RaspberryPi側の設定方法
[GitHubのソースコードはこちらから](https://github.com/CarteClaire/RJP)


1. ラズベリーパイに距離センサーを繋げる(HC-SR04)
![超音波距離センサー_ブレッドボード-768x684.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/a11dd0e2-1a6f-191b-8277-45e68b19fbd1.png)

2. ラズベリーパイに距離センサーを動かすためのプログラムを書く
```python
import RPi.GPIO as GPIO
import time
import sys
import requests

url = 'ここにspreadsheetのURL名'

# HIGH or LOWの時計測
def pulseIn(PIN, start=1, end=0):
    if start==0: end = 1
    t_start = 0
    t_end = 0
    # ECHO_PINがHIGHである時間を計測
    while GPIO.input(PIN) == end:
        t_start = time.time()
        
    while GPIO.input(PIN) == start:
        t_end = time.time()
    return t_end - t_start

# 距離計測
def calc_distance(TRIG_PIN, ECHO_PIN, v=34000):
    
    # TRIGピンを0.3[s]だけLOW
    GPIO.output(TRIG_PIN, GPIO.LOW)
    time.sleep(0.3)
    # TRIGピンを0.00001[s]だけ出力(超音波発射)        
    GPIO.output(TRIG_PIN, True)
    time.sleep(0.00001)
    GPIO.output(TRIG_PIN, False)
    # HIGHの時間計測
    t = pulseIn(ECHO_PIN)
    # 距離[cm] = 音速[cm/s] * 時間[s]/2
    distance = v * t/2
    return distance

# TRIGとECHOのGPIO番号   
TRIG_PIN = 27
ECHO_PIN = 18

# 気温24[℃]の場合の音速[cm/s]
v = 33150 + 60*24

# ピン番号をGPIOで指定
GPIO.setmode(GPIO.BCM)
# TRIG_PINを出力, ECHO_PINを入力
GPIO.setup(TRIG_PIN,GPIO.OUT)
GPIO.setup(ECHO_PIN,GPIO.IN)
GPIO.setwarnings(False)

while True:
    try:
            
        # 距離計測(TRIGピン番号, ECHO_PIN番号, 音速[cm/s])
        distance = calc_distance(TRIG_PIN, ECHO_PIN, v)
        print(distance)
        requests.get(url+str(distance))
        #payload = {'data1':distance}
        #headers = {"Content-Type": "application/json"}
        #r = requests.post(url, data=payload,headers=headers
        #print(r)
            
        time.sleep(1)                          #5秒間待つ

    except KeyboardInterrupt:       #Ctrl+Cキーが押された
        GPIO.cleanup()              #GPIOをクリーンアップ
        sys.exit()                  #プログラム終了
```

#### 実際の通知画面
![LINE_capture_691847115.290963.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2981820/40578b94-b482-552c-4b5d-c1d35ae32ff2.jpeg)

こんな感じです。
長時間椅子に座ってゲームをしていたら「もうこんな時間」なんて事があり、次の日が学校なのにも拘わらず遅くに寝てしまい睡眠不足で行くことになってしまったり、長時間座ること自体が健康にもよくないので警告するシステムを作ろうと考えました。