計測値を取り出す ~Raspberry Pi & DHT11~

計測値を取り出す~Raspberry PiとDHT11~

はじめに

計測値を保存するの続編です。
測定して保存したデータを取り出し、取り出した値を判定しLEDを光らせます。
プログラムはC言語で記述していきます。
全文は最後に載せてます。

準備するもの
Raspberry Pi Raspberry Pi 4
DHT11DHT11
抵抗カーボン抵抗 1/2W 5.1kΩ(100本入)
ジャンパーケーブルジャンパーケーブル
ブレッドボードブレッドボード
配線図

LEDをGPIO23、DHT11のデータピンをGPIO18に接続します。

測定データを保存する

1分ごとに測定値を保存します。
データベースの作成と測定方法はこちらから。




1分毎の測定ですが今回は永久ループを作成し1分の待ち時間を作ることで実現します。

#include <stdio.h>
#include <time.h>
#include <wiringPi.h>
#include <math.h>
#include <mysql/mysql.h>

//dht parameter
・
・
int main()
{
        //START

        while(1){
            ・
          ・温湿度を計測する処理
          ・
          ・データベースに書き込む処理
            ・
      delay(60000);
        }

        return 0;
}


while(1)で囲まれている中身が永久ループします。
delay(60000)で60000ms(60s)待機します。これで1分ごとに繰り返すプログラムになります。

保存データを取り出す

続いてデータを取り出す部分です。
基本的な部分は保存するときと変わりません。

    MYSQL *conn = NULL;
    MYSQL_RES *res = NULL;
    MYSQL_ROW row;

    char *sql_sv = "127.0.0.1";
    char *user = "root";
    char *passwd = "root";
    char *db_name = "dht";
    char *tblname = "dht";

    //timer
    time_t t;
    t = time(NULL); //現在時刻

    time_t target_time;
    target_time= t - 3600; //1時間前
        
    char checktime[30];
    strftime(checktime , sizeof(checktime) , "%Y-%m-%d %H:%M:%S" , localtime(&target_time) );
        //1時間前の日時をYYYY-mm-dd HH:MM:SS 形式でchecktimeに代入

    sprintf(query,"SELECT avg(temperature) from dht where date >= '%s'" , checktime );
        //データを取り出すSQL文        
        
    // mysql connect
    conn = mysql_init(NULL);
    if( !mysql_real_connect(conn,sql_sv,user,passwd,db_name,0,NULL,0) ){
		// error
		fprintf(stderr, "%s\n", mysql_error(conn));
    		exit(-1);
     }

    if( mysql_query( conn , query ) ){
    		// error
		fprintf(stderr, "%s\n", mysql_error(conn));
    		mysql_close(conn);
    		exit(-1);
    }
    res = mysql_use_result(conn);
    row = mysql_fetch_row(res);  //結果を取り出す。
    double temavg  = atof(row[0]); //必要な値を取り出す。 
        
    mysql_free_result(res);
    mysql_close(conn);

データを取り出すためのSQL文ですが、「dhtからdate列のchecktimeより大きな値(時間)を取り出し田内のtempareture列の平均を取り出す。」となっています。

select avg(temperature) from dht where date >= checktime
temperature列の平均dhtテーブルから取り出す条件はdate列がchecktimeより大きいの

checktimeについては現時刻から3600s(1時間)引いた値が入るようにしています。



SQL文の実行結果は row = mysql_fetch_row(res); で row に格納されます。

MariaDB [dht]> select * from dht where date >= '2020-12-15 15:00:00';
+---------------------+-------------+----------+
| date                | temperature | humidity |
+---------------------+-------------+----------+
| 2020-12-15 15:00:35 |          25 |       25 |
| 2020-12-15 15:01:37 |          25 |       25 |
| 2020-12-15 15:02:39 |          24 |       25 |
| 2020-12-15 15:03:41 |          24 |       26 |
| 2020-12-15 15:04:43 |          24 |       27 |
| 2020-12-15 15:05:45 |          24 |       26 |
| 2020-12-15 15:06:47 |          24 |       26 |
| 2020-12-15 15:07:49 |          25 |       25 |
| 2020-12-15 15:08:51 |          26 |       23 |
| 2020-12-15 15:09:53 |          26 |       21 |
| 2020-12-15 15:10:55 |          27 |       21 |
| 2020-12-15 15:11:58 |          26 |       22 |
+---------------------+-------------+----------+

このようなSQLを実行した時に、row = mysql_fetch_row(res) を1回実行するとrowの中身が次のようになります。

row= { ‘2020-12-15 15:00:25’ , 25 , 25 }

取り出すとこんな感じです。

row[0] ⇒ 2020-12-15 15:00:25
row[1] ⇒ 25
row[2] ⇒ 25

再度row = mysql_fetch_row(res)を実行すると次の行が対象となります。

