概 要 |
ESPr Developerから、I2C接続で温度センサー(ADT7410)を使って温度測定し、レンタルサーバー上のPHPプログラムに一定時間間隔で測定結果を送信します。PHPプログラムはデータを受信した都度、SQLiteファイルに書き込みます。(SQLiteデータベースファイル処理については先回投稿していますので、参考にしてみて下さい。) 今回はこの様にして書き込まれた温度データをインターネット経由でブラウザー上で見るところまで確認してみます。
尚、SQLite処理については、下記も参考にしてみて下さい。
[https://kats-eye.net/info/2018/11/13/php-sqlite/]
配線接続 |
今回の確認は、これまで投稿したインターネットダイスとPHPによるSQLite書き込みの組み合わせです。全体構成イメージはそちらを参考にして下さい。配線接続もインターネットダイスで使用した基板配線に下の写真の通り、⑤ I2C接続温度センサー(ADT7410)を追加配線しています。
実際に配線した写真は下の通りです。写真上の中央(やや右)に温度センサーを接続しています。狭い領域ですが、ピンソケットをはんだ付けできたので、ジャンパー線で接続しています。
プログラム |
(1)ESPr Developerプログラム
基本的には、インターネットダイス(サイコロ)用プログラムに温度センサーの値を測定するプログラムを追加しています。インターネットダイスでは、加速度センサーの測定値をサイコロの目に変換してサーバーに送信していましたが、今回はサイコロの目の代わりに温度測定データを送信します。加速度センサー測定関連プログラムは、今回関係ありませんが、また違う目的で使うことがあるかもしれませんので、基本的には残しています。
行番24~66が主な追加した温度センサー関連のコードです。Arduinoで同じセンサー接続を行っており、プログラムも同じです。行番151で初期化の為の関数を呼び出しています。
行番172~229が繰り返しループになっており、温度測定を行い、サーバーにデータ送信する処理を繰り返します。
行番173で温度測定を行い、その結果を行番177で変数bodyに格納し、インターネットダイスと同じように一連の送信処理を行います。行番228では、約5分(=5*60*1000)間処理を遅延させるので、およそ5分に1回データ送信するプログラムになっています。
#include <ESP8266WiFi.h> #include <Wire.h> // WIFI関連 const char* ssid = "アクセスポイントSSID"; // 接続アクセスポイントのSSID const char* password = "アクセスポイントパスワード"; // 接続アクセスポイントのパスワード const int httpPort = 80 ; // ポート番号指定 const char* host = "接続サーバードメイン"; // 接続サーバードメイン名 const char* path = "サーバー側プログラムPath"; // 呼び出すプログラム名 const int s_p = 4; int loopCnt=0; String body = ""; String rtn =""; // I2C-加速度センサー(MMA8451) #define DVC_ADRS 0x1D // デバイスアドレス #define GRAV_E (9.80665F) // 標準重力加速度 uint16_t x_r , y_r , z_r ; // XYZ 14bitデータ long int x_v , y_v , z_v ; // XYZ 数字 float x_g , y_g , z_g ; // XYZ 角加速度 // ☆ ADT7410 定数・変数 #define DVC_ADT7410 0x48 // 温度センサ(ADT7410)アドレス(外部設定) uint16_t g_md = 0x40 ; uint16_t g_rs = 0x00 ; float r_t ; // ☆ 温度センサ-(ADT7410)初期化 void ADT7410_INIT(){ Wire.beginTransmission(DVC_ADT7410); // 接続開始 Wire.write(0x03); // Configurationアドレス指定 Wire.write(g_md | g_rs); // 操作モードと分解能指定 Wire.endTransmission(); // 接続終了 } // ☆ 温度センサ-(ADT7410)データ読み取り float rd_dat_ADT7410(void) { uint16_t ui_val ; long int in_val ; float fl_tmp ; Wire.beginTransmission(DVC_ADT7410); // 接続開始 Wire.write(0x00); // 読込開始アドレス指定 Wire.endTransmission(false); // 送信完了(接続維持) Wire.requestFrom(DVC_ADT7410 , 2); // 2バイト要求 ui_val = (uint16_t)Wire.read() << 8 ; // データの読み出し(上位) ui_val |= Wire.read(); // データの読み出し(下位) if (g_rs == 0x80){ // 測定レンジによる処理選択 in_val = (long int)ui_val; if(ui_val & 0x8000) { // 符号判定 in_val = in_val - 65536 ; } fl_tmp = (float)in_val / 128.0 ; }else{ ui_val >>= 3 ; in_val = (long int)ui_val; if(ui_val & 0x1000) { // 符号判定 in_val = in_val - 8192 ; } fl_tmp = (float)in_val / 16.0 ; } return fl_tmp ; } // ①通信開始、デバイス初期化 bool DVC_INIT(uint8_t i2caddr){ Wire.begin(12,14); // 接続開始 wrt_reg(0x2B, 0x40); // DEVICE RESET ENABLED while (read_reg(0x2B) & 0x40); // デバイスリセット待ち wrt_reg(0x0E , 0x01); // RANGE 設定 wrt_reg(0x2B, 0x02); // PowerMode( 0x00:normal,0x01:Low Noise Low Power,0x02:High Resolution, 0x03:Low Power) wrt_reg(0x2D, 0x01); // INT_EN_DRDY wrt_reg(0x2E, 0x01); // INT_CFG_DRDY wrt_reg(0x11, 0x40); // PL_EN wrt_reg(0x2A, 0x01 | 0x04); // ACTIVE , LNOISE return true; } // ②指定レジスタにデータ書き込み void wrt_reg(uint8_t reg, uint8_t value) { Wire.beginTransmission(DVC_ADRS); // デバイス指定、通信開始 Wire.write((uint8_t)reg); // レジスタ指定 Wire.write((uint8_t)(value)); // データ書込 Wire.endTransmission(); // 送信完了 } // ③指定レジスタからデータを読み出し uint8_t read_reg(uint8_t reg) { Wire.beginTransmission(DVC_ADRS); // 送信処理開始 Wire.write(reg); // レジスタ指定 Wire.endTransmission(false); // 送信完了(コネクション維持) Wire.requestFrom(DVC_ADRS, 1); // 1byteデータに要求 if (! Wire.available()) return -1; // データ有無判定 return (Wire.read()); // 1byteデータ } // ④データ取得、変換 void read_data(void) { Wire.beginTransmission(DVC_ADRS); // 送信処理開始 Wire.write(0x01); // アドレス指定 Wire.endTransmission(false); // 送信完了(コネクション維持) Wire.requestFrom(DVC_ADRS, 6); // 6byteデータ要求 // // データ取得、変換 x_r = Wire.read() ; x_r <<= 8 ; x_r |= Wire.read() ; x_r >>= 2; y_r = Wire.read() ; y_r <<= 8 ; y_r |= Wire.read() ; y_r >>= 2; z_r = Wire.read() ; z_r <<= 8 ; z_r |= Wire.read() ; z_r >>= 2; x_v = (long int)x_r ; y_v = (long int)y_r ; z_v = (long int)z_r ; // マイナス値変換 if(x_r & 0x2000) x_v = x_v - 16384 ; if(y_r & 0x2000) y_v = y_v - 16384 ; if(z_r & 0x2000) z_v = z_v - 16384 ; // スケールレンジを取得 uint8_t range = read_reg(0x0E) & 0x03; uint16_t div_p = 1; // 加速度変換係数(測定レンジにより異なる) if (range == 0x02) div_p = 1024 ; if (range == 0x01) div_p = 2048 ; if (range == 0x00) div_p = 4096 ; x_g = (float)x_v * GRAV_E / div_p ; y_g = (float)y_v * GRAV_E / div_p ; z_g = (float)z_v * GRAV_E / div_p ; } // ⑤最初に1回だけ行う処理 void setup() { Serial.begin(115200); // デバイスアドレス指定し、初期設定 if(!DVC_INIT(DVC_ADRS)) { Serial.println("-----"); while (1); } uint8_t reg1 = read_reg(0x2A); // 元設定確認 wrt_reg(0x2A, 0x00); // StandByMode wrt_reg(0x0E, 0x00 & 0x3); // Set Range( 0x00:2g , 0x01:4g , 0x02:8g , 0x03:reserved ) wrt_reg(0x2A, reg1 | 0x01); // ActiveMode ADT7410_INIT(); // ☆ 温度センサ-(ADT7410)初期化 // ◆ WIFI-初期設定 ◆ Serial.println() ; Serial.println() ; Serial.print("Connecting to ") ; Serial.println(ssid); WiFi.mode(WIFI_STA); // STAモード設定 WiFi.begin(ssid, password); // SSID,パスワードを指定してアクセスポイント接続 // Wi-Fi接続確認 while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.println("WiFiに接続しました。"); Serial.println(""); } // ⑥繰り返し処理(センサーを読んで、シリアル通信出力) void loop() { r_t = rd_dat_ADT7410(); // ☆ 温度センサ-(ADT7410)データ取得 read_data(); // XYZ軸データ取得 loopCnt = loopCnt + 1 ; body = r_t ; // 温度データを送信ボディに設定 WiFiClient client; // TCP接続用にWiFiClient classを使用する // TCP接続確認 if (!client.connect(host, httpPort)) { // 外部サーバーに接続 Serial.println("接続に失敗しました。"); return; } // サーバにリクエストを送信(POST) client.print(String("POST ") + path + " HTTP/1.1\r\n" + "Host: " + host + "\r\n" + "Content-Length:" + String(body.length())+ "\r\n" + "Connection: close\r\n\r\n" + body); // リクエスト結果受信待ち unsigned long timeout = millis(); while (client.available() == 0) { if (millis() - timeout > 12000) { Serial.println(">>> タイムアウトしました。"); client.stop(); return; } } // HTTPヘッダを含むデータの読み取り(1文字毎) String raw = ""; while (client.available()) { char c = client.read(); raw = raw +c; } // HTTPヘッダの削除、 int index = raw.indexOf("\r\n\r\n"); // 改行が2回続く箇所検索(\r\n(='CR+LF')) // ( index + s_p + 2 )から1文字切り出す rtn = raw.substring(index+s_p , index+s_p + 32 ) ; Serial.println("--------------------------------------------------------------"); //Serial.print( loopCnt ) ; // 送信回数 Serial.print("送信:"); Serial.print(r_t); // 送信データ 出力 Serial.print(", 受信:"); Serial.println(rtn); // 受信データ出力 Serial.println(""); // 改行 // WiFi.disconnect(); // Wifiの切断 // 1000=1秒 delay(5 * 60 * 1000); }
以下の図はプログラム実行時のシリアルモニター出力内容です。約5分おきにサーバーに送った「送信データ」とサーバから返信された「受信データ」を出力しています。
(2)レンタルサーバー側プログラム①(SQLite書き込み)
レンタルサーバー側のプログラムを示します。行番8でESPr® Developerから送信されたデータを受け取ります。行番10~17で受け取ったデータを書き込むSQLiteデータベースファイルが存在しているか確認します。存在しない場合、行番18~22で新たにデータベースファイルを作成します。行番28では受け取った値が、1度~45度以内の範囲であることを確認し、行番29~32でデータベースファイルに書き込みを行います。
行番34,36では、書き込みを行った場合、行わなかった場合の結果をESPr® Developer側に送信しています。
<?php // 日時取得 date_default_timezone_set('Asia/Tokyo'); $timestamp = date('Y-m-d H:i:s'); // post送信のBodyすべて取得 $entireBody = file_get_contents('php://input'); // 温度記録用テーブルを作成 $db = null ; $sql = null ; $res = null; $db = new SQLite3("./sq/temp_record.sqlite3"); // テーブル有無確認用のSQL $sql = 'SELECT count(*) FROM sqlite_master WHERE type="table" AND name="temp_reco"'; // テーブルがない場合は新たに作成 if(!$db->querySingle($sql)){ $sql = "CREATE TABLE temp_reco( id INTEGER PRIMARY KEY, g_temp TEXT NOT NULL, created_datetime TIMESTAMP DEFAULT(datetime(CURRENT_TIMESTAMP,'localtime')))"; $res = $db->exec($sql); //echo "<br>"; //echo "商品リストテーブルを新たに作成しました。"; } if($entireBody >= 1 && $entireBody <= 45){ $db = null ; $sql = null ; $res = null; $db = new SQLite3("./sq/temp_record.sqlite3"); $sql = 'INSERT INTO temp_reco( g_temp ) VALUES ("'.$entireBody.'")'; $res = $db->exec($sql); echo "OK , ".$entireBody." , ".$timestamp ; }else{ echo "NG , ".$entireBody." , ".$timestamp ; } ?>
(3)レンタルサーバー側プログラム②(SQLite読み出し)(2)で書き込んだレンタルサーバー上のSQLiteファイルからデータを読み出すプログラムを示します。行番3~7で登録されている全てのデータセットを読み出し、行番9~18でブラウザー上に出力します。
<?php $db = null;$sql = null;$res = null; $db = new SQLite3("./sq/temp_record.sqlite3"); $sql = 'SELECT * FROM temp_reco'; $res = $db->query($sql); while($row = $res->fetchArray(SQLITE3_NUM)) { for($i = 0 ; $i < count($row); $i++){ echo $row [$i]; if($i < count($row) - 1){ echo " , " ; } } echo "<br>"; } ?>
ブラウザーへの出力は以下の様になります。左からカンマで区切って、連番,温度,日時の順に登録時間単位で表示しています。
(件数が蓄積されると、出力時間が掛かりますので、最新20件表示に一部改良)
まとめ |
今回はESPr Developerを使った測定値をサーバー側に保存する為にSQLiteを使ってみました。今回、サーバー側に登録したデータの呼び出しも行ってみましたが、単なるデータの羅列ですので、もう少し見る人にやさしい表示方法を検討する予定です。
IoTやCloudなどの意味は知らいないのですが、なんとなく少し近づいてきた様な気分になっています。
「ESPr Developerを使って、温度を測定し、サーバー上のSQLiteファイルに記録してみる」への1件のフィードバック