オフィスのCO2(二酸化炭素)濃度を測定しSlack Botにしゃべらせる

# まとめ

測定したり可視化したりするのが好きなので、Netatmo + Netatmo API + hubot でslackにオフィスの温度・湿度・二酸化炭素濃度を通知して快適なオフィス環境を維持できるようにしました。

センサーをそろえてRaspberry Piを使って実現、もできるのですが、校正や運用を考えるとNetatmoを買ってさくっとAPIで繋いでしまったほうが楽でハードの知識も不要なのでオススメです。

![image](https://qiita-image-store.s3.amazonaws.com/0/54356/73202f58-5ea8-8a75-cc82-8b941d8c3cf8.png)

運用開始後は、Slack上でBotがCO2濃度を教えてくれるので、気づいた人が話しかけて随時換気される文化?ができ、おおむね1000ppm程度に維持されるようになりました。

# 背景

夕方になると頭痛がする、、集中力が切れる、みたいな症状に悩まされていませんか？
私が働いている会社もメンバーが増えるにつれ、夕方になると頭痛だったり空気が悪い感じがしたりする、というのに悩まされていました。

推測するな計測せよ、ということでインフラチームが測定のため、据え置き式のCO2測定器を設置してくれて頭痛がしたりするときには1000ppmを越える二酸化炭素濃度になっていることが多い、というのがわかってきました。

ただ、据え置き式だといちいち見に行かないといけないし、Slack上でほとんど生活してるのでSlack上で環境測定した結果を見れるようにしたい、ということでいくつか検討しました。

パーツから組み立てても良かったのですが、簡単に実現すべく、既存の製品でAPIでデータが取れるNetAtmoを購入しました(自腹)。

# 購入したもの

Netatmo Weather Station
https://www.netatmo.com/ja-JP/product/weather-station

Wifiに繋いでクラウド上にデータを蓄積できて、それを取得するAPIがあって、センサーのデータが取れる、というのがキモです。
https://dev.netatmo.com/doc

自腹すると高いので、会社で買ってもらえると良いですね。
この記事を稟議書に添付して社内稟議にご活用下さい。

# 実装

## npm

netatmoのパッケージがあるのでそのまま使います。測定結果はクラウド上にあるので、最新のデータをAPIで取得するだけです。
https://www.npmjs.com/package/netatmo

![image](https://qiita-image-store.s3.amazonaws.com/0/54356/dd4a76f6-9df0-1ecf-ffcc-1c13281ffd40.png)



## hubot-script (抜粋)

「二酸化炭素」「CO2」などに反応するようにしています。
インフルエンザの時期は予防のため湿度のアドバイスもするように。
先人のコードをコピペしたナゲヤリなコードですが参考になれば。

```coffeescript

Netatmo = require('netatmo')
moment = require('moment')

options_office =
  device_id: 'xxxxx'
  scale: "max"
  type: [
    "Temperature"
    "CO2"
    "Humidity"
    "Pressure"
    "Noise"
  ]
  date_end: "last"

options_outdoor =
  device_id: 'xxxxx'
  scale: "max"
  type: [
    "Temperature"
    "Humidity"
  ]
  date_end: "last"
  module_id: 'xxxxx'

moment.lang 'ja',
  {weekdays: ["日曜日","月曜日","火曜日","水曜日","木曜日","金曜日","土曜日"],
  weekdaysShort: ["日","月","火","水","木","金","土"]}


module.exports = (robot) ->

  netatmo_api = new Netatmo config

  measureMessageOffice = (msg, opt_str="") ->
    netatmo_api.getMeasure options_office, (err, measure) ->
      temperature = measure[0]['value'][0][0]
      co2 = measure[0]['value'][0][1]
      humidity = measure[0]['value'][0][2]
      pressure = measure[0]['value'][0][3]
      noise = measure[0]['value'][0][4]

      result_comment = if co2 > 2000 then "\n空気悪っ！換気しましょう！オフィスのCO2濃度は1000ppmが目安です。1000ppm超えると眠くなるよ！" else ''

      measure_time = moment.unix(measure[0]['beg_time']).format("YYYY年MM月DD日(ddd) HH:mm:ss ")
      msg.send opt_str + "#{measure_time}に測定した室内環境\\( ❛ө❛)\/\n温度 #{temperature}℃ \n湿度 #{humidity}%\nCO2 #{co2}ppm\n気圧 #{pressure}hPa\n騒音 #{noise}dB" + result_comment

  measureMessageOutdoor = (msg, opt_str="") ->
    netatmo_api.getMeasure options_outdoor, (err, measure) ->
      temperature = measure[0]['value'][0][0]
      humidity = measure[0]['value'][0][1]

      measure_time = moment.unix(measure[0]['beg_time']).format("YYYY年MM月DD日(ddd) HH:mm:ss ")
      msg.send opt_str + "#{measure_time}に測定した外の  温度 #{temperature}℃  湿度 #{humidity}%"

  robot.hear /(CO2|二酸化炭素|空気悪い|換気|苦しい)/i, (msg) ->
    measureMessageOffice(msg)

  robot.hear /インフル/i, (msg) ->
    measureMessageOffice(msg, "インフルエンザの流行を防ぐには換気と湿度50%以上にするのが有効である\n")

  robot.respond /外の気温/i, (msg) ->
    measureMessageOutdoor(msg)


  netatmo_api.on 'error', (e) ->
    console.error e
```

# 測定してみてわかったこと

- 据え置き型のCO2測定器だと、3000ppmが最大だったのですが、NetAtmoだと3000ppm以上でも測定できていました。5000ppmまで測定できる仕様なので、結構良いセンサーを使っているようです。

![image](https://qiita-image-store.s3.amazonaws.com/0/54356/c76a9fcc-3e55-fe8c-cdf2-16ef8e6f4e82.png)


- ちなみに外気温も測定できるようにしたのですが、ほとんど使われませんでした。

- 測定は10分に一回なので、換気して反映されるまでちょっと待たされます。
- だいたい2000ppmを超えると頭痛がしたり頭がボーっとしたりする人が増えてくるみたいです。オフィスは1000ppmが目安、とはされてますが、1000ppm以下に保つのは結構むつかしくて常に風が抜ける、ぐらいじゃないといけないです。
- 半年以上運用していますが、NetAtmoはフリーズすることもなく安定して測定できています。

## ちなみに最高記録

これぐらいのCO2濃度になると息苦しさや頭痛などが出ます。

![image](https://qiita-image-store.s3.amazonaws.com/0/54356/e34ca887-fc8d-ed56-65a0-dcf19b355816.png)


http://marvel-online.jp/co2-monitor-and-eco/health-standards/
によると

```
3000PPM～：頭痛、めまいなどの症状が出て、長時間では健康に危害を及ぼすレベル
日常では起こりません。工場や厨房などで気をつけるレベルです。
周辺で火災やぼやが起きている可能性が想定されます。
```

非日常感があると思ったら案の定でした。