LPWA(Sigfox)で二酸化炭素濃度を測ってみた

>※IoT Agency Platfromは2020年12月31日をもってサービス終了予定となります。
※[GitHubリポジトリ](https://github.com/IoT-Makers/sigfox-platform.git)は引き続きご利用いただけます。

2020年5月25日の緊急事態宣言解除、6月11日東京アラートの解除を受け、日々の生活に戻りつつあるものの、同時に感染者数も増加し、「正解のないニューノーマル」にどう立ち向かえば良いのか、悩みは尽きません。
オフィスや商業施設も活気を戻しているものの、本当にこのままで良いのだろうか？という疑問も増すばかりです。何に注意をしていけばいいのでしょうか？
「三密」状態を避ける必要はあるものの、コロナウィルスを見れる化することなんてできません。でも、空気環境を測定するセンサは世の中に存在しています。空気環境を測定することにより、身近な場面での、コロナ感染拡大を抑えることができるのではないでしょうか？
ということで、ここでは、室内の二酸化炭素濃度について、簡単な測定方法と考察を行ってみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/eeb688b8-173d-9e8f-80d4-0d62c7c59ac5.png)

#推奨される換気の方法
厚生労働省からは、3月30日『商業施設等における「換気の悪い密閉空間」を改善するための換気について』、**良好な換気状態の基準**として**二酸化炭素濃度（CO2濃度）1,000ppm**以下と提示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/a6560944-de2c-395e-1a03-bdf9aa9a3787.png)

>この換気方法の推奨に当たっては、いくつかの注意点もあるため、誤解を招かないよう[こちら](https://www.mhlw.go.jp/content/10900000/000616069.pdf#search=%27%E3%80%8C%E6%8F%9B%E6%B0%97%E3%81%AE%E6%82%AA%E3%81%84%E5%AF%86%E9%96%89%E7%A9%BA%E9%96%93%E3%80%8D%E3%82%92%E6%94%B9%E5%96%84%E3%81%99%E3%82%8B%E3%81%9F%E3%82%81%E3%81%AE%E6%8F%9B%E6%B0%97%E3%81%AE%E6%96%B9%E6%B3%95%27)の全文を読まれることをお奨めします。

#CO2センサで測ってみる
ここでは、CO2センサ（MH-Z19）とSigfox Shield for Arduino（以降UnaShield）を使って、CO2濃度の計測とグラフ化までを試してみます。
##準備するもの

|項目|イメージ|ドキュメント|
|:---|:---:|:---:|
|[CO2センサ(MH-Z19)](https://www.amazon.co.jp/Lanfy-%E3%83%A9%E3%83%B3%E3%83%95%E3%82%A3%E3%83%BC-MH-Z19-0-5000PPM-CO2%E5%AE%A4%E5%86%85%E7%A9%BA%E6%B0%97%E8%B3%AA%E3%83%A2%E3%83%8B%E3%82%BF%E7%94%A8%E8%B5%A4%E5%A4%96%E7%B7%9ACO2%E3%82%BB%E3%83%B3%E3%82%B5UART-PWM/dp/B07B3VGGNL)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/33de7b37-4109-bb7e-74eb-b0bda5a352e1.png)|[User’s Manual](https://www.winsen-sensor.com/d/files/infrared-gas-sensor/mh-z19b-co2-ver1_0.pdf)|
|Arduino Uno|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/0fa4157d-f0d3-9476-7b8b-0eb8d4b7c9ba.png)||
|[Sigfox Shield for Arduino (UnaShield)](https://www.kccs-iot.jp/solution/product/device10/)|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/be5417ee-dcfa-eaa9-4d6b-bf17f0f9bce8.png)|[Hardware Guide](https://unabiz.github.io/unashield/hardware.html) / [無償回線利用方法](https://qiita.com/ghibi/items/5893923b44f1757294e9)|
|ピンヘッダ x2|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/4ae5354f-5070-e65c-adce-ec53789c98f6.png)|
|ジャンパワイヤ x4|![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/f583d1b7-8b8a-8629-0f87-4a738fa8a552.png)|

##UnaShieldとMH-Z19を接続
MH-Z19にピンソケットをはんだ付けしたら、Arduinoからの5V出力をMH-Z19のV+/V-ピンに、ArduinoのDigital I/OをMH-Z19のTx/Rxピンに接続します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/ddd8be0a-c810-da21-31cd-c65a6b908413.png)

