2021/09/10
Raspberry Piに温度、湿度、気圧をとれるセンサーBME280を取り付けて、データをMicrosoftのクラウドAzureに送信し、グラフ描画してみました。
2年ほど前に同様の事をしたことがありました。その時の記録はこちら↓↓↓。
その際、Stream Analyticsという有料サービスを無料と思い込み、2ヵ月間動かし続けて2万円の請求が来てしまうという、大失敗をやらかしました。今回は別なアプローチで無料枠で動かせるように、試した手順の紹介です。
各ステップ毎に、3回に分けて書きます。
- 温度・湿度・気圧をBME280/Raspberry Pi/Azureで可視化 その1(AzureにWEBサーバとDBの準備編) ←本稿
- 温度・湿度・気圧をBME280/Raspberry Pi/Azureで可視化 その2(Raspberry Pi Zero WにBME280取り付け・データ送信編)
- 温度・湿度・気圧をBME280/Raspberry Pi/Azureで可視化 その3(チャート描画編)
構成概要
Raspberry Pi Zero Wに、温度・湿度・気圧の測定できるセンサーモジュールBME280を取り付ます。そして、読み取った値を一定間隔でWEBサーバにアップロードし、グラフで可視化する事を最終目標とします。
Raspberry Piでのデータ送信プログラムはPython、データを受け取るWebサーバはAzureのWebApps、データを格納するDBはMySQL、WEBサーバサイドのプログラムはPHP、ブラウザでのグラフ描画はJavaScriptを利用します。
最終的には、WEBブラウザ上でこのようなグラフを表示させます。
Azure Web Appsの準備
Azure Portalにログインします。アカウントは無料で作れます。
ログイン後、リソースの作成を選択します。
Webアプリを選択します。
作成するWebアプリの詳細を入力します。
- サブスクリプション:料金支払いのお財布のようなイメージ。
- リソースグループ:関連するサービスをグループ化します。
- 名前:この名前がアクセスするURLになります(例:https://●●●.azurewebsites.net)。
- 公開:コードを選択します。
- ランタイムスタック:PHPを選択します。
- オペレーティングシステム:Windowsを選択。後述しますが、Linuxを選択すると、MySQLが選択不可となります。
- 地域:近くのサーバが良いでしょう。
- SKUとサイズ:デフォルトではS1が選択されています。無料で動かせるF1に変更します。
開発/テストを選択>F1を選択します。
SKUとサイズがFreeF1になっている事を確認し、確認及び作成を選択します。
作成前の確認画面。作成を選択します。
おおよそ30秒ぐらいで、デプロイが完了します。ここまでの作業時間は、慣れてしまえばほんの数分。こんなに簡単な作業でWEBサーバが出来上がってしまいます。Azure凄い!
作成したAppsの概要を選択し、デプロイしたWEBサーバにアクセスしてみます。httpsがデフォルトで有効になっているのもありがたいですね。
デフォルト画面。このページは特に変更せずに、そのままにしておきます。
MySQLの準備
続いて、DBのMySQL in Appを設定します。MySQL in Appを選択>オンを選択>保存を選択>管理を選択します。この操作でDBが利用できるようになります。ホントに簡単です。
ちなみに、WebAppsを作成する際に、オペレーティングシステム:Linuxを選択すると、MySQL in Appが下記のようにグレーアウトして、「Linuxアプリでは、この機能はご利用いただけません。」と表示され選択できません。自社OSを使ってもらう為なんでしょうか。やりたいことができればどちらでもよいんですけどね。
MySQL in Appの管理を選択すると、DBの管理が出来るphpMyAdminが立ち上がります。しかし、場合によっては以下のようなエラー画面や、ユーザー名/パスワードを求められる画面が出る場合があります。
Error
MySQL said:
#2002 - An attempt was made to access a socket in a way forbidden by its access permissions.
— The server is not responding (or the local server's socket is not correctly configured).
ログインするIDやパスワードは設定してないし、どこにも書いてないのです。
このような画面が出たときの対処ですが、アプリの概要から、URLにアクセスし、再度MySQL in Appの管理を選択すると、phpMyAdminの画面に入れると思います。
デフォルトでデータベースlocaldbは作成済みのため、テーブルsensordataを下記内容で作成します。tempは温度を、humは湿度を、pressは気圧を格納します。
sensordataテーブルを設定します。localdbを選択>SQL>以下のCREATE文を貼り付け>Goを選択します。
CREATE TABLE `sensordata` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`datetime` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
`temp` float NOT NULL,
`hum` float NOT NULL,
`press` float NOT NULL,
PRIMARY KEY (`id`)
)DEFAULT CHARSET=utf8;
作成したテーブルを確認してみます。
データベースには、予めIDとパスワードが自動で設定されていたので、確認してみます。高度なツール>移動を選択します。
Kuduというツールを使います。クーズーと読むらしいです。呼び名に似つかわしくなく非常に優秀なツールで、そのギャップに思わず笑ってしまいました。Debug console>PowerShellを選択します。
MySQLのユーザー名やパスワードを確認してみます。ディレクトリ[D:\home\data\mysql]に移動し、[MYSQLCONNSTR_localdb.txt]の内容を確認します。データベース名、ホスト名、ポート番号、ユーザーID、パスワードが確認できます。
cat MYSQLCONNSTR_localdb.txt
プログラムのアップロード
WEBコンテンツが保存されるルートディレクトリは、[D:\home\site\wwwroot]となります。ルートディレクトリに直接ファイルを置きたくないので、[sensortest]というディレクトリを作成しました。
データベースにデータをインサートするのに、IDとパスワードが必要となります。今回利用するMySQLinAppの情報を調べてみると、上記のIDパスワードを直接設定してもDB接続できるらしいですが、ポート番号が不定期に変更され、接続できなくなることがあるとの事。
そのため、環境変数からその都度IDとパスワードをポートを取得する方が良いとの情報がありました。自分も環境変数から必要情報を取得しDB接続する方法をやってみました。環境変数は$_SERVER[“MYSQLCONNSTR_localdb”]で渡されます。参考にしたサイトはこちら。
DB接続で上手くいったコード[DbManager.php]と[Encode.php]。
<?php
function GetDb(){
$azure_mysql_connstr = $_SERVER["MYSQLCONNSTR_localdb"];
$azure_mysql_connstr_match = preg_match(
"/".
"Database=(?<database> .+);".
"Data Source=(?<datasource> .+):".
"(?<port> .+);".
"User Id=(?<userid> .+);".
"Password=(?<password> .+)".
"/u",
$azure_mysql_connstr,
$_);
$dsn = 'mysql:dbname='.$_['database'].'; host='.$_['datasource'].':'.$_['port'];
$usr = $_['userid'];
$passwd = $_['password'];
try
{
$db = new PDO($dsn, $usr, $passwd);
$db-> exec('SET NAMES utf8');
}
catch (PDOException $e)
{
die("connection failure: {$e-> getMessage()}");
}
return $db;
}
<?php
function e($str, $charset = 'UTF-8'){
print htmlspecialchars($str, ENT_QUOTES, $charset);
}
端末からデータをPOSTメソッドで受け取るプログラム[senserdatapost.php]はこちら。JSON形式で受け取り、データベースにインサートします。
<?php
require_once 'DbManager.php';
require_once 'Encode.php';
$db = GetDB();
$in = json_decode(file_get_contents('php://input'), true);
if (!isset($in['id']))
{
$st = $db->prepare("INSERT INTO sensordata(datetime,temp,hum,press) VALUES(:datetime,:temp,:hum,:press)");
}
$st->execute($in);
echo json_encode("normal end");
3つのファイルをアップロードします。ファイルのアップロードはKuduのWEB画面領域にドラッグ&ドロップで可能です。最近までKuduの存在を知らずにずっとFTPと利用していたのですが、こちらの方が圧倒的に便利です。全てブラウザ1つで完結します。
データベースへ書き込みテスト
温度等のセンサーデータをDBに書き込めるかのテストしてみます。クライアントからアップロードする想定で、以下のテストファイル[testpost.html]を作ってみました。これをサーバにアップロードして、値を適当に入力し送信を選択します。POSTメソッドでJSONデータを送信しています。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>データPOST送信テスト用</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js"></script>
<script type="text/javascript">
$(function(){
$("#response").html("Response Values");
$("#button").click( function(){
var url = $("#url_post").val();
var JSONdata = {
datetime: $("#datetime").val(),
temp: $("#temp").val(),
hum: $("#hum").val(),
press: $("#press").val()
};
alert(JSON.stringify(JSONdata));
$.ajax({
type : 'post',
url : url,
data : JSON.stringify(JSONdata),
contentType: 'application/JSON',
dataType : 'JSON',
scriptCharset: 'utf-8',
success : function(data) {
// Success
alert("success");
alert(JSON.stringify(data));
$("#response").html(JSON.stringify(data));
},
error : function(data) {
// Error
alert("error");
alert(JSON.stringify(data));
$("#response").html(JSON.stringify(data));
}
});
})
})
</script>
</head>
<body>
<h1>データPOST送信テスト</h1>
<p>URL: <input type="text" id="url_post" name="url" size="60" value="https://●●●.azurewebsites.net/sensortest/sensordatapost.php"></p>
<p>時刻: <input type="text" id="datetime" size="30" value="2020-04-18 20:30:12"></p>
<p>温度(℃): <input type="text" id="temp" size="30" value="23"></p>
<p>湿度(%): <input type="text" id="hum" size="30" value="56.3"></p>
<p>気圧(hpa): <input type="text" id="press" size="30" value="1017.2"></p>
<p><button id="button" type="button">送信</button></p>
<textarea id="response" cols=60 rows=1 disabled></textarea>
</body>
</html>
エラーは出ず、データベースに値が登録されているのが確認できました。
Raspberry Piから同じ形式でのデータ送信されれば、データベースへ値が登録される状況になりました。この作業までで、その1(AzureにWEBサーバとDBの準備編)は終了です。
次回その2では、Raspberry Pi Zero Wに物理的にセンサーを取り付ける作業、センサーから値を読み取る設定、読み取った値をサーバにアップロードする設定を行います。
参考にさせていただいたURL