GoogleAppsScriptとNetatmo ウェザーステーションで室内環境をSlackに通知する 


## やったこと
* 部屋の空気環境をbotで通知する  
<img width="1268" alt="スクリーンショット 2018-12-04 16.30.26.png" src="https://qiita-image-store.s3.amazonaws.com/0/322375/b54cfad7-80a1-6440-c0ac-a1028c68e9ad.png">


今回はオフィスでの利用なのでSlackに通知するbotですが、LINEに通知するbotもできます。
[LINE Notify][1]とかを使うとできるんじゃないでしょうか。

## CO2濃度てなんだろう

部屋で人が呼吸すると、あたりまえですが酸素が減って二酸化炭素が増えます。
つまりCO2濃度が上がるわけです。
これが高いと[思考力や判断力に影響を及ぼす][5]みたいな話あったりもしまして

「昼休み後や夕方以降なんか眠いなー仕事はかどらないなー」の原因はお昼ご飯を食べたからもあるけど 実は換気が足りてないんじゃないのという風潮がうっすら漂い始めたんですね。
僕自身も換気するとだいぶ違うなという実感はありましたし。
このbotを作って導入してから、どうやら自分は800ppmを超えたあがりから頭がぼーっとしがちだなとかがわかったりもしました。

実際に部屋やオフィスを測ってみるとわかりますがCO2濃度(ppm)が基準(1000ppmを超えたあたりから思考力や集中力に影響を及ぼすとされている)を上回ってることって意外と多いものでして、
そういう場合換気するだけで「なんだか午後眠い」「頭がぼーっとする」「会議がだるすぎる」とかを結構へらせるわけです。

> 350～450ppm　　 過剰な換気（外気：330～400ppm）
450～700ppm　　 理想的な換気レベル
700～1000ppm　　換気が不十分（室内では1000ppm以下に抑えることとされている※）
1000～1500ppm　 悪い室内空気環境（学校環境では1500ppm以下が望ましいとされいる）
1500～5000ppm　 これ以上の環境で労働をしてはいけない（労働安全基準法では、5000ppmが限度）
5000ppm以上　　　疲労集中力の欠如（締め切った車の中は、5000ppm以上になることもあるらしい）
※建築物衛生法、建築基準法、労働安全衛生法



## つかったもの
* [ウェザーステーション (NETATMO社)][2]
<img width="1669" alt="スクリーンショット 2018-12-04 16.35.18.png" src="https://qiita-image-store.s3.amazonaws.com/0/322375/9ee03aae-4e49-6a71-0da0-98e40d7808e9.png">


* [GoogleAppsScript][3]  

GASと言われるものですね。
GoogleAppsScriptってめちゃくちゃ便利で  

* もちろんサーバーいらず、24時間いつでも動かせる
* Gmail、Googleカレンダー、スプレッドシートとかGoogleのアプリケーションと簡単に連携できる 
* 無料のGoogleアカウントだけあればいい。開発環境いらないしJSライクで簡単に書ける  

個人レベルならこれだけでほとんど何でもできちゃうんじゃないかと、最近は思ってます。


## やりかた
手順ですね。
[ウェザーステーション][2]はスグレモノで、買って登録するだけでブラウザやスマホアプリから
室温・湿度・CO2濃度に加えて気圧や騒音、外気温まで見られたりするんですが  

* slack通知したい
* 一定の値を上回った/下回った などのアラートを出したい  

ということでGoogleAppsScriptを使ってbotをつくります。

### 準備

#### Slack
今回はSlackに投稿するbotなので、まずslackのappを作成し
webhook_url(アプリケーションから投稿するためのurl)を取得する必要があります。
下の`SLACK_WEBHOOK_URL` にあたるものですね。slackの公式ドキュメントとかググったほうがわかりやすいかと。

#### ウェザーステーション
* 買う
* 初期セットアップ
* NETATMOアカウント作成
* ステーションのIDなど  
これは下の`DEVICE_ID`,`CLIENT_ID`, `CLIENT_SECRET`にあたるものですね。  
[NETATMO社のページ][4]からログインしてアプリを作成すると取得できます。  
`DEVICE_ID` なんかはcurlコマンドでAPIを叩いてみるのも簡単に知る方法としてはいいかも。

#### GoogleAppsScript  

あとは書いていくだけですね。GAS固有の機能や使い方もあるんですが基本的にJSライクに書けます。
「Scriptを実行したときにNETATMOのAPIを叩いてSlackに通知する」だけでよければ
これだけ！