##サンプルコード
10分間隔でMH-Z19からCO2濃度を取得し、Sigfoxで送信するサンプルコードになります。

```mhz19.ino.c
#include <SoftwareSerial.h>
#define txPin_mhz 10
#define rxPin_mhz 11
#define REQUEST_SIZE 8 //Byte size for request to MH-Z19
#define RESPONSE_SIZE 9 //Byte size of response from MH-Z19

uint8_t get_co2[REQUEST_SIZE] = {0xff, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t abc_on[REQUEST_SIZE] =  {0xff, 0x01, 0x79, 0xA0, 0x00, 0x00, 0x00, 0x00};
uint8_t abc_off[REQUEST_SIZE] = {0xff, 0x01, 0x79, 0x00, 0x00, 0x00, 0x00, 0x00};

void setup()
{
  Serial.begin(9600);         // Arduinoハードウェアシリアルを起動(Arduino <-> PC)
  Serial.println("===========================");
  Serial.println("Sigfox UnaShield CO2(MH-Z19B) Sample");
  Serial.println("===========================");
  
  //mhzCommand(abc_off, NULL); //Auto Caliburation: off
}

void loop()
{ 
  int co2 = mhzGetCo2();
  Serial.print("CO2: "); Serial.println(co2);
  if (co2 != 0) {
    sigSendMessage(String(co2, HEX));
  }
  delay(600000);
}

int mhzGetCo2()
{
  int co2 = 0;
  uint8_t buf[RESPONSE_SIZE];
  mhzCommand(get_co2, buf);
  if (buf[0] == 0xff && buf[1] == 0x86 && mhzChecksum(buf) == buf[RESPONSE_SIZE-1]) {
    co2 = buf[2] * 256 + buf[3];
  }
  return co2;
}

void mhzCommand(uint8_t cmd[], uint8_t *response)
{
  SoftwareSerial ss_mhz(rxPin_mhz, txPin_mhz);
  ss_mhz.begin(9600);
  ss_mhz.write(cmd, REQUEST_SIZE);
  ss_mhz.write(mhzChecksum(cmd));
  ss_mhz.flush();

  if (response != NULL) {
    int i = 0;
    while (ss_mhz.available() <= 0) {
      if (++i > 100) {
        Serial.println("no response.");
        return;
      }
      yield();
      delay(10);
    }
    ss_mhz.readBytes(response, RESPONSE_SIZE);
  }
}

uint8_t mhzChecksum(uint8_t com[])
{
  uint8_t sum = 0x00;
  for (int i = 1; i < REQUEST_SIZE; i++) {
    sum += com[i];
  }
  sum = 0xff - sum + 0x01;
  return sum;
}

void sigSendMessage(String s)
{
  String msg = sigSFMessage(s);
  SoftwareSerial ss_sig(5, 4);
  pinMode(5, INPUT);
  pinMode(4, OUTPUT);
  ss_sig.begin(9600);
  delay(100);
  ss_sig.print(msg);
  Serial.println(msg);

  String res = "";
  char output;
  while(ss_sig.available()) {
    res += (char)ss_sig.read();
    delay(10);
  }
  if (res.length()) Serial.println(res);
}

String sigSFMessage(String msg)
{
  String sfMessage = "";
  if(msg.length() % 2 == 1) {
    sfMessage = "0" + msg;
  } else {
    sfMessage = msg;
  }
  return "AT$SF=" + sfMessage + "\r";
}
```
MH-Z19のユーザーマニュアルを見ると、下記のように[0xff, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79(CRC)]がCO2取得の要求コマンドとなっています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/8ff60e25-873e-58a2-3f6f-b41f481f1221.png)

また、オートキャリブレーション機能があり、電源投入後から24時間毎に、その間の最低値を400ppmにみなしてくれる機能のようです。オフィスなどではONにすることが推奨されているようですので、利用環境に合わせて設定を変えた方が良さそうです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/b99d74b5-962c-0eb9-8172-64959358c2c6.png)