row= { ‘2020-12-15 15:01:37’ , 25 , 25 }

ループで繰り返すことにより各行を取り出すことが可能となります。
対象の行がなくなった場合NULLを返してきます。

今回の場合は平均を取得しているので1行1列が返ってきます。
row = mysql_fetch_row(res) を1回実行し1行目を取得してから
double temavg = atof(row[0]); で1列目を取得してます。

LED点灯部分
#define LED_PIN 23

    pinMode(LED_PIN);

    if ( temavg >= 24 ){
        digitalWrite(LED_PIN,HIGH);
    }else{
        digitalWrite(LED_PIN,LOW);
    }

if分でちょちょいですね。24度を境に点灯・消灯します。

実行

コンパイルして実行します。

root@raspberrypi:~# gcc -o sql_dht_loop sql_dht_loop.c -lwiringPi -lmysqlclient
root@raspberrypi:~# ./sql_dht_loop
temperature 27.1  humdity 29.0  
ave=26.942300
temperature 26.5  humdity 31.0  
ave=26.924500
temperature 25.8  humdity 31.0  
ave=26.888900
temperature 25.3  humdity 32.0  
ave=26.854500
temperature 24.9  humdity 34.0  
ave=26.803600
temperature 24.7  humdity 35.0  
ave=26.754400
temperature 24.5  humdity 35.0  
ave=26.706900
temperature 24.3  humdity 36.0  
ave=26.689700
temperature 24.1  humdity 37.0  
ave=26.689700
temperature 24.1  humdity 37.0  
ave=26.689700


1分ごとに温湿度の測定が行われデータベースに値が保存されていきます。
データベースも確認してみます。

root@raspberrypi:~# mysql -u root -p
Enter password: 
Welcome to the MariaDB monitor.  Commands end with ; or \g.
Your MariaDB connection id is 646
Server version: 10.3.27-MariaDB-0+deb10u1 Raspbian 10

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [(none)]> use dht
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Database changed
MariaDB [dht]> select * from dht;
+---------------------+-------------+----------+
| date                | temperature | humidity |
+---------------------+-------------+----------+
| 2020-12-15 10:51:14 |          24 |       38 |
| 2020-12-15 10:52:16 |          24 |       37 |
| 2020-12-15 10:53:18 |          23 |       38 |
| 2020-12-15 10:54:20 |          16 |       38 |
| 2020-12-15 10:55:22 |          24 |       37 |
| 2020-12-15 10:56:56 |          24 |       37 |
| 2020-12-15 10:57:58 |          26 |       34 |
| 2020-12-15 10:59:00 |          27 |       31 |
| 2020-12-15 11:00:02 |          27 |       30 |
| 2020-12-15 11:01:04 |          26 |       31 |
| 2020-12-15 11:02:06 |          25 |       32 |
| 2020-12-15 11:03:08 |          25 |       34 |
| 2020-12-15 11:04:10 |          25 |       35 |
| 2020-12-15 11:05:13 |          24 |       36 |
| 2020-12-15 11:06:15 |          24 |       36 |
| 2020-12-15 11:07:18 |          48 |       37 |

いい感じに保存されています。たまにおかしな値が入っていますが、ビットずれが起きてると思われます。これはプログラムの書き方の問題のような気がしますので今後の課題です。
しかし、家で使う分には許容範囲でしょう。
直近1時間の平均が指定温度を上回った場合LEDが点灯します。

終わりに

測定したデータをデータベースに保存しました。
定期的に実行し蓄積すればグラフなどを作ったりもできます。
自宅などで計測すれば時間帯の傾向など見れるようになるので温度湿度の対策に使えるかも?しれません。



全文

※何も考えず関数化もしてないです。

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <wiringPi.h>
#include <wiringPiSPI.h>
#include <math.h>
#include <locale.h>
#include <mysql/mysql.h>

//DHT parameter
#define DHT11_DATAPIN 18
#define DHT11_START_SIG_LOW 20
#define DHT11_START_PullUp 10
#define DHT11_WAITRES_LOW 78
#define DHT11_WAITRES_HIGH 80
#define DHT11_DATAWAIT_LOW 50
#define DHT11_BITZERO 27
#define DHT11_BITONE 68
#define DHT11_END 56

#define LED_PIN 23

