傘置き忘れ防止ストラップ(プロトタイプ)

3人でハッカソン(じゃないけど限られた時間で)IoT製品のプロトタイプ作りました
# 機能
- 持ち主が傘を置いてから**指定した時間**経過したらLINEで通知(通知手段は変更可能)
    - 通知する前に傘を持ち主が持ったら通知はしない
- 時間の指定はロータリースイッチで３段階設定出来る
    - 3段階の具体的時間についてはWeb上で具体的な時間を設定できる
- 加速度がうまく取れない時(主に電車内を想定)用にタイマーだけを頼りに動作するモード
![スクリーンショット 2018-08-30 19.42.19.png](https://qiita-image-store.s3.amazonaws.com/0/285348/ec5b9ab4-dbe4-87fb-5a61-984568939cb7.png)

#利用したもの
- raspberryPi3
- 加速度センサ
- ロータリースイッチ
- 配線に使うもの(ブレッドボードやケーブル)
- IFTTT

#配線
ブレッドボードビューはFritzingを使用させていただき、作成しました(http://fritzing.org/home/)
![スクリーンショット 2018-08-30 18.08.15.png](https://qiita-image-store.s3.amazonaws.com/0/285348/1da10968-fd3b-ec97-7bc8-c3ae7950a5a0.png)
ロータリースイッチは使用したものがfritzingで見つからなかったので代用しましたがその部分は以下のような配線です
![配線.jpg](https://qiita-image-store.s3.amazonaws.com/0/285348/297ed5af-3f12-3592-41d9-5a0d48e04c7a.jpeg)

#プログラム
```index.html
<!doctype html>
<html>
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, user-scalable=no, initial-scale=1">
    <title>傘の置き忘れ通知</title>
    <script src="../../polyfill/polyfill.js"></script>
    <script src="../../drivers/i2c-grove-accelerometer.js"></script>
    <script src="./main.js"></script>
    <style>
      body {
    	text-align:center;
      }
      #display p{
        background: #F4E8FF;
        font-size: 24px;
        padding: 0.7em;
      }
      span {
      	margin: 0 0.5em;
      	padding: 0.3em;
      	border: 2px solid #3A9F00;
      	background: white;
      }
      hr{
      	border: 2px dotted red;
      }
      #setting #title {
      	border-radius: 10px;
      	padding:0.2em;
      	font-size: 24px;
      	background: #CDE9FF;
      }
	#minute {
		list-style-type: none;
	}
	#train li {
		display: inline-block;
		width:3em;
		background: #800000;
		color: white;
	}
    </style>
  </head>
  <body>
	<div id="display">
		<p>加速度センサーのy座標:<span id="ay">---</span></p>
		<p>通知まで:<span id="count">---</span><!--vBいらない-->秒</p>
	    <!--<div id="ledview"></div> --> 
	    <p><!--現在動いているかid:isMoving-->現在傘が動いているか:<span id="isMoving">---</span></p>
	 	<p><!--何%動いているか-->直近の計測中傘が動いている割合:<span id="movement">---</span>%</p>
	</div>
	<div id="setting">
		<div id="title">設定</div>
		<ul id="minute">
			<li>モード0:<input type="text" value="999999" id="iTime0" />秒</li>
			<li>モード1:<input type="text" value="60" id="iTime1" />秒</li>
			<li>モード2:<input type="text" value="120" id="iTime2" />秒</li>
			<li>モード3:<input type="text" value="180" id="iTime3" />秒</li>
		</ul>
		<p>↓電車内モード↓</p>
		<ul id="train">
			<li>0 <input type="checkbox" id="mode0" /></li>
			<li>1 <input type="checkbox" id="mode1" /></li>
			<li>2 <input type="checkbox" id="mode2" /></li>
			<li>3 <input type="checkbox" id="mode3" /></li>
		</div>
	</div>
  </body> 
</html>

```

```main.js
'use strict';

window.onload = function(){ 
//onload = function () {
  mainFunction();
}


async function mainFunction() {
  var ay = document.querySelector('#ay');
  var movement = document.querySelector('#movement');
  var isMovingHTML = document.querySelector('#isMoving');
  var count = document.querySelector('#count');

  var intervalTime = -100 //n*60*1000 = n min 
  var valueBefore = 0;
  var countdown = intervalTime; 
  var movePercent = 60;
  
  var alerting = function () {

    let data = "value1=" + (intervalTime / 60) + "&value2=&value3";
    var url = "https://maker.ifttt.com/trigger/LINE/with/key/---";//URL最後の部分だけ隠しました
    var xhr = new XMLHttpRequest();
    xhr.open("POST", url);
    xhr.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
    xhr.send(data);

  }

  //ロータリースイッチ関連のセットアップ
  var oldRotary = -1;
  var gpioAccess = await navigator.requestGPIOAccess();
  //tgtText.innerHTML = "requestGPIO sucsess";
  var firstInputPort = gpioAccess.ports.get(5);
  var secondInputPort = gpioAccess.ports.get(4);
  var thirdInputPort = gpioAccess.ports.get(6);
  //tgtText.innerHTML = "ports.get sucsess";
  await firstInputPort.export("in");
  await secondInputPort.export("in");
  await thirdInputPort.export("in");

  //加速度センサーのセットアップ
  var i2cAccess = await navigator.requestI2CAccess();
  var port = i2cAccess.ports.get(1);
  var groveaccelerometer = new GROVEACCELEROMETER(port, 0x53);
  await groveaccelerometer.init();

  var term = 0;
  let checkTime = 10;
  var moment = [checkTime];

  //メインループ
  while (true) {
    var values = await groveaccelerometer.read();
    console.log('values(x,y,z):', values.x, values.y, values.z);
    //ax.innerHTML = values.x ? values.x : ax.innerHTML;
    ay.innerHTML = values.y ? values.y : ay.innerHTML;
    //az.innerHTML = values.z ? values.z : az.innerHTML;

    count.innerHTML = countdown;  //for debug

    //スイッチの状態読み取り
    var rotaryValue;
    if (!await firstInputPort.read()) {
      rotaryValue = 1;
    } else if (!await secondInputPort.read()) {
      rotaryValue = 2;
    } else if (!await thirdInputPort.read()) {
      rotaryValue = 3;
    } else {
      rotaryValue = 0;
    }
    

    //スイッチの状態に応じてintervalTimeを変更
    switch (rotaryValue) {
      case 0: intervalTime = document.querySelector('#iTime0').value;
        break;
      case 1: intervalTime = document.querySelector('#iTime1').value;
        break;
      case 2: intervalTime = document.querySelector('#iTime2').value;
        break;
      case 3: intervalTime = document.querySelector('#iTime3').value;
        break;
    }

    //動いたかどうかの判定(30秒間)
    var isMoving;
	  term = (term+1) % checkTime; //ターン進行
    if (Math.abs(values.y - valueBefore) >= 1)//ここの値は要検討
    {
      moment[term] = true;
      isMovingHTML.innerHTML = "動いた";
    }
    else {
      moment[term] = false;
      isMovingHTML.innerHTML = "不動なり。";
    }
    
	  var j;
	  var countJ = 0;
	  for(j=0;j<checkTime;j++){
		  if(moment[j]){
			  countJ++;
		  }
    }


    
    //動いてる率が一定値を上回るか
	  if((countJ / checkTime) * 100 > movePercent){
      isMoving = true;
      movement.innerHTML = "<font color='red'>" + parseInt( (countJ / checkTime) * 100 ) + "</font>";
	  } else{
      isMoving = false;
      movement.innerHTML = parseInt( (countJ / checkTime) * 100 );
	  }

    switch (rotaryValue) {
      case 0:  isMoving = document.querySelector('#mode0').checked ? false : isMoving;
        break;
      case 1:  isMoving = document.querySelector('#mode1').checked ? false : isMoving;
        break;
      case 2:  isMoving = document.querySelector('#mode2').checked ? false : isMoving;
        break;
      case 3:  isMoving = document.querySelector('#mode3').checked ? false : isMoving;
        break;
    }

      if(oldRotary != rotaryValue)
	{
		isMoving = true;
		oldRotary = rotaryValue;
  	}

    if (isMoving)
    {
      //傘もってる！
      countdown = intervalTime;
    }
    else {
      //もってない！
      countdown--;
      if (countdown == 0) {
        alerting();  
      }
    }

    valueBefore = values.y;

    await sleep(1000);
  }
  //}).catch(e => console.error('error', e));
}

//msミリ秒待つ関数
function sleep(ms) {
  return new Promise(function (resolve) {
    setTimeout(resolve, ms);
  });
}
```

#IFTTT
IFTTTによってLINEに送信されるメッセージは次のようです![S__41279498.jpg](https://qiita-image-store.s3.amazonaws.com/0/285348/10496f8f-916c-d1cf-e943-fa1201c80b05.jpeg)



#特に時間を要したこと
- (持ち主以外が同じ傘立てから傘を探すときなど)何かの拍子で傘が動いてしまったときに、アラームがリセットされないようなアルゴリズム
- 通知手段の模索 (**IFTTT**にたどり着くまでに時間がかかってしまった)


#追記
- 時間が短く設定されているなどプロトタイプ仕様になっています

- 傘忘れ防止を目標にプロトタイプを制作したが、傘以外にも使える汎用性のある製品に出来る可能性もあったのではとご指摘。少し視野が狭くなっていたよう。

- 課題・未実装部分がいくつかあります。
**未実装1**
Webアプリケーションなりスマホアプリケーションなどで時間の設定を出来るように
**課題１**
　電車用に実装したタイマーのみによる通知モードだが、いちいちアプリを開いて時間指定することは現実的ではない(不便)。
　現状、あらかじめ設定した時間でのみの利用となる。通勤ルートにおける時間をあらかじめ設定して利用。
**課題2**
　安直にY座標方向の数値で判定してしまったがベクトルで数値をとったほうがより正確に動きをとることが出来る。
　センサの特性をより理解することが必要。