快適な睡眠を目指して寝床内気象を測定する(温度編) #sleeptech

## 良い睡眠を取るために

みなさん、良い睡眠は取れていますか？　？
私は 1 日に夜 8 時間睡眠+日中仮眠を数回取らないと夕方にはクタクタになってしまいます。

毎日 8 時間睡眠を取るのはなかなか難しいので、睡眠の質を上げていきたいわけです。

その一環として、前回の記事([よく風邪を引くのでちょうどいい布団を教えてくれるLINE BOT作った](https://qiita.com/tmisuo0423/items/a00223ebd603a911ddd9))でちらっと紹介しましたが、今回は**寝床内気象**にフォーカスを当てたいと思います。

## 寝床内気象とは？

寝床内気象でググるといろんなサイトがヒットします。

- [寝室環境・寝床内の研究 ぐっすり眠るために最適な温度や湿度は？](https://www.nishikawasangyo.co.jp/company/laboratory/kankyo/)
- [寒い夜も快眠したい！「寝床内気象」を快適に保つには？](https://www.chintai.net/news/2013/12/19/275/)
- [寝床内気象　良い睡眠のための環境つくり](https://www.tsukurupajama.jp/pajamapedia/sleep/2128)

寝床内気象とは、快適な眠りに関わる条件のうち、**布団内の温度・湿度**のことを指すようです。

![bed-temp.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/25a90010-b641-4c36-014d-e8c2b1916634.jpeg)
(「[寝室環境・寝床内の研究 ぐっすり眠るために最適な温度や湿度は？](https://www.nishikawasangyo.co.jp/company/laboratory/kankyo/)」より引用)

日本睡眠化学研究所さんの研究によると、

>理想的な寝床内温度・湿度を明らかにするために数々の実験を重ね、その結果、「温度33±1℃」「湿度50±5%RH」という数値を導きだしました。

とのこと。

つまり、良い睡眠を得るためには、布団の温度を湿度が適切な値になっている必要があるようです。
手元に Obniz と温度センサーがあったので、早速温度を測る準備を始めましょう（湿度はまた今度）

ところで寝床内気象って何て読むんでしょうか…ねどこないきしょう？　しんしょうないきしょう？

## アプリイメージ

- 5 分ごとに布団内部の温度を測りデータベースに登録することで、データを集めていく。
![app-image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/d8c0151b-d33d-18ab-f54b-aebb2234ddbd.jpeg)


## システムイメージ

- マイコンの知識がないので、お手軽に使える Obniz を使用。
- Lambda を使って、Obniz からの温度取得と DynamoDB への保存を行う。
- 上記処理を Cron 実行させるため、CloudWatchEvents を使用

![sys-image.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/bdd1aa71-e391-ea40-52cb-ad9c1d3184c4.jpeg)


## 回路イメージ

今回は Obniz でお手軽に実装するため、[ObnizのJSパーツライブラリ](https://obniz.io/ja/sdk/parts)で対象となっている温度センサーを使用していきます。

### Obniz

Obniz とは、

>obniz（オブナイズ）は、ON/OFFやUART通信などのIO制御をクラウドのAPI経由で行える仕組みです。センサーやアクチュエーター、既存機器をネットワーク経由で直接操作でき、クラウド中心のIoT開発が可能です。

とのこと。青色のかわいいやつです。
公式サイト→ https://obniz.io/ja/

### 使用した素子

- 温度センサー：LM35DZ (http://akizukidenshi.com/catalog/g/gI-00116/)
  - gnd: io0, output: io1, vcc: io2 に接続します。
- 青色 LED(デバッグ用) (http://akizukidenshi.com/catalog/g/gI-06247/)
  - anode: io3, cathode: io4 に接続します。

接続イメージは以下の通り。
![circuit.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/0df17a8d-cbb6-b938-debf-30954d7f227f.jpeg)

## 処理の流れ
### Lambda関数

大まかな処理の流れは、
　（1）Obniz から温度取得
　（2）DynamoDB への保存
です。

ソースをピックアップして説明します。

- Obniz に接続、LM35DZ から温度を取得する。  
[Obniz JSパーツライブラリのドキュメント](https://obniz.io/ja/sdk/parts/LM35DZ/README.md)がとても分かりやすいので、こちらを一読するのをオススメします。

```javascript:Obnizに接続
const Obniz = require('obniz');
const obniz = new Obniz(process.env.OBNIZ_ID);

const getTemperature = async () => {
  await obniz.connectWait(); // 接続を試し、接続するまで待つ
  const tempsens = obniz.wired("LM35DZ", { gnd:0 , output:1, vcc:2});
  return await tempsens.getWait(); // センサーの温度を取得
}

getTemperature().then((temperature) => {
  console.log(`${temperature}度`);
})
```

- 取得した値を DynamoDB に保存する。
  DynamoDB の操作には、DocumentClient（[公式ドキュメント](https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/DynamoDB/DocumentClient.html)）を使います。

```javascript:取得した温度をDBへ保存
const AWS = require('aws-sdk');
const documentClient = new AWS.DynamoDB.DocumentClient();

const uuidv4 = require('uuid/v4');
const dayjs = require('dayjs');

documentClient.put({ // putメソッドでDynamoDBにアイテムを作成
  TableName: 'BedSensorTable',
  Item: {
    dataId: uuidv4(), // パーティションキー。UUIDを入れる。
    created: dayjs().unix(), // ソートキー。現時刻のUNIX時間を入れる。
    temperature: temperatureValue // 上記で取得した温度を入れる。
  }
}).promise();
```

### CloudWatchEvents

上記で作成した Lambda 関数を 5 分に 1 回実行するようにルールを設定する。  
`AWSコンソール > CloudWatch > ルール > ルールの作成`から適当にルールを作る。

![cloudwatchevents.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/65fe4da9-7cac-9427-6d91-8ff5dab91ba9.jpeg)

これで完成！

## 早速設置し、寝てみる

ベッドに設置してみた。
![bed.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/aed96d98-04ce-c21a-bdf8-116158525a99.jpeg)
うん。なかなかシュールだ。
シーツをかけると見た目は普通のベッドになりました。
![bed2.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/f8e8debb-8095-4de6-9f7c-ca578c422afd.jpeg)

実際に寝てみる。ベッドが柔らかいおかげか、意外と気にならなかった。

結果は、こんな感じとなった。
![result.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/2ebbe149-1785-0b4e-1264-400829718d7a.png)

布団に入ると内部の温度が上昇し、40±2℃くらいで推移しているようです。
体感ではちょうど良い温度だったのですが、33℃前後って少し寒いのでは…？

## 改善したいこと

- 意外と気にならないとは言っても、無意識にセンサーを避けて寝ていた。また、寝ていて Obniz の熱を感じる。  
Obniz の熱＋温度センサーが近い＝温度が高めに取得されている？  
どちらにせよ壊れるのはいやなので、Obniz とセンサーの間にケーブルを入れて、Obniz はベッドの外に出したほうがよさそう。
- Obniz 直挿しだと素子がすぐ抜けてしまう。ちゃんとやるならはんだ付けなどをしないと。
![morning.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/90087/22c12c58-b189-26f6-29c2-d2d01b226aa6.jpeg)
- 温度の見える化。時間の関係で、見える化にまでは至らなかった。[LINE LIFF](https://developers.line.biz/ja/docs/liff/overview/)の v2 が公開されたらしいので使ってみたい。
  - 記事書きました。(2019/11/28 更新)
  - →https://qiita.com/tmisuo0423/items/1044e4ee96e6868ae17e


## 詰まったところ

### Obniz接続時のエラー(Error: ad 1 is not valid io)

Obniz を使って温度センサーの値を取得しようとすると以下のようなエラーが出てきた。

```typescript
const Obniz = require('obniz');
const obniz = new Obniz(process.env.OBNIZ_ID);

const tempsens = this.obniz.wired("LM35DZ", { gnd:0 , output:1, vcc:2});
const result = await tempsens.getWait();
console.log(result);
```

``` json
{
  "errorType": "Error",
  "errorMessage": "ad 1 is not valid io",
  "trace": [
    "Error: ad 1 is not valid io",
    "    at Obniz.getAD (/var/task/node_modules/obniz/obniz/ObnizComponents.js:200:13)",
    "    at LM35DZ.wired (/var/task/node_modules/obniz/parts/TemperatureSensor/analog/AnalogTemperatureSensor.js:11:21)",
    "    at Obniz.wired (/var/task/node_modules/obniz/obniz/ObnizParts.js:54:17)",
    "    at Runtime.exports.handler (/var/task/index.js:5:26)",
    "    at Runtime.handleOnce (/var/runtime/Runtime.js:66:25)",
    "    at process._tickCallback (internal/process/next_tick.js:68:7)"
  ]
}
```

[ドキュメント](https://obniz.io/ja/doc/sdk/doc/connection)をちゃんと見ると、onconnect のコールバックとして温度取得の処理を入れないといけないらしい。

```typescript
const Obniz = require('obniz');
const obniz = new Obniz(process.env.OBNIZ_ID);

obniz.onconnect = async function() { // 追加
  const tempsens = this.obniz.wired("LM35DZ", { gnd:0 , output:1, vcc:2});
  const result = await tempsens.getWait();
  console.log(result);
}
```

なんか書きにくいなぁと思いながらドキュメントを眺めていると、`connectWait関数`なる関数を発見。

```typescript
const Obniz = require('obniz');
const obniz = new Obniz(process.env.OBNIZ_ID);

obniz.connectWait().then(async () => { // connectWaitに変更
  const tempsens = obniz.wired("LM35DZ", { gnd:0 , output:1, vcc:2});
  const result = await tempsens.getWait();
  console.log(result);
});
```

最終的に、温度を 1 回分取得する関数として以下のように落ち着いた。

```typescript
const Obniz = require('obniz');
const obniz = new Obniz(process.env.OBNIZ_ID);

// きれいになった
const getTemperature = async () => {
  await obniz.connectWait();
  const tempsens = obniz.wired("LM35DZ", { gnd:0 , output:1, vcc:2});
  return await tempsens.getWait();
}

// 使うときはこんな感じ。async/awaitで書いてもよい。
getTemperature().then((temp) => {
  console.log(temp);
})
```