ATOM Matrixにセンサを繋ぐ

[ATOM MatrixのセンサとIO](https://qiita.com/jksoft/items/40082d680558cefb71cd)で、ATOM Matrixの背面のピンを調べましたが、アナログ系のI/Oはピンが固定されるものの通信系のペリフェラル機能は好きなポートに割り当てられることがわかりました。

[Wio LTEに複数のI2CなGroveモジュールを繋げる](https://qiita.com/jksoft/items/f268f6b15c28dfca2149)の記事で作った紫外線センサ VEML6070と気温、湿度、気圧、空気の汚染度が計測できるセンサ BME680、それと[GroveのCo2センサー](http://wiki.seeedstudio.com/Grove-CO2_Sensor/)を繋げてI2CとUARTを確認してみます。

# センサとの接続
もともとATOM MatrixにはGrove互換ポートがありますが電源が5Vのため、3.3V動作のセンサは直接繋げられません。
裏のポートからブレッドボード経由で繋げても良かったのですが、専用に基板を作りました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109992/6ceec49e-b7d6-1346-a987-aac3704e764e.png)

専用基板経由で、センサを繋げます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109992/80f71269-831a-e7d1-da64-6b1912d83013.png)

# BME680(I2C)の確認
まずはI2C接続のBME680だけで動作を確認してみます。BME680は[ストロベリーリナックスで販売されているモジュール](https://strawberry-linux.com/catalog/items?code=12680)を使用していますが、現在はseeedからも[Groveのモジュール](https://www.switch-science.com/catalog/3987/)が販売されています。
使い方はどちらも同じだと思います。

## プログラム
Adafruitのライブラリがありましたので、それを使用しました。```BME680```で検索すれば出てきますので、インストールします。これだけでは足らなかったので、[Adafruit_Sensor](https://github.com/adafruit/Adafruit_Sensor)もZipでダウンロードしてインストールします。

プログラムはほぼサンプルのままです。Wireはデフォルトのポートと異なるので、そこだけ接続しているポートに変更しています。

```cpp
#include <Wire.h>
#include "Adafruit_BME680.h"

Adafruit_BME680 bme;

void setup() {
  Serial.begin(115200);
  Wire.begin(23,22);
  bme.begin();

  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
}

void loop() {
  if (! bme.performReading()) {
    Serial.println("Failed to perform reading :(");
    return;
  }
  Serial.print("Temperature = ");
  Serial.print(bme.temperature);
  Serial.println(" *C");

  Serial.print("Pressure = ");
  Serial.print(bme.pressure / 100.0);
  Serial.println(" hPa");

  Serial.print("Humidity = ");
  Serial.print(bme.humidity);
  Serial.println(" %");

  Serial.print("Gas = ");
  Serial.print(bme.gas_resistance / 1000.0);
  Serial.println(" KOhms");

  Serial.println();
  delay(2000);
}

```

## 結果
シリアルモニタにセンサから取得された値が出力されました。

```
Temperature = 23.30 *C
Pressure = 994.49 hPa
Humidity = 50.67 %
Gas = 354.47 KOhms
```

#Co2センサ(UART)の確認
次にUART接続のCo2センサーを確認してみます。このセンサは電源が5VでもOKなので直接繋げられますが、専用基板にも5VのGrove互換ポートを用意しているので、そちらに繋げました。

## プログラム
こちらも主にサンプルのままですが、UART部分を変更しています。このセンサは温度も取得できます。

```cpp
#include <HardwareSerial.h>

HardwareSerial Co2SensorSerial(1);
const unsigned char cmd_get_sensor[] =
{
    0xff, 0x01, 0x86, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x79
};

unsigned char dataRevice[9];
int temperature;
int CO2PPM;

void setup() {
  Serial.begin(115200);
  Co2SensorBegin();

};

void loop() {

  if(dataRecieve())
  {
      Serial.printf("Temperature=%d\n",temperature);
      Serial.printf("Co2=%d\n",CO2PPM);
  }
  delay(1000);
};


void Co2SensorBegin()
{
  Co2SensorSerial.begin(9600,SERIAL_8N1,25,21);
}

bool dataRecieve(void)
{
    byte data[9];
    int i = 0;

    //transmit command data
    for(i=0; i<sizeof(cmd_get_sensor); i++)
    {
        Co2SensorSerial.write(cmd_get_sensor[i]);
    }
    delay(10);
    //begin reveiceing data
    if(Co2SensorSerial.available())
    {
        while(Co2SensorSerial.available())
        {
            for(int i=0;i<9; i++)
            {
                data[i] = Co2SensorSerial.read();
            }
        }
    }

    if((i != 9) || (1 + (0xFF ^ (byte)(data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7]))) != data[8])
    {
        return false;
    }

    CO2PPM = (int)data[2] * 256 + (int)data[3];
    temperature = (int)data[4] - 40;

    return true;
}
```

## 結果
シリアルモニタにセンサから取得された値が出力されました。

```
Temperature=27
Co2=1114
Temperature=27
Co2=1110
Temperature=27
Co2=1104
Temperature=27
```

# センサ値をAmbientにアップロード
すべてのセンサを組み合わせてAmbientにアップロードし、グラフ化してみます。

## プログラム
Ambientについては、[ATOM MatrixをAmbientに繋ぐ](https://qiita.com/jksoft/items/915f917fd76c2b045fe0)を参考にしてください。

```cpp
#include <HardwareSerial.h>
#include <Wire.h>
#include "Adafruit_BME680.h"
#include "Adafruit_VEML6070.h"
#include "Ambient.h"
#include <WiFi.h>

Adafruit_BME680 bme;
Adafruit_VEML6070 uv;
HardwareSerial Co2SensorSerial(1);
WiFiClient client;
Ambient ambient;

const unsigned char cmd_get_sensor[] =
{
    0xff, 0x01, 0x86, 0x00, 0x00,
    0x00, 0x00, 0x00, 0x79
};

unsigned char dataRevice[9];
int temperature;
int CO2PPM;

// Wi-FiのSSID
const char* ssid = "ssid";
// Wi-Fiのパスワード
const char* password = "pass";

// AmbientのチャネルID
unsigned int channelId = 100; 
// Ambientのライトキー
const char* writeKey = "write key"; 

void setup() {
  Serial.begin(115200);
  // Wi-Fi APに接続
  WiFi.begin(ssid, password);
  //  Wi-Fi AP接続待ち
  while (WiFi.status() != WL_CONNECTED) {
      delay(500);
      Serial.print(".");
  }
  Serial.print("WiFi connected\r\nIP address: ");
  Serial.println(WiFi.localIP());
  
  ambient.begin(channelId, writeKey, &client);
  
  Co2SensorBegin();
  Wire.begin(23,22);
  bme.begin();
  uv.begin(VEML6070_1_T);

  // Set up oversampling and filter initialization
  bme.setTemperatureOversampling(BME680_OS_8X);
  bme.setHumidityOversampling(BME680_OS_2X);
  bme.setPressureOversampling(BME680_OS_4X);
  bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
  bme.setGasHeater(320, 150); // 320*C for 150 ms
};

void loop() {
  Serial.printf("----------------------------------------------------------------\n");
  if(bme.performReading()) {
    Serial.printf("Temperature = %f *C\n",bme.temperature);
    Serial.printf("Pressure = %f hPa\n",bme.pressure / 100.0);
    Serial.printf("Humidity = %f %%\n",bme.humidity);
    Serial.printf("Gas = %f KOhms\n",bme.gas_resistance / 1000.0);
    ambient.set(1, bme.temperature);
    ambient.set(2, bme.pressure / 100.0);
    ambient.set(3, bme.humidity);
    ambient.set(4, bme.gas_resistance / 1000.0);
  }
  Serial.printf("UvLightLevel = %d \n",uv.readUV());
  ambient.set(5, (float)uv.readUV());

  if(dataRecieve())
  {
    Serial.printf("Co2 = %d ppm\n",CO2PPM);
    ambient.set(6, (float)CO2PPM);
  }
  ambient.send();
  Serial.printf("----------------------------------------------------------------\n\n");
  delay(30000);
};


void Co2SensorBegin()
{
  Co2SensorSerial.begin(9600,SERIAL_8N1,25,21);
}

bool dataRecieve(void)
{
    byte data[9];
    int i = 0;

    //transmit command data
    for(i=0; i<sizeof(cmd_get_sensor); i++)
    {
        Co2SensorSerial.write(cmd_get_sensor[i]);
    }
    delay(10);
    //begin reveiceing data
    if(Co2SensorSerial.available())
    {
        while(Co2SensorSerial.available())
        {
            for(int i=0;i<9; i++)
            {
                data[i] = Co2SensorSerial.read();
            }
        }
    }

    if((i != 9) || (1 + (0xFF ^ (byte)(data[1] + data[2] + data[3] + data[4] + data[5] + data[6] + data[7]))) != data[8])
    {
        return false;
    }

    CO2PPM = (int)data[2] * 256 + (int)data[3];
    temperature = (int)data[4] - 40;

    return true;
}
```

## 結果
センサから取得した各値がAmbient上でグラフ化されました。
（室内で計測したため、UV Levelは0のままです。日に当てると変化することは確認しています）
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/109992/772fe5c1-a821-da89-d8b1-fdef4625752c.png)

# あとがき
センサーの精度と計測環境的に値の精度はそれほど高くないと思います。どちらかというと変化を検出したいのでAIで解析させて、環境の状態通知をやってみたいと思いました。