| 概 要 |
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件のフィードバック