前回、とりあえずDSPラジオがWebサーバーとなって、スマホ等からDSPラジオのセンサーの値を表示すると同時に、DSPラジオの操作も出来るようになった。
まぁ一応、機能的にはやりたかったことは出来たのである。
しかし、前回にも書いたが、実際に操作するにあたっては、なんかいまいちな感じがする。つまりUI(ユーザーインターフェース)を改善したいのである。
主にブラウザ画面の改善なので、基本はHTMLなのである。
おじさんはHTMLをまじめに触るのは初体験なのである。
初体験はドキドキするのである(嘘)
改善その1:日本語対応
現在のコードだと、日本語指定しても文字化けしてしまう。
日本語対応を試みる
対話型AIに質問して、答えを要約すると・・
UTF-8の文字コードを指定してWebサーバーを構築するには、Content-Type
ヘッダーを適切に設定する必要があります。以下は、先ほどのコードにUTF-8の文字コードを指定するための変更を加えた例です。
String html = "<html><head><meta charset=\"UTF-8\"></head><body>";
にゃるほど。コピペして以下とした。
void handleRootPage(AsyncWebServerRequest *request) {
String html = "<html><head><meta charset=\"UTF-8\"></head><body>";
// 内部変数の値を表示
html += "温度: " + String(temp,1) + " ℃<br>";
html += "湿度: " + String(humidity,0) + " %<br>";
html += "CO2濃度: " + String(CO2_data,0) + " ppm<br>";
結果、このようにちゃんと表示できた。
本体の表示と同じように、湿度、CO2濃度は小数点以下は表示しないようにもし。
(PCのブラウザ表示↓)
改善その2:スマホ等での表示が小さくて使いにくい
前回の記事でも書いたのだが、スマホ等で表示させると、デフォルトでは文字が小さくて、いちいち拡大表示しないといけない。世の中のwebサイトでは、スマホでアクセスした場合でも、それっぽく見やすいサイズになっている。
で、対話型AIに聞いてみる。
----------------------------------
質問
PCやスマホの画面サイズに合わせて表示を調整するには どうすれば良い?
--------------------------------
html += "<meta name='viewport' content='width=device-width, initial-scale=1.0'>";
このメタタグは、ビューポートの設定を行い、デバイスの幅に基づいて正しくスケーリングされるようにします。
----------------------
にゃるほど、以下のようにコピペして試してみる
void handleRootPage(AsyncWebServerRequest *request) {
String html = "<html><head><meta charset=\"UTF-8\">";
html += "<meta name='viewport' ";
html += "content='width=device-width, initial-scale=1.0'>";
html += "</head><body>";
すると、手で拡大表示しなくても、おじさんの眼でも識別できる程度の大きさで表示するようになった。
改善その3:ボタンを大きくして、ボタンの文字も大きくしたい
どうも、ボタンのサイズが小さくて、ボタンの文字も小さいので、ちょっと修正したい。
もちろん、おじさんにはどうすれば良いか分からないので、対話型AIにお願いする。
--------------------------------
お願い
さらにボタンのサイズを大きくしてボタンの中の文字も大きくするにはどうすれば良い?
---------------------------------
ボタンのサイズを大きくし、ボタン内のテキストを大きくするためには、HTMLとCSSを使用してスタイルを指定する必要があります。以下に、ボタンのサイズとテキストサイズを大きくするための修正例を示します。
まず、HTMLのボタン要素にclass
属性を追加して、CSSでスタイルを指定できるようにします。次に、CSSのスタイルシート内でボタンのサイズとテキストサイズを指定します。
// ルートパスのハンドラーを追加
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
String html = "<html><head>";
html += "<style>";
html += ".button {";
html += " font-size: 24px;"; // ボタンのテキストサイズ
html += " width: 200px;"; // ボタンの幅
html += " height: 80px;"; // ボタンの高さ
html += "}";
html += "</style>";
html += "</head><body>";
html += "<h1>Temperature: " + String(temp) + "°C</h1>";
html += "<h1>Humidity: " + String(humidity) + "%</h1>";
html += "<h1>CO2 Data: " + String(CO2_data) + "</h1>";
html += "<br><br>";
html += "<button class='button' onclick=\"sendRequest('radio_on')\">Radio On/Off</button>";
html += "<button class='button' onclick=\"sendRequest('volume_up')\">Volume Up</button>";
html += "<button class='button' onclick=\"sendRequest('volume_down')\">Volume Down</button>";
html += "<button class='button' onclick=\"sendRequest('tune_up')\">Tune Up</button>";
html += "<button class='button' onclick=\"sendRequest('tune_down')\">Tune Down</button>";
html += "<button class='button' onclick=\"sendRequest('mode')\">Mode</button>";
html += "<button class='button' onclick=\"sendRequest('band')\">Band</button>";
html += "<script>";
html += "function sendRequest(action) {";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.open('GET', '/' + action, true);";
html += "xhttp.send();";
html += "}";
html += "</script>";
html += "</body></html>";
request->send(200, "text/html", html);
});
上記の修正では、button
クラスを持つ要素に対してCSSスタイルを適用するように指定しています。CSSの.button
セレクタ内で、ボタンのテキストサイズ、幅、高さを指定しています。
修正を加えた後、ESP32にプログラムをアップロードし、ブラウザからアクセスしてボタンを表示すると、ボタンのサイズとテキストサイズが大きくなっているはずです。必要に応じて、CSSのスタイルを調整して、表示をカスタマイズできます。
-----------------------------------
にゃるほど、もう、おじさんは言われるがままに以下のように修正してみる。
void handleRootPage(AsyncWebServerRequest *request) {
String html = "<html><head><meta charset=\"UTF-8\">";
html += "<meta name='viewport' ";
html += "content='width=device-width, initial-scale=1.0'>";
html += "<style>";
html += ".button {";
html += " font-size: 16px;"; // ボタンのテキストサイズ
html += " width: 130x;"; // ボタンの幅
html += " height: 35px;"; // ボタンの高さ
html += "}";
html += "</style>";
html += "</head><body>";
// 内部変数の値を表示
html += "温度: " + String(temp,1) + " ℃<br>";
html += "湿度: " + String(humidity,0) + " %<br>";
html += "CO2濃度: " + String(CO2_data,0) + " ppm<br>";
// ボタンを表示
html += "<br>";
html += "<button class='button' onclick=\"sendRequest('radio_on')\">Radio On/Off</button>";
html += "<br><br>";
html += "<button class='button' onclick=\"sendRequest('volume_up')\">Volume Up</button>";
html += " ";
html += "<button class='button' onclick=\"sendRequest('volume_down')\">Volume Down</button><br>";
html += "<br>";
html += "<button class='button' onclick=\"sendRequest('tune_up')\">Tune Up</button>";
html += " ";
html += "<button class='button' onclick=\"sendRequest('tune_down')\">Tune Down</button><br>";
html += "<br>";
html += "<button class='button' onclick=\"sendRequest('mode')\">Mode</button>";
html += " ";
html += "<button class='button' onclick=\"sendRequest('band')\">Band</button>";
html += "<script>";
html += "function sendRequest(action) {";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.open('GET', '/' + action, true);";
html += "xhttp.send();";
html += "}";
html += "</script>";
html += "</body></html>";
request->send(200, "text/html", html);
}
何回か試してボタンの文字サイズとボタンサイズを調整した。
このような大きさサイズになった。
改善その4:最新のセンサーの数値を常にWeb画面に反映させる
センサーの値は刻々と変化しているのである。しかし今の状態では、アクセスした時点での状態を表示するだけで、ブラウザのリロードボタンを押さない限り、表示は更新されない。
データが変わった時などにESP32側から、webブラウザに数値の更新を出来るようにしたい。
これは、ものすごく苦労した。
おじさんのお願いの仕方が悪いのか、AIがまだ十分な性能出ないのか、 AIが書いたコードをコンパイルしてもエラーになる等、なかなか上手くいかなかった。何十回もいろいろAIにお願いしたり、コードを書き換えたりして、ようやく以下のように、setup()内に次のコードを配置して、うまく動くようになった。
//-------------------------
// web server set up
//--------------------------
server.on("/", HTTP_GET, [](AsyncWebServerRequest *request){
String html ="<html><head><meta charset=\"UTF-8\">";
html += "<meta name='viewport' ";
html += "content='width=device-width, initial-scale=1.0'>";
html += "<style>";
html += "button {";
html += " padding: 10px 15px;"; // ボタンのパディングを大きくする
html += " font-size: 18px;"; // 文字のサイズを大きくする
html += "}";
html += "</style>";
html +="<html><body>";
html += "<h1 style='font-size: 24px;'>温度: <span id='temp'>" + String(temp,1) + "</span> ℃</h1>";
html += "<h1 style='font-size: 24px;'>湿度: <span id='humidity'>" + String(humidity,0) + "</span> %</h1>";
html += "<h1 style='font-size: 24px;'>CO2濃度: <span id='CO2'>" + String(CO2_data,0) + "</span> ppm</h1>";
html += "<br>";
html += "<button onclick=\"sendRequest('radio_on')\">Radio on/off</button>";
html += "<br><br>";
html += "<button onclick=\"sendRequest('volume_up')\">Volume up</button>";
html += " ";
html += "<button onclick=\"sendRequest('volume_down')\">Volume down</button>";
html += "<br><br>";
html += "<button onclick=\"sendRequest('tune_up')\">Tune up</button>";
html += " ";
html += "<button onclick=\"sendRequest('tune_down')\">Tune down</button>";
html += "<br><br>";
html += "<button onclick=\"sendRequest('mode')\">Mode</button>";
html += " ";
html += "<button onclick=\"sendRequest('band')\">Band</button>";
html += "<script>function sendRequest(action) {";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.open('GET', '/action?action=' + action, true);";
html += "xhttp.send();";
html += "}</script>";
html += "<script>setInterval(function() {";
html += "var tempSpan = document.getElementById('temp');";
html += "var humiditySpan = document.getElementById('humidity');";
html += "var CO2Span = document.getElementById('CO2');";
html += "var xhttp = new XMLHttpRequest();";
html += "xhttp.onreadystatechange = function() {";
html += "if (this.readyState == 4 && this.status == 200) {";
html += "var response = JSON.parse(this.responseText);";
html += "tempSpan.innerHTML = response.temp;";
html += "humiditySpan.innerHTML = response.humidity;";
html += "CO2Span.innerHTML = response.CO2;";
html += "}";
html += "};";
html += "xhttp.open('GET', '/data', true);";
html += "xhttp.send();";
html += "}, 1000);</script>";
html += "</body></html>";
request->send(200, "text/html", html);
});
// データ取得のハンドラー
server.on("/data", HTTP_GET, [](AsyncWebServerRequest *request){
String json = "{\"temp\":" + String(temp,1) + ",";
json += "\"humidity\":" + String(humidity,0) + ",";
json += "\"CO2\":" + String(CO2_data,0) + "}";
request->send(200, "application/json", json);
});
// アクションのハンドラー
server.on("/action", HTTP_GET, [](AsyncWebServerRequest *request){
if (request->hasParam("action")) {
String action = request->getParam("action")->value();
if (action == "radio_on") {
radioOn_web_button = true;
} else if (action == "volume_up") {
volume_up_web_button = true;
} else if (action == "volume_down") {
volume_down_web_button = true;
} else if (action == "tune_up") {
tune_up_web_button = true;
} else if (action == "tune_down") {
tune_down_web_button = true;
} else if (action == "mode") {
mode_web_button = true;
} else if (action == "band") {
band_web_button = true;
}
}
request->send(200);
});
// サーバーの開始
server.begin();
}
1秒ごとに値を取るようなスクリプトをWebブラウザで実行させることで実現。
スケッチ全体を下の方で公開するので、詳細が知りたい方は、そちらを参照してほしい。
結果、このように表示するようになり、自動で数値も更新されるようになった。
文字サイズも指定し直して大きさも整ったような気がする。
この他にも、ラジオのon/offの状態表示や、受信周波数の表示などもやりたかったのだが、今のおじさんには知識・技術が圧倒的に足りていない。
一旦、この状態でVer1.0の完成としたい。
将来、おじさんの能力が向上するようなことが有ったら、順次アップデートしてみたい。
あと、消費電流がどの程度か見てみた。
1Ωの抵抗を5Vラインに挿入し、オシロで電位差を測定。
抵抗誤差もあるし、格安中華オシロの精度が悪いので参考程度
ラジオoff、LED全off
約60mA流れている中で、およそ100msec間隔で80mAくらいのピーク電流が流れている。
おそらくはWi-Fiのビーコン応答を送信しているものと思われる
ラジオoff、LED on
約105mAまで上昇 バックライトとカラーLEDで50mAくらい
ラジオon、LED on
さらに30mA増えて135mA ラジオモジュールM6951の消費分
ラジオon、LED on CO2測定時
5秒に1回、CO2濃度測定の際にはさらに100mAのピークが追加される。
この時のピークで330mAくらいになる。
まぁ、これでもUSB電源(500mA)に対しては十分に低い、ということが確認できた。
Ver1.0のスケッチ、回路図等は以下に置いておくので、興味のある方はどうぞ。
ああ、今回の製作は、おじさんの能力を大きく超えるものだったが、先人の知恵と対話型AIの力で何とか出来た。世の中の進歩は何ともすさまじい。
おじさんも能力を伸ばさないと、もっと楽しい物は作れないのである。
「にゃに? もっと猫の手を借りたいのニャ?」