Android Wear センサ活用チュートリアル4 WordPress&PHP編

Pocket

PHPプログラム

本ページは、Android Wear 開発チュートリアルのPHPプログラム編です。Wearアプリの開発やWear↔Mobile間通信については、こちらの Index からご参考ください。

Index

  • Functionalities

  • Files

  • Explanations

機能

post.php (サーバ)
  • スマートフォン側のプログラムからのデータを受け、DBに格納する。

  • (認証については未実装)

charts.php (サーバ)
  • Webサーバから起動され、DBからセンサデータを取得し、Charts.jsを利用したJavascriptのコードを生成し、標準出力に出力する。

  • (Webブラウザ上で Javascriptがチャートをレンダリングする。)

  • (認証については未実装)

Files

post.php

<?php

require_once('bioinfo_classes.php');


if(
        ( isset($_SERVER["SHELL"]) || isset($_SERVER["HOMEPATH"]) )
		&amp;&amp; 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を記載した文字列に対して置換を行います。置換されたものを出力します。

初めに戻る

Android Wear センサ活用チュートリアル3 Android Studio 開発 Mobileプログラム編
なぜウェルビーイング技術が注目されているのか、その理由とは?