LINE Thingsでごみの日通知アプリを作ってみた

## 作ったもの
ごみ箱に着けるタイプの”ゴミの日通知”IoTアプリ
LINE Things Awardに応募しました。
LINE bot上で動かせるLIFF(LINE Front-end Framework)を使って、obnizに情報を登録してobnizがゴミの日を通知してくれるアプリを作りました。

LINE thingsの良い所は独自のアプリを作らなくてもBLE経由でデバイスと接続しデバイスを操作する事ができる点と
デバイスからLINEへ自動的に通信を送る事ができる自動通信という機能を使ってbotからメッセージを送る事ができる点が良い点でした!

## 作った理由
1. ゴミを捨てるのを忘れてしまう事が多い
    2. 家を出てから、今日燃えるゴミの日だったぁあああ 生ごみぃぃぃと嘆くのが嫌だ。
2. ゴミ箱✖️IoTの方向性として
    1. ゴミの日カレンダーというサービスがあるので、それをデバイスに落とし込めば便利そうと思った。

## 使い方
1. LIFFを立ち上げて住んでいる地区のゴミ捨て情報を入力する
2. デバイス側にゴミの日情報を登録する
3. ゴミの日前日になると、botからメッセージが来る(自動通信) デバイスのLEDライトが光る
4. ゴミの日当日になると、デバイスから音が鳴りゴミ出しのリマインドをしてくれる

## 構成
![スクリーンショット 2019-12-11 23.05.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/549164/2e012591-69c8-155a-f691-6d5ec051c411.png)

LINE ThingsのBLE通信ができるメリットを活かすならwifiに接続できるobnizではなくても良いと思ったが、家にあったので採用しました！使い易くて最高でした！

## 開発の流れ
- LIFF側
    - 曜日登録画面の開発（友達にお願いした）
    - BLE連携部分の開発
- デバイス側
    - LINE THINGS連携
    - BLEで受け取った情報の処理
    - ゴミの日判定処理
    - 通知処理


## コード抜粋と開発のtips
### BLE接続について
obnizとLIFF間で共通のUUIDを頼りに接続している

``` LIFFでデバイスを探しているところ.js
    device.gatt.connect().then(() => {
        // Get service
        device.gatt.getPrimaryService(USER_SERVICE_UUID).then(service => {
          liffGetUserService(service);
        }).catch(error => {
            uiStatusError(makeErrorMsg(error), false);
        });
        device.gatt.getPrimaryService(PSDI_SERVICE_UUID).then(service => {
            liffGetPSDIService(service);
        }).catch(error => {
            uiStatusError(makeErrorMsg(error), false);
        });

        // Device disconnect callback
        const disconnectCallback = () => {
            // Remove disconnect callback
            document.getElementById("log").innerText = "failed";
            device.removeEventListener('gattserverdisconnected', disconnectCallback);
            // Try to reconnect
            initializeLiff();
        };
        device.addEventListener('gattserverdisconnected', disconnectCallback);
    }).catch(error => {
        document.getElementById("log").innerText = "gets";
        uiStatusError(makeErrorMsg(error), false);
    });
```
### データのやりとり
``` LIFFからデバイスにデータを送るところ.js
  function submitValue(array){
    let param = localStorage.getItem('param');
    let str = JSON.stringify( param );
    window.writeCharacteristic.writeValue(
      Uint8Array.from(str.split(""), e => e.charCodeAt(0))
    ).catch(error => {
      document.getElementById("log").innerText = error;
        uiStatusError(makeErrorMsg(error), false);
    });
  };
```
``` デバイスでデータを受け取るところ.js
  writeCharacteristic.onwritefromremote = function(address, newvalue) {
    let str = Array.from(newvalue, e => String.fromCharCode(e)).join("");
    param = JSON.parse(str);
  }
```
UUIDを用いて取得するCharacteristicオブジェクトを使ってcharasteristicに値を読み書きします。
便利。

``` charasteristic.js
  var writeCharacteristic = new obniz.ble.characteristic({
    "uuid" : writeCharacteristicUUID,
    "properties" : ["write"],
    "data" : [0x00]
  });
```
### ごみの日チェック
``` ゴミの日チェック.js
    StartTimer = function() {
      // 30分ごとの処理
      timerID = setInterval(Timer, 1800000);
    }
    StopTimer = function() {
      clearInterval(timerID);
    }
    Timer = function() {
      if(!getParamFlag)
        return;
      }
      let today = new Date();

      checkDaysSchedule(today);
      // checkDaysSchedule(tomorrow);
    }

    function checkDaysSchedule(day){

      let date = weekdays[day.getDay()];
      let weekNum = Math.floor((day.getDate() - day.getDay() + 12 ) / 7);
      if(isSchedule) {
        checkSchedule(date, weekNum);
      }
    }

    function isSchedule(date){
      return param["schedule"][date] != null;
    }

    async function checkSchedule(date, weekNum){
    let schedule = param["schedule"][date];
      let garbageInfo = param["garbageInfo"][schedule];
      garbageInfo["frequency"].forEach(function(e) {
        if(e == weekNum){
          let output = "";
          output += date + "は" + schedule + "日です。\n";
          output += garbageInfo["hour"] + "時" + garbageInfo["min"] + "収集です。";
          obniz.display.print(output);

          NotifyToLine();
          swichLed(true);
        }
      })
    }
```
タイマー回して30分ごとに通知をする必要があるかどうかを判別しています！

## 苦労した点
- BLEの接続段取り
- Android端末だと上手く連携できずに、iPhoneを購入した結果貧しい生活を送ることになった点

## 楽しかった点
- BLEでデバイスで値を受け取った時!!!
- LINEから自動通信でメッセージを受け取った時!!!

# また何か作ります！

## 参考にした記事
[LINE Things 自動通信機能 ハンズオン] (https://qiita.com/hktechno/items/12781e38b09e10c20da2)