#IoT Agency Platformでグラフ化
先程のサンプルスケッチではCO2濃度を2バイトでSigfoxクラウドに送信しています。SigfoxクラウドからCallback機能を使って、[IoT Agency Platform](https://try.iotagency.sigfox.com)に転送することにより、グラフ化が可能です。
##IoT Agency Platformへのコールバック
IoT Agency Platform （https://try.iotagency.sigfox.com ）にログイン後、**API**メニューを開けます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/156521f3-a5e3-8fc7-2f0b-6d59e171a844.png)

1. **Manage Tokens**をクリックして、まだトークンがない場合は、"Create New"ボタンをクリックし、新規にトークンを作成してください。既にトークンがある場合は、そのトークンを使えます。
2. **UPLINK**をクリックし、表示されている**Url pattern**、**Use HTTP Method**、**Headers**、**Content Type**、**Body**をSigfoxクラウドのCallback設定に入力します。

Sigfoxクラウド上でのCallback設定方法は、[こちら](https://qiita.com/ghibi/items/53259381a30363538a6d)を参考にしてください。
これで、CO2計測後のメッセージが送信されると、そのデータがIoT Agency Platformまで転送されます。転送されると、自動的にDeviceが登録され、そのメッセージを確認することもできます。

##データをパースする
Sigfoxメッセージ上のデータは、CO2濃度を16進表記で表した文字列です。グラフ化するためには、この文字列をパースする必要があります。
**Parsers**メニューを選択します。ここでパーサをJavascriptでコーディングするのですが、Parserは、このプラットフォーム上で全共有となるため、画面レスポンスが悪いことは覚悟しておいてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/3e8373d6-761f-d749-53b0-fb823c2d853d.png)
ここで、下記コードを入力すれば、Sigfoxメッセージ上のCO2濃度をco2変数として扱えるようになります。

```mhz19.java
var payload, co2, parsedData = [], obj = {};
co2 = parseInt(payload.slice(0, 4), 16);

// Store objects in parsedData array
obj = {};
obj.key = 'CO2';
obj.value = co2;
obj.type = 'number';
obj.unit = 'ppm';
parsedData.push(obj);

//console.log(parsedData);
return parsedData;
```
既にMHZ19という名前（"parserId": "5f0082144ab1680018d4a525"）のパーサーを作っていますので、それを使ってもらってもかまいません。

##カテゴリを作る
**Categories**メニューを開いて、適当にカテゴリを作っておいてください。今回は、Enviromentというカテゴリを作りました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/5d74cd9d-90c2-adfb-e4e4-d94baa41e8a8.png)

##Deviceを編集する
**Devices**メニューを開けると、認識済みのデバイスが一覧表示されています。対象のデバイスIDのEdit deviceボタンを選択し、デバイス名（Name）と使用するパーサ（Parser）、カテゴリ（Category）を選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/22c3e6b2-6036-3f03-c968-d610bf1c774d.png)

##ダッシュボードでグラフ化
**New dashboard**メニューを開き、**Add widget**ボタンをクリックし、線(Line)グラフを作成します。CategoriesやDevicesは、先ほど設定したものを選択します。また、Parserが設定されていれば、Keys項目から*CO2*を選択できるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/1245d6a6-7e1e-91e5-1463-d7845d87539b.png)

#1日のCO2濃度変化
自宅のリビングルームにCO2センサを設置し、その変化を見てみました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/751856b4-0e80-d535-e197-d8d0d59a7208.png)
我が家は窓を開けていることが多いので、平均的には500～600ppm程度を推移していましたが、**エアコンをつけた後、CO2濃度は上昇し、3時間程度で1,000ppmを超えて**しまいました。その後の換気効果が目に見えてでていました。
**「密閉空間」**（換気の悪い密閉空間）であっても、空気環境を測定し、時間帯、場所による変化を把握し、人の密集を避ける手立てをとることによって、**「密集場所」を作らない**ようにすることから始めてみてもいいかもしれませんね。
[![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/172313/d6ad10bc-75ba-8124-14d4-f144657c6473.png)](https://twitter.com/ghibi)