```JavaScript

function getStationsdata() {
  // WeatherStation constant
  const TOKEN_URL = 'https://api.netatmo.com/oauth2/token';
  const STATION_DATA_URL = 'https://api.netatmo.com/api/getstationsdata';
  const DEVICE_ID = '11:11:11:11:11:11';
  const CLIENT_ID = 'XXXXXXXXXXXXX';
  const CLIENT_SECRET = 'XXXXXXXXXXXXX';
  const USERNAME = 'XXXXXXXX@XXXX.XXX';
  const PASSWORD = 'XXXXXXXX';
  // Slack url
  const SLACK_WEBHOOK_URL = 'XXXXXXXXXXX';
  
  var auth_request = {
    'grant_type': 'password',
    'client_id': CLIENT_ID,
    'client_secret': CLIENT_SECRET,
    'username': USERNAME,
    'password': PASSWORD,
  };
  var auth_options = {
    'method': 'post',
    'contentType': 'application/x-www-form-urlencoded',
    'payload': auth_request
  };
  // tokenを取得
  var auth_response = UrlFetchApp.fetch(TOKEN_URL, auth_options); 
  var auth_json = JSON.parse(auth_response);
  var access_token = auth_json.access_token;
  
  var station_request = {
    'access_token': access_token,
    'device_id': DEVICE_ID,
  }
  var station_options = {
    'method': 'post',
    'contentType': 'application/x-www-form-urlencoded',
    'payload': station_request
  };
  // stationデータを取得
  var station_response = UrlFetchApp.fetch(STATION_DATA_URL, station_options); 
  var station_json = JSON.parse(station_response);
  var station_data = station_json.body.devices[0].dashboard_data;
  
  // 室温、湿度、CO2濃度
  var temp = station_data.Temperature;
  var humidity = station_data.Humidity;
  var pressure = station_data.Pressure;
  var co2_ppm = station_data.CO2;
  
  var slack_post_data = {
    'text': '現在のオフィス環境',
    'attachments': [
      {
        'color': 'good',
        'text': '室温: ' + temp + '℃\n' + '湿度: ' + humidity + '％\n' + 'CO2濃度: ' + co2_ppm + 'ppm',
        'footer': '投稿のfooterだよ'
      }
    ]
  };

  var payload = JSON.stringify(slack_post_data);
  var options = {
    'method' : 'post',
    'contentType' : 'application/json',
    'payload' : payload
  };
    
  // Slackへpost
  UrlFetchApp.fetch(SLACK_WEBHOOK_URL, options);   
}
```

#### さらに
ぼくの場合  

* 朝9時~21時で1時間おきに自動で今のオフィス環境を通知する
* 土日と祝日は実行しない  

というふうにしたかったのでGoogleAppsScriptのトリガー機能を工夫した使い方をして
上記の `getStationsdata() ` に加えて下のような関数を追記してみました。

```JavaScript

function createTriggers() {
  Logger.log('今日の実行計画を作成するよー')
  var now = new Date()
  var triggers = ScriptApp.getProjectTriggers()
  if (Array.isArray(triggers)) {
    triggers.forEach(function(trigger) {
      if (trigger.getHandlerFunction() === 'getStationsdata') {
        // 残っているトリガーのうちgetStationsdataのものだけ削除
        ScriptApp.deleteTrigger(trigger);
      }
    })
  }
  // 土日祝は実行しない
  if (isHoliday(now)) {
    Logger.log('今日はおやすみだよ。')
    return
  }
  // 平日の9:00〜21:00は1時間おきに実行Triggerを作成
  var hours = [9,10,11,12,13,14,15,16,17,18,19,20,21]
  hours.forEach(function(hour) {
    var date = new Date()
    date.setHours(hour)
    date.setMinutes(0)
    if (now.valueOf() < date.valueOf()) {
      // getStationsdata() のTriggerを指定した日時で作成
      ScriptApp.newTrigger("getStationsdata").timeBased().at(date).create()
    }
  })
}

function isHoliday(date) {
  if (date.getDay() === 0 || date.getDay() === 6) {
    return true
  }
  // 「日本の祝日カレンダー」から祝日を取得
  var calendar = CalendarApp.getCalendarById('ja.japanese#holiday@group.v.calendar.google.com')
  var events = calendar.getEventsForDay(date)
  return events.length > 0
}
```

ここまで書かなくてもGASには
5分おき、とか1時間おき、とか時間指定のトリガーは用意されてるんですが(選択するだけ)
指定した時間×回数 を毎日、のような複雑なトリガーは作成できないので
自分で毎日トリガーを作成するようにしました。

読んでのとおり、
`createTriggers` を毎朝実行するトリガーを1つ作成する
だけで毎朝こいつは
今日が土日じゃないかチェック → 祝日カレンダーから祝日チェック →
そうじゃなければ朝9時~21時で1時間おきに `getStationsdata()`を実行するトリガーを13個作成
をしてくれるわけです。ハッピー

## おわり
今回はNETATMOのウェザーステーション(ネタトモっていう響きで日本の会社だと思ってたけどフランスの会社だった)を使いましたが
同じように APIを提供している空気環境モニターデバイスで
見た目がインテリアになじみやすく、花粉の量とかも計測してくれる[Awair][6]というのがあるっぽい。

<img width="1504" alt="スクリーンショット 2018-12-04 16.38.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/322375/e39737f9-e428-b224-b373-457864d33a95.png">


こいつは屋外を測れないんですが、自分の部屋だったらこっちが好みだなー。
何はともあれGoogleAppsScriptできると便利だなと思った次第でした。

今のスクリプトだと1時間にいちど計測して換気をうながすだけなので、室温やCO2濃度をスプレッドシートに自動で記録していくようにすれば

* 設定した基準値を上回ったときだけbotで通知
* 換気して下がったらまた通知  

ということができそうなので、それもできたらいいなあ。




[1]:https://notify-bot.line.me/ja/
[2]:https://www.netatmo.com/en-us/weather/weatherstation
[3]:https://developers.google.com/apps-script/
[4]:https://dev.netatmo.com/en-US
[5]:https://newscenter.lbl.gov/2012/10/17/elevated-indoor-carbon-dioxide-impairs-decision-making-performance/
[6]:https://getawair.com/