int main()
{

    //START
    //SetUp
    
    while(1){
    
 	int DHT11_DATA[40]= {0}; 
    wiringPiSetupGpio();
    pinMode(DHT11_DATAPIN , OUTPUT);
    
    digitalWrite(DHT11_DATAPIN , HIGH);
    delay(2000);
    
    //START OUTPUT LOW >18ms
    digitalWrite(DHT11_DATAPIN , LOW);
    delay(DHT11_START_SIG_LOW);

    //START PUll up
    digitalWrite(DHT11_DATAPIN , HIGH);
    delayMicroseconds(DHT11_START_PullUp);
    
    //WAIT DATA SIG
    pinMode(DHT11_DATAPIN , INPUT);
    
    //Response LOW SIG
    pinMode(DHT11_DATAPIN , INPUT);
    for ( int i = 0 ; i < DHT11_WAITRES_LOW ; i++ ){
        if (digitalRead(DHT11_DATAPIN) == HIGH){
            break;
        }
        delayMicroseconds(1);   
    }
    
    //Response HIGH SIG
    delayMicroseconds(DHT11_WAITRES_HIGH);
    for ( int i = 0 ; i < DHT11_WAITRES_HIGH ; i++ ){
        if (digitalRead(DHT11_DATAPIN) == LOW){
            break;
        }
        delayMicroseconds(1);
    }
    
    //DATA Recieve
    for ( int i = 0 ; i < 40 ; i++){
        //start bit wait
        delayMicroseconds(DHT11_DATAWAIT_LOW);
        for ( int j = 0 ; j < DHT11_DATAWAIT_LOW ; j++){
            if(digitalRead(DHT11_DATAPIN) == HIGH){
                break;
            }
            delayMicroseconds(1);
        }
        for ( int j = 0 ; j < 255 ; j++){
            if (digitalRead(DHT11_DATAPIN) == LOW){
                if ( j  < DHT11_BITONE ){
                    DHT11_DATA[i] = 0;
                } else {
                    DHT11_DATA[i] = 1;
                }
                break;
            }
            delayMicroseconds(1);
        }
    }
    
    //End process
    delayMicroseconds(DHT11_END);
    digitalWrite(DHT11_DATAPIN , HIGH);
    
    //data check
    int dec[8] = {1,2,4,8,16,32,64,128};
    int dt[5] = {0};
    for ( int i = 0 , j = 7 ,k = 0 ; i < 40 ; i++ , j--){
        if (DHT11_DATA[i] == 1 ){
            dt[k] += dec[j];
        }
        if ( j < 0 ){
            j = 7;
            k += 1;
        }
    }
    
    printf( "temperature %d.%d  humdity %d.%d  \n" , dt[2],dt[3] , dt[0],dt[1] );
    
    
    int tem,hum;
    tem=dt[2];
    hum=dt[0];
    
	//mysql partmeters
	MYSQL *conn = NULL;
	MYSQL_RES *res = NULL;
    MYSQL_ROW row;

	char *sql_sv = "127.0.0.1";
	char *user = "root";
	char *passwd = "root";
	char *db_name = "dht";
    char *tblname = "dht";

	//timer

    time_t t;
    t = time(NULL);

	char str[30];
	strftime(str , sizeof(str) , "%Y-%m-%d %H:%M:%S" , localtime(&t));

	//create sql
	char query[256];
    sprintf(query ,"INSERT INTO %s(date,temperature,humidity) values('%s',%d,%d)" , tblname , str , tem , hum);

  	// mysql connect
	conn = mysql_init(NULL);
	if( !mysql_real_connect(conn,sql_sv,user,passwd,db_name,0,NULL,0) ){
		// error
		fprintf(stderr, "%s\n", mysql_error(conn));
    		exit(-1);
  	}

	if( mysql_query( conn , query ) ){
    		// error
		fprintf(stderr, "%s\n", mysql_error(conn));
    		mysql_close(conn);
    		exit(-1);
 	 }
	res = mysql_use_result(conn);
	mysql_free_result(res);
	mysql_close(conn);

    time_t target_time;
    target_time= t - 3600;
        
    char checktime[30];
    strftime(checktime , sizeof(checktime) , "%Y-%m-%d %H:%M:%S" , localtime(&target_time) );
        
    sprintf(query,"SELECT avg(temperature) from dht where date >= '%s'" , checktime );
        
        
  	// mysql connect
	conn = mysql_init(NULL);
	if( !mysql_real_connect(conn,sql_sv,user,passwd,db_name,0,NULL,0) ){
		// error
		fprintf(stderr, "%s\n", mysql_error(conn));
    		exit(-1);
  	}

	if( mysql_query( conn , query ) ){
    		// error
		fprintf(stderr, "%s\n", mysql_error(conn));
    		mysql_close(conn);
    		exit(-1);
 	 }
	res = mysql_use_result(conn);
        
	row = mysql_fetch_row(res);
	double temavg  = atof(row[0]);
        
	mysql_free_result(res);
	mysql_close(conn);

    pinMode(LED_PIN);

    if ( temavg >= 24 ){
        digitalWrite(LED_PIN,HIGH);
    }else{
        digitalWrite(LED_PIN,LOW);
    }

    delay(60000);
    }
    
	return 0;
}

タイトルとURLをコピーしました