CO2センサー(MHZ-14A)と気温気圧湿度センサー(BME280)の測定値をArduinoで取得してEthernet経由でラズパイで記録

タイトル長くてすみません

#きっかけ

　僕「Arduinoをせっかく買ったのでセンサー類をArduinoに載せ替えてみよう」
　※以前ラズパイにセンサー類を取り付けて遊んでました
　[Raspberry PiでCO2センサーモジュール(MH-Z14A)を使って室内のCO2濃度測定](https://qiita.com/_shin_/items/dfdab160a49feaf4ba66)
　
　僕「Arduinoをイーサネットにつなぐモジュールが適当に転がってたので使ってみよう」
　僕「離れた場所でセンサーの値を取得することができるね」

#用意したもの

・ラズパイ(Raspberry Pi3 B+)
・Arduino Uno
・Arduino用 Ethernetモジュール
・CO2濃度センサー　(MHZ-14A)
・気温気圧湿度センサー(BME280)
・プルアップ用抵抗1 kΩ
・ジャンパワイヤ　(オス-オス)
・ブレッドボード

Ethernetモジュールはこんな感じ
![ethernet.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513034/8c574df4-0a6a-a5a4-d525-3b8eca703064.jpeg)

マイクロSDを差し込んで色々できるらしいがまた今度
裏にはMACアドレスが印刷されたシールが貼り付けてある




#手順

##接続
ArduinoにEthernetモジュールを接続する


###CO2センサー(MHZ-14A)
今回も前回にならってUART方式で接続する
下の図の通りに接続する

<img width="400" alt="arduino.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/513034/0db49301-2c0d-62b7-1dc1-62ba3dc9ea47.png">

ちなみに配線はこんな感じ

| 割り当て | 配色 |
|:-:|:-:|
| 電源(5V) | 赤 |
| GND | 黒 |
| UART(RXD) | 青 |
|UART(TXD)| 黄 |


###気温気圧湿度センサー(BME280)
この記事と同様に接続
[温度・湿度・気圧センサー(BME280)の値をArduinoで取得](https://qiita.com/_shin_/items/d85327c2b6bd5fb9f9ee)



##Arduinoのスケッチ

```AdvancedChatServer.ino
#include <SPI.h>
#include <Ethernet.h>
#include <Wire.h>
#include <SoftwareSerial.h>

#define BME280_ADDRESS 0x76
SoftwareSerial SerialCom (2,3);
int myDelay = 5000;
byte addArray[] = { 0XFF, 0x01, 0x86, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79 };
byte addcalib[] = { 0XFF, 0x01, 0x87, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78 };
char dataValue[9];
String dataString = "";


unsigned long int hum_raw,temp_raw,pres_raw;
signed long int t_fine;

uint16_t dig_T1;
 int16_t dig_T2;
 int16_t dig_T3;
uint16_t dig_P1;
 int16_t dig_P2;
 int16_t dig_P3;
 int16_t dig_P4;
 int16_t dig_P5;
 int16_t dig_P6;
 int16_t dig_P7;
 int16_t dig_P8;
 int16_t dig_P9;
 int8_t  dig_H1;
 int16_t dig_H2;
 int8_t  dig_H3;
 int16_t dig_H4;
 int16_t dig_H5;
 int8_t  dig_H6;

byte mac[] = {
0x90, 0xA2, 0x0D, 0xD2, 0xDD}; //イーサネットシールドに記載されているMACアドレスを指定する

IPAddress ip( 192,168,0,50); //Arduinoサーバーに割り当てるIPアドレスを指定する

EthernetServer server(80); 

void setup() {
// Open serial communications and wait for port to open:
Serial.begin(9600);
SerialCom.begin(9600);
uint8_t osrs_t = 1;             //Temperature oversampling x 1
uint8_t osrs_p = 1;             //Pressure oversampling x 1
uint8_t osrs_h = 1;             //Humidity oversampling x 1
uint8_t mode = 3;               //Normal mode
uint8_t t_sb = 5;               //Tstandby 1000ms
uint8_t filter = 0;             //Filter off 
uint8_t spi3w_en = 0;           //3-wire SPI Disable

uint8_t ctrl_meas_reg = (osrs_t << 5) | (osrs_p << 2) | mode;
uint8_t config_reg    = (t_sb << 5) | (filter << 2) | spi3w_en;
uint8_t ctrl_hum_reg  = osrs_h;

Wire.begin();

writeReg(0xF2,ctrl_hum_reg);
    writeReg(0xF4,ctrl_meas_reg);
    writeReg(0xF5,config_reg);
    readTrim();                    //


//addcalib
SerialCom.write(addcalib, 9);
delay(30);


while (!Serial) {
; // wait for serial port to connect. Needed for Leonardo only
}
Ethernet.begin(mac, ip); 
server.begin();
Serial.print("server is at ");
Serial.println(Ethernet.localIP());
}
void loop() {
EthernetClient client = server.available(); 
if (client) {
Serial.println("new client");
// an http request ends with a blank line
boolean currentLineIsBlank = true;
while (client.connected()) {
if (client.available()) {
char c = client.read();
Serial.write(c);
// if you've gotten to the end of the line (received a newline
// character) and the line is blank, the http request has ended,
// so you can send a reply
if (c == '\n' && currentLineIsBlank) {
// send a standard http response header
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println("Connection: close"); // the connection will be closed after completion of the response
client.println("Refresh: 30"); // refresh the page automatically every 5 sec
client.println();
client.println();
client.println();
// output the value of each analog input pin

double temp_act = 0.0, press_act = 0.0,hum_act=0.0;
signed long int temp_cal;
unsigned long int press_cal,hum_cal;


for (int analogChannel = 0; analogChannel < 1; analogChannel++) {

readData();
SerialCom.write(addArray, 9);
SerialCom.readBytes(dataValue, 9);
int resHigh = (int) dataValue[2];
int resLow  = (int) dataValue[3];
int pulse = (256*resHigh)+resLow;
dataString = String(pulse);




temp_cal = calibration_T(temp_raw);
press_cal = calibration_P(pres_raw);
hum_cal = calibration_H(hum_raw);
temp_act = (double)temp_cal / 100.0;
press_act = (double)press_cal / 100.0;
hum_act = (double)hum_cal / 1024.0;
//client.print("TEMP : ");
client.print(temp_act);
client.print(" ");
//client.print(" DegC  PRESS : ");
client.print(press_act);
client.print(" ");
//client.print(" hPa  HUM : ");
client.print(hum_act);
client.print(" ");
client.print(pulse);
//client.println(" %");
//delay(30000);

//int sensorReading = analogRead(analogChannel);
//client.print("analog input ");
//client.print(analogChannel);
//client.print(" is ");
//client.print(sensorReading);
//client.println();
}
client.println();
break;
}
if (c == '\n') {
// you're starting a new line
currentLineIsBlank = true;
}
else if (c != '\r') {
// you've gotten a character on the current line
currentLineIsBlank = false;
}
}
}
// give the web browser time to receive the data
delay(30);
// close the connection:
client.stop();
Serial.println("client disonnected");
}
}

void readTrim()
{
    uint8_t data[32],i=0;                      // Fix 2014/04/06
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0x88);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,24);       // Fix 2014/04/06
    while(Wire.available()){
        data[i] = Wire.read();
        i++;
    }

    Wire.beginTransmission(BME280_ADDRESS);    // Add 2014/04/06
    Wire.write(0xA1);                          // Add 2014/04/06
    Wire.endTransmission();                    // Add 2014/04/06
    Wire.requestFrom(BME280_ADDRESS,1);        // Add 2014/04/06
    data[i] = Wire.read();                     // Add 2014/04/06
    i++;                                       // Add 2014/04/06

    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0xE1);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,7);        // Fix 2014/04/06
    while(Wire.available()){
        data[i] = Wire.read();
        i++;    
    }
    dig_T1 = (data[1] << 8) | data[0];
    dig_T2 = (data[3] << 8) | data[2];
    dig_T3 = (data[5] << 8) | data[4];
    dig_P1 = (data[7] << 8) | data[6];
    dig_P2 = (data[9] << 8) | data[8];
    dig_P3 = (data[11]<< 8) | data[10];
    dig_P4 = (data[13]<< 8) | data[12];
    dig_P5 = (data[15]<< 8) | data[14];
    dig_P6 = (data[17]<< 8) | data[16];
    dig_P7 = (data[19]<< 8) | data[18];
    dig_P8 = (data[21]<< 8) | data[20];
    dig_P9 = (data[23]<< 8) | data[22];
    dig_H1 = data[24];
    dig_H2 = (data[26]<< 8) | data[25];
    dig_H3 = data[27];
    dig_H4 = (data[28]<< 4) | (0x0F & data[29]);
    dig_H5 = (data[30] << 4) | ((data[29] >> 4) & 0x0F); // Fix 2014/04/06
    dig_H6 = data[31];                                   // Fix 2014/04/06
}
void writeReg(uint8_t reg_address, uint8_t data)
{
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(reg_address);
    Wire.write(data);
    Wire.endTransmission();    
}

void readData()
{
    int i = 0;
    uint32_t data[8];
    Wire.beginTransmission(BME280_ADDRESS);
    Wire.write(0xF7);
    Wire.endTransmission();
    Wire.requestFrom(BME280_ADDRESS,8);
    while(Wire.available()){
        data[i] = Wire.read();
        i++;
    }
    pres_raw = (data[0] << 12) | (data[1] << 4) | (data[2] >> 4);
    temp_raw = (data[3] << 12) | (data[4] << 4) | (data[5] >> 4);
    hum_raw  = (data[6] << 8) | data[7];
}


signed long int calibration_T(signed long int adc_T)
{

    signed long int var1, var2, T;
    var1 = ((((adc_T >> 3) - ((signed long int)dig_T1<<1))) * ((signed long int)dig_T2)) >> 11;
    var2 = (((((adc_T >> 4) - ((signed long int)dig_T1)) * ((adc_T>>4) - ((signed long int)dig_T1))) >> 12) * ((signed long int)dig_T3)) >> 14;

    t_fine = var1 + var2;
    T = (t_fine * 5 + 128) >> 8;
    return T; 
}

unsigned long int calibration_P(signed long int adc_P)
{
    signed long int var1, var2;
    unsigned long int P;
    var1 = (((signed long int)t_fine)>>1) - (signed long int)64000;
    var2 = (((var1>>2) * (var1>>2)) >> 11) * ((signed long int)dig_P6);
    var2 = var2 + ((var1*((signed long int)dig_P5))<<1);
    var2 = (var2>>2)+(((signed long int)dig_P4)<<16);
    var1 = (((dig_P3 * (((var1>>2)*(var1>>2)) >> 13)) >>3) + ((((signed long int)dig_P2) * var1)>>1))>>18;
    var1 = ((((32768+var1))*((signed long int)dig_P1))>>15);
    if (var1 == 0)
    {
        return 0;
    }    
    P = (((unsigned long int)(((signed long int)1048576)-adc_P)-(var2>>12)))*3125;
    if(P<0x80000000)
    {
       P = (P << 1) / ((unsigned long int) var1);   
    }
    else
    {
        P = (P / (unsigned long int)var1) * 2;    
    }
    var1 = (((signed long int)dig_P9) * ((signed long int)(((P>>3) * (P>>3))>>13)))>>12;
    var2 = (((signed long int)(P>>2)) * ((signed long int)dig_P8))>>13;
    P = (unsigned long int)((signed long int)P + ((var1 + var2 + dig_P7) >> 4));
    return P;
}

unsigned long int calibration_H(signed long int adc_H)
{
    signed long int v_x1;

    v_x1 = (t_fine - ((signed long int)76800));
    v_x1 = (((((adc_H << 14) -(((signed long int)dig_H4) << 20) - (((signed long int)dig_H5) * v_x1)) + 
              ((signed long int)16384)) >> 15) * (((((((v_x1 * ((signed long int)dig_H6)) >> 10) * 
              (((v_x1 * ((signed long int)dig_H3)) >> 11) + ((signed long int) 32768))) >> 10) + (( signed long int)2097152)) * 
              ((signed long int) dig_H2) + 8192) >> 14));
   v_x1 = (v_x1 - (((((v_x1 >> 15) * (v_x1 >> 15)) >> 7) * ((signed long int)dig_H1)) >> 4));
   v_x1 = (v_x1 < 0 ? 0 : v_x1);
   v_x1 = (v_x1 > 419430400 ? 419430400 : v_x1);
   return (unsigned long int)(v_x1 >> 12);   
}
```


この例ではArduinoのIPを`192.168.0.50`に固定
スケッチができたらArduinoのマイコンに書き込んだ後、測定したい場所の近くのコンセントからUSB電源を供給する

##ラズパイ側でデータ取得
Pythonで以下のようなコードを書く

```read.py
#!/usr/bin/env python
# -*- coding: utf-8 -*-

import requests
from datetime import datetime
 
r = requests.get('http://192.168.0.50')
 

day =datetime.now().strftime('%Y %m %d %H %M') 
dayname =datetime.now().strftime('%Y%m%d') 
data = r.content.decode().splitlines()

with open( "/home/pi/ethernet/" + dayname + ".dat", "a") as f:
    f.write(day + ' ' + data[2] + '\n')

print(data[2])
```


`192.168.0.50`からデータを取得し、ファイルに保存する的な感じ

#データ取得してみた

cronを使って5分毎にpythonのスクリプトを走らせてデータを取得してみた

```20200115.dat
　　　　　　　　・
　　　　　　　　・
　　　　　　　　・
#年  月  日 時 分  温度   気圧    湿度   CO2濃度
2020 01 15 21 35 24.12 1003.41 28.25 1193
2020 01 15 21 40 24.13 1003.41 28.58 1270
2020 01 15 21 45 24.09 1003.41 28.50 1576
2020 01 15 21 50 24.06 1003.49 28.30 1627
```

一応ちゃんと測れてるっぽい
お金があったらWiFiかBluetoothのモジュールも欲しいな


#参考にしたサイト

・Ethernetのスケッチが載っていたサイト
https://deviceplus.jp/hobby/entry_006/
・スイッチサイエンスのスケッチ
http://trac.switch-science.com/wiki/BME280

有用な情報ありがとうございます