Android Wear アプリ開発 センサ活用チュートリアル4 WordPress&PHP編
PHPプログラム
本ページは、Android Wear 開発チュートリアルのPHPプログラム編です。Wearアプリの開発やWear↔Mobile間通信については、こちらの Index からご参考ください。
Index
Functionalities
Files
Explanations
機能
post.php (サーバ) |
| |
---|---|---|
charts.php (サーバ) |
|
Files
post.php
<?php require_once('bioinfo_classes.php'); if( ( isset($_SERVER["SHELL"]) || isset($_SERVER["HOMEPATH"]) ) && stristr($argv[0],'post.php') ){ $_REQUEST["d0"]="0,0,".date("Y-m-d H:i:s").",0,0"; } if( isset($_REQUEST["d0"]) ){ $i = 0; $bioinfo_list = new BioInfo_List(); while(true){ $k = "d".$i; if( isset($_REQUEST[$k]) ){ $bioinfo_list->add_bioinfo_from_csv($_REQUEST[$k]); }else{ break; } $i++; } if( count($bioinfo_list->bioinfo_list) > 0 ){ $bioinfo_list->insert_db(); } //var_dump($bioinfo_list); } ?>
charts.php
<?php require_once('bioinfo_classes.php'); ?> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8"> <title>Graphs</title> <script src="https://cdnjs.cloudflare.com/ajax/libs/Chart.js/2.7.2/Chart.bundle.js"></script> </head> <body> <h1>Graphs</h1> <?php $bioinfo_list = new Bioinfo_List(); $bioinfo_list->chart_flg="xyz"; $bioinfo_list->load_sensor_values_from_db("acc",20); $bioinfo_list->set_chart_config("acc","acc",30,-30,10); $bioinfo_list->output_chart_js("acc"); $bioinfo_list = new Bioinfo_List(); $bioinfo_list->chart_flg="0"; $bioinfo_list->load_sensor_values_from_db("hr",20); $bioinfo_list->set_chart_config("hr","hr",140,0,10); $bioinfo_list->chart_max=140; $bioinfo_list->chart_min=0; $bioinfo_list->output_chart_js("hr"); $bioinfo_list = new Bioinfo_List(); $bioinfo_list->chart_flg="0"; $bioinfo_list->load_sensor_values_from_db("lux",20); $bioinfo_list->set_chart_config("lux","lux",0,0,0); $bioinfo_list->output_chart_js("lux"); $bioinfo_list = new Bioinfo_List(); $bioinfo_list->chart_flg="incremental"; $bioinfo_list->load_sensor_values_from_db("sc",20); $bioinfo_list->set_chart_config("sc","sc",100,0,0); $bioinfo_list->output_chart_js("sc"); ?> </body> </html>
bioinfo_classes.php
<?php $DB_HOST="localhost"; $DB_USER="xxxxx"; $DB_PW="xxxxx"; $DB_NAME="wpbioinfo"; Class Bioinfo_List { public $bioinfo_list=array(); public $chart_flg=0; public $chart_max=0; public $chart_min=0; public $chart_config = array( "__PREFIX__"=>"", "__CHART_TITLE__"=>"", "__CHART_MAX__"=>40, "__CHART_MIN__"=>0, "__STEP_SIZE__"=>10); public function add_bioinfo_from_csv($csv){ $rec = new BioInfo(); $rec->set_values_from_csv($csv); $this->bioinfo_list[] = $rec; } public function insert_db(){ //echo "insert db<BR>\n"; try { $pdo_opts = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]; $pdo = new PDO ( 'mysql:host='.$GLOBALS["DB_HOST"].';dbname='.$GLOBALS["DB_NAME"].';charset=utf8', $GLOBALS["DB_USER"], $GLOBALS["DB_PW"], $pdo_opts ); $stmt = $pdo->prepare( 'INSERT INTO `'."sensor_data".'` (`user_id`,`device_id`,`timestamp`,`sensor_id`,`value`) VALUES (:user_id,:device_id,:timestamp,:sensor_id,:value) ON DUPLICATE KEY UPDATE `value`=VALUES(`value`) ;'); foreach( $this->bioinfo_list as $i => $rec ){ //var_dump($rec); $d = explode(' ', $rec->timestamp); if( count($d) == 3 ){ array_pop($d); $rec->timestamp=join(' ',$d); } $stmt->bindValue(':user_id', $rec->user_id, PDO::PARAM_STR); $stmt->bindValue(':device_id', $rec->device_id, PDO::PARAM_STR); $stmt->bindValue(':timestamp', $rec->timestamp, PDO::PARAM_STR); $stmt->bindValue(':sensor_id', $rec->sensor_id, PDO::PARAM_STR); $stmt->bindValue(':value', $rec->value, PDO::PARAM_STR); $stmt->execute(); } }catch(PDOException $PDO_ERROR){ header('Content-Type: text/plain; charset=UTF-8', true, 500); exit('DataBase ERROR/'.$PDO_ERROR->getMessage()."\n"); } return(count($this->bioinfo_list)); } public function load_sensor_values_from_db($str, $num){ if( $this->chart_flg == "xyz" ){ $num = $num*3; } try { $pdo_opts = [ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION, PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, ]; $pdo = new PDO ( 'mysql:host='.$GLOBALS["DB_HOST"].';dbname='.$GLOBALS["DB_NAME"].';charset=utf8', $GLOBALS["DB_USER"], $GLOBALS["DB_PW"], $pdo_opts ); $stmt = $pdo->prepare( 'SELECT * FROM `'."sensor_data".'` WHERE `user_id`=0 AND `device_id`=0 AND `sensor_id` LIKE "%'.$str.'%" ORDER BY `timestamp` DESC LIMIT '.$num.' ;'); $stmt->execute(); while($result = $stmt->fetch(PDO::FETCH_ASSOC)){ $rec = new BioInfo(); $rec->set_values_from_assoc($result); $this->bioinfo_list[] = $rec; } }catch(PDOException $PDO_ERROR){ header('Content-Type: text/plain; charset=UTF-8', true, 500); exit('DataBase ERROR/'.$PDO_ERROR->getMessage()."\n"); } return(count($this->bioinfo_list)); } public function set_chart_config($prefix,$title,$max,$min,$step){ $this->chart_config = array( "__PREFIX__"=>$prefix, "__CHART_TITLE__"=>$title, "__CHART_MAX__"=>$max, "__CHART_MIN__"=>$min, "__STEP_SIZE__"=>$step); } public function output_chart_js($prefix){ $chart_js_str=' <style type="text/css"> <!-- div.chart_canvas { width: 48%; } --> </style> <DIV class="chart_canvas"> <canvas id="__PREFIX__Chart"></canvas> </DIV> <script> var ctx = document.getElementById("__PREFIX__Chart"); var myChart = new Chart(ctx, { type: "line", data: { labels: [__X_AXIS_LABELS__], datasets: [ { label: "__VALUE_LABEL_1__", data: [__DATA_ARRAY_1__], borderColor: "rgba(255,0,0,1)", backgroundColor: "rgba(0,0,0,0)" }'; if( $this->chart_flg=="xyz" ){ $chart_js_str=$chart_js_str.', { label: "__VALUE_LABEL_2__", data: [__DATA_ARRAY_2__], borderColor: "rgba(0,255,0,1)", backgroundColor: "rgba(0,0,0,0)" }, { label: "__VALUE_LABEL_3__", data: [__DATA_ARRAY_3__], borderColor: "rgba(0,0,255,1)", backgroundColor: "rgba(0,0,0,0)" }'; } $chart_js_str=$chart_js_str.' ], }, options: { title: { display: true, text: "__CHART_TITLE__" }, scales: { yAxes: [{ ticks: { suggestedMax: __CHART_MAX__, suggestedMin: __CHART_MIN__, stepSize: __STEP_SIZE__, callback: function(value, index, values){ return value; //return value + "度" } } }] }, } }); </script> '; $timestamp_list=array(); $value_list_1=array(); $value_list_2=array(); $value_list_3=array(); foreach ( $this->bioinfo_list as $i => $rec ){ $t = preg_replace('{.* ([0-9]*:[0-9]*):[0-9]*.*}',"$1",$rec->timestamp); if( !in_array($t,$timestamp_list) ){ $timestamp_list[] = $t; } if( $this->chart_flg == "xyz" ){ if( $rec->sensor_id==$prefix." x" ){ $value_list_1[] = $rec->value; }else if( $rec->sensor_id==$prefix." y" ){ $value_list_2[] = $rec->value; }else if( $rec->sensor_id==$prefix." z" ){ $value_list_3[] = $rec->value; } }else if( $this->chart_flg == "incremental" ){ if( count($value_list_1) == 0 ){ $value_list_1[] = 0; }else{ $value_list_1[] = $this->bioinfo_list[$i-1]->value - $rec->value; } }else{ $value_list_1[] = $rec->value; } } $timestamp_list = array_reverse($timestamp_list); $value_list_1 = array_reverse($value_list_1); $value_list_2 = array_reverse($value_list_2); $value_list_3 = array_reverse($value_list_3); foreach ( $this->chart_config as $k => $v ){ $chart_js_str=str_replace($k,$v,$chart_js_str); } $chart_js_str=str_replace("__X_AXIS_LABELS__",'"'.join('","',$timestamp_list).'"',$chart_js_str); $chart_js_str=str_replace("__VALUE_LABEL_1__","x",$chart_js_str); $chart_js_str=str_replace("__DATA_ARRAY_1__",join(",",$value_list_1),$chart_js_str); $chart_js_str=str_replace("__VALUE_LABEL_2__","y",$chart_js_str); $chart_js_str=str_replace("__DATA_ARRAY_2__",join(",",$value_list_2),$chart_js_str); $chart_js_str=str_replace("__VALUE_LABEL_3__","z",$chart_js_str); $chart_js_str=str_replace("__DATA_ARRAY_3__",join(",",$value_list_3),$chart_js_str); echo $chart_js_str; } } Class BioInfo { public $user_id; public $device_id; public $timestamp; public $sensor_id; public $value; public function set_values_from_csv($csv){ $d = explode(",",$csv); $this->user_id = $d[0]; $this->device_id = $d[1]; $this->timestamp = $d[2]; $this->sensor_id = $d[3]; $this->value = $d[4]; } public function set_values_from_assoc($assoc){ foreach ( $assoc as $k => $v ){ $this->$k = $v; } } } ?>
Database
使っているテーブルの仕様は以下の通り、複数ユーザ対応を想定したuser_id、例えばスマートウォッチに加えてスマートフォンのセンサデータを取得するなど、複数デバイスの利用を想定した device_id は現在のところ、使われていない。
# | 名前 | データ型 | 照合順序 | NULL | デフォルト値 | コメント | その他 | |||
1 | varchar(255) | utf8_general_ci | いいえ | なし | ||||||
2 | varchar(255) | utf8_general_ci | いいえ | なし | ||||||
3 | timestamp | いいえ | CURRENT_TIMESTAMP | ON UPDATE CURRENT_TIMESTAMP | ||||||
4 | varchar(255) | utf8_general_ci | いいえ | なし | ||||||
5 | float | いいえ | なし |
コード解説
AndroidからHTTP POSTをする方法は前のページ「Mobileプログラム編」をご参考ください。
Chart.js: グラフを表示する
<DIV class="chart_canvas"> <canvas id="__PREFIX__Chart"></canvas> </DIV> <script> var ctx = document.getElementById("__PREFIX__Chart"); var myChart = new Chart(ctx, { type: "line", data: { labels: [__X_AXIS_LABELS__], datasets: [ { label: "__VALUE_LABEL_1__", data: [__DATA_ARRAY_1__], borderColor: "rgba(255,0,0,1)", backgroundColor: "rgba(0,0,0,0)" }, { label: "__VALUE_LABEL_2__", data: [__DATA_ARRAY_2__], borderColor: "rgba(0,255,0,1)", backgroundColor: "rgba(0,0,0,0)" }, { label: "__VALUE_LABEL_3__", data: [__DATA_ARRAY_3__], borderColor: "rgba(0,0,255,1)", backgroundColor: "rgba(0,0,0,0)" } ], }, options: { title: { display: true, text: "__CHART_TITLE__" }, scales: { yAxes: [{ ticks: { suggestedMax: __CHART_MAX__, suggestedMin: __CHART_MIN__, stepSize: __STEP_SIZE__, callback: function(value, index, values){ return value; //return value + "度" } } }] }, } }); </script>
上記にChart.jsを使う場合のコードを掲載しました。
- 7行目: type: “line”
グラフの種類の指定です。ここでは線グラフにしています。
- 8行目: data: {}
ここからX軸の設定です。
- 9行目: labels: [__X_AXIS_LABELS__]
X軸のラベルの設定です。ここには時刻が入ります。
- 10行目: datasets: []
データの設定です。ここではデータが3セットで、線が3本の設定になっていますが、線が1本のグラフの場合、PHP側で調整しています。
label: ・・・ データの名前。心拍数、歩数等。
data: ・・・ 数値の配列をコンマ区切りで繋げた文字列
borderColor: ・・・ 線の色
backgroundColor: ・・・ 背景色
- 34行目: text: “__CHART_TITLE__”
グラフタイトルの設定です。
- 37行目:
Y軸の設定です。
suggestedMax: ・・・ Y軸の最大値の設定です。0の場合、データの数値が超過した場合は自動で設定されるようです。
suggestedMin: ・・・ Y軸の最小値の設定です。0の場合、データの数値が下回った場合は自動で設定されるようです。
stepSize: ・・・ 横補助線の感覚です。
callback: 個々のデータ点上に単位を入れる場合に使います。
Class Bioinfo_List { public $bioinfo_list=array(); public $chart_flg=0; public $chart_max=0; public $chart_min=0; public $chart_config = array( "__PREFIX__"=>"", "__CHART_TITLE__"=>"", "__CHART_MAX__"=>40, "__CHART_MIN__"=>0, "__STEP_SIZE__"=>10); public function set_chart_config($prefix,$title,$max,$min,$step){ $this->chart_config = array( "__PREFIX__"=>$prefix, "__CHART_TITLE__"=>$title, "__CHART_MAX__"=>$max, "__CHART_MIN__"=>$min, "__STEP_SIZE__"=>$step); } public function output_chart_js($prefix){ $chart_js_str='ここにJavascriptのコードを入れる'; if( $this->chart_flg=="xyz" ){ $chart_js_str=$chart_js_str.'ここにJavascriptのコードを入れる'; } $chart_js_str=$chart_js_str.'ここにJavascriptのコードを入れる'; $timestamp_list=array(); $value_list_1=array(); $value_list_2=array(); $value_list_3=array(); foreach ( $this->bioinfo_list as $i => $rec ){ $t = preg_replace('{.* ([0-9]*:[0-9]*):[0-9]*.*}',"$1",$rec->timestamp); if( !in_array($t,$timestamp_list) ){ $timestamp_list[] = $t; } if( $this->chart_flg == "xyz" ){ if( $rec->sensor_id==$prefix." x" ){ $value_list_1[] = $rec->value; }else if( $rec->sensor_id==$prefix." y" ){ $value_list_2[] = $rec->value; }else if( $rec->sensor_id==$prefix." z" ){ $value_list_3[] = $rec->value; } }else if( $this->chart_flg == "incremental" ){ if( count($value_list_1) == 0 ){ $value_list_1[] = 0; }else{ $value_list_1[] = $this->bioinfo_list[$i-1]->value - $rec->value; } }else{ $value_list_1[] = $rec->value; } } $timestamp_list = array_reverse($timestamp_list); $value_list_1 = array_reverse($value_list_1); $value_list_2 = array_reverse($value_list_2); $value_list_3 = array_reverse($value_list_3); foreach ( $this->chart_config as $k => $v ){ $chart_js_str=str_replace($k,$v,$chart_js_str); } $chart_js_str=str_replace("__X_AXIS_LABELS__",'"'.join('","',$timestamp_list).'"',$chart_js_str); $chart_js_str=str_replace("__VALUE_LABEL_1__","x",$chart_js_str); $chart_js_str=str_replace("__DATA_ARRAY_1__",join(",",$value_list_1),$chart_js_str); $chart_js_str=str_replace("__VALUE_LABEL_2__","y",$chart_js_str); $chart_js_str=str_replace("__DATA_ARRAY_2__",join(",",$value_list_2),$chart_js_str); $chart_js_str=str_replace("__VALUE_LABEL_3__","z",$chart_js_str); $chart_js_str=str_replace("__DATA_ARRAY_3__",join(",",$value_list_3),$chart_js_str); echo $chart_js_str; } } ?>
Chart.jsの仕様に合わせて文字列を生成し、javascriptを記載した文字列に対して置換を行います。置換されたものを出力します。