日曜日,雨がちらついていたので,今日に延期かなと思ってましたが,午後から,付かぬ間の曇りの天気で急
遽9回目の芝かりを行ってしまいました。結果的に,長めにならずに芝刈りができてよかったです。大分成長
が早くなってきたので,軸刈り近くなるおそれを回避できました。大分密度もこくなってきましたが,部分
部分,サッチが目立つところがありますので,晴れの日をみて,熊手で,サッチ取りをするようですね。
IOT再びーESP32編(9)ーーー番外編
あれこれとネットサーフィンをしていて,WEBページとサーバーとのやりとりについて,おそまきながらわ
かってきました。この役割をになってるのが,ハンドラーと呼ばれる部分でした。その書き方や意味が少
しわかりました。
特に
サーバー→→→WEB
の方法がいまいちでしたが,この役割のになってるのが,esp32 の processor関数 だとい言うことが
分かりました。
このやりとりをする前段階として,
AsyncWebServerRequest *request; #requestというオブジェクトを作成
request->send(SPIFFS,"/hogehoge.hoge",String(),false,processor);
記述をするようで,記述で,hogehoge.hoge(html記載されたページ)の%で囲まれた文字列がprocessor関
数で置きかえられるとのことでした。
実際には,
WEBからサーバーへホームページ表示のrequest
が出されるなかで,いろいろ解釈されて,%で囲まれた文字列が,processor関数で置き換えられるとのこと
のようでした。これで,ちょっとだけ進歩かなと思います。
芝刈りーー今年第8回目
IOT再びーESP32編(8)ーESP32へ移植完了ーA0221AT(防水超音波センサー)+SSD1306OLE
あれこれ手こずりましたが,ESP32への移植完了しました。おまけに,手元にあったSSD1306OLEを
ディスプレイにくわえました。当初,BLEも加えようかと思いましたが,BLEをいれるとメモリーが足りな
なるので断念。ESP32への接続は次のようにしました。
SSD1306OLE SCL→→→→GPIO22
SDA→→→→GPIO21
A0221AT RX(コネクター3)→→→→GPIO17
TX(コネクター4)→→→→GPIO16
LED 赤(WIFY接続 OFF)→→→→GPIO2
緑(WIFY接続 ON)→→→→GPIO4
ESP32をブレッドボードで使うに当たって,通常の使い方では,端子が使えなくなってしまうので,秋月電子
から購入したブレッドボード BB-01P を二つ組み合わせて使ってます。
OLEは,I2Cのものですが,表示をいれると,通信に時間がかかるのか,WEB に反映されるのに,タイムラ
グがあるようです。実際の運用には,外した方がいいかもですね。
下記が今回使ったスケッチです,といっても,諸兄のものをちょっと改変しただけす。また,WEB用のhtml
ファイルは,ESP32編(3) のものを使ってます。本当は,WEB に距離を反映させたかったのですが,
javascript が手強くて,そのままにしてあります。
// 必要なライブラリのインクルード
#include <wifi.h>
#include <spi.hamp>
#include <webserver.h>
#include <spiffs.h>
#include <adafruit_gfx.h>
#include <adafruit_ssd1306.h>
byte hdr, data_h, data_l, chksum;
String inputString = "";
float distance=0;
float new_distance=0;
float val=0.00f;
// ピンの定義
#define wifyOn 4 // wify 接続OK
#define wifyOff 2 // wify 未接続
//OLE
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C //< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 32 // OLED display height, in pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
// WiFi接続情報(固定IP)
const char* ssid = "*************";
const char* password = "**********";
const IPAddress ip(192, 168, 2, 30);
const IPAddress gateway(192, 168, 2, 2);
const IPAddress subnet(255, 255, 255, 0);
const IPAddress dns1(192, 168, 2, 2);
// WebServerオブジェクトの初期化
WebServer server(80);
// セットアップ関数
void setup() {
Serial.begin(115200); // シリアル通信の開始
Serial2.begin(9600,SERIAL_8N1,16,17);
//OLE開始
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
display.display();
delay(2000); // Pause for 2 seconds
// Clear the buffer
display.clearDisplay();
//OLE初期設定
display.setTextSize(2); // Draw 2X-scale text
display.setTextColor(SSD1306_WHITE);
display.print(F("wify-set"));
display.display();
pinMode(wifyOn, OUTPUT);
pinMode(wifyOff, OUTPUT);
digitalWrite(wifyOn, LOW);
digitalWrite(wifyOff, HIGH);
// SPIFFSの初期化
if(!SPIFFS.begin(true)){
Serial.println("SPIFFSのマウントに失敗しました");
return;
}
// WiFi接続
if (!WiFi.config(ip,gateway,subnet,dns1)){
Serial.println("Failed to configure!");
}
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
digitalWrite(wifyOn, HIGH);
digitalWrite(wifyOff, LOW);
Serial.println("");
Serial.println("WiFi connected");
Serial.println("IP address: ");
Serial.println(WiFi.localIP());
// Webサーバーのルート設定
server.on("/", HTTP_GET, []() {
server.send(200, "text/html", SPIFFS.open("/index.html", "r").readString());
});
// '/distance'で距離を返す設定
server.on("/distance", HTTP_GET, []() {
server.send(200, "text/plain", String(measureDistance()));
});
server.begin(); // サーバーの開始
}
// メインループ
void loop() {
server.handleClient(); // クライアントのリクエストを処理
}
// 距離測定関数
float measureDistance() {
char m[50];
Serial2.write("S");
if (Serial2.available())
{
hdr = (byte)Serial2.read();
if (hdr == 255){
data_h = (byte)Serial2.read();
data_l = (byte)Serial2.read();
chksum = (byte)Serial2.read();
if (chksum == ((hdr + data_h + data_l)&0x00FF)){
distance = data_h * 256 + data_l;
//if(distance!=new_distance){
display.clearDisplay();
new_distance=distance;
dtostrf(new_distance, 6, 1, m);
Serial.print(m);
Serial.println(" mm");
display.setCursor(0, 0);
display.println("distance= ");
display.print(m);
display.println(" mm");
display.display();
// delay(100);
//return new_distance;
//}
}
}
}
delay(100);
return distance;
}
IOT再びーーーESP32編(7)ーーーESP32への移植-A0221AT
A0221ATのセンサーを ESP32 用に移植していました。何度書き換えても,思ったようにうごきませんでし
た。でもある HP の記載を見て,スケッチを変更したらやっと動きました。
いろんな方の HP で,シリアル通信(UART)にデフォルトで使えるピンの説明がありその通りにしていた
のですが,動きませんでした。「デフォルト」ということで,何もしなくてもいいのかと思っていました。
ある方のHPのように
Serial2.begin(9600);→→→→→→Serial2.begin(9600,SERIAL_8N1,16,17);
のように,使うピンを明示してやっと動作しました。
不要な部分を取り除いて,esp32に移植しとりあえず動くようにしたスケッチです。
byte hdr, data_h, data_l, chksum;
unsigned int distance;
void setup() {
// initialize both serial ports:
Serial.begin(9600);
Serial2.begin(9600,SERIAL_8N1,16,17);
}
void loop() {
Serial2.write("1");
if (Serial2.available())
{
hdr = (byte)Serial2.read();
if (hdr == 255){
data_h = (byte)Serial2.read();
data_l = (byte)Serial2.read();
chksum = (byte)Serial2.read();
if (chksum == ((hdr + data_h + data_l)&0x00FF)){
distance = data_h * 256 + data_l;
Serial.print(distance, DEC);
Serial.println(" mm");
}
}
}
delay(100);
}
はっきりしませんが,メジャーで,だいたいの距離をとりながら,測定させています。手で持っているので,
数字が安定しませんが,ほぼほぼ正確な距離をだしています。
始め,
センサーが天井をむいていたので,2000とかの数字ですが,
なおしてから10cm-20cm-30cmと10cm刻みでうごかしています。
IOT再びーーーESP32編(6)ーーー部品調達(防水 超音波センサー)-A0221AT
〇zonより,
超音波距離センサー、UART 制御距離検出器 3 ~ 450cm 低電力設計距離センサー、
IP67 防水設計 DC 3.3V ~ 5V ロボット用超音波距離検出器
を購入しました。たまたま,データシートをみつけ,GitHubにもサンプルのスケッチがのっていたので大丈夫
だろうと思っての購入でした。
取り合えず,arduino UNO で動かしてから,esp32に移植しようかと思いましたが,初期段階で,はまり
ました。何回やっても,シリアルポートが二つ開けないのです。結局勘違いでした。
Srial.available()
の関数ですが,ポートが有効かどうかの判断の関数かと思いましたが,書き込みがあったかどうかの判定の
関数でした。どうりで,ポートが有効にならないはずです。
おまけに,届いた品物は,A0221AT というものですが,この型番のものは,測定を開始するのに,RX ピ
ンを一時ハイにしてやらないとだめなようで,GitHub のスケッチには,この部分が抜けていて,うごきませ
んでしたが,試しに,
ss.write(“s”);(”S”を書き込みましたが,なんでもいみたいです)
を書き込んでやると無事うごきはじめました。
ちなみに,この防水センサーには,入出力の違いで,いくつか種類があるようで,UART 出力のものもに二種
類あるようでした。多分〇zonのものは,オートではないものなのかな,と思いました。
アリエクスプレスでは,きちんと,選択できるようになってます。
下記が,arduino UNO のスケッチで,loop(){ の次に,ss.write(“s”);を加筆してます。
/**
*
* Author: Ritesh Talreja, Made in China, Warehouse: Shenzhen, Guangdong.
*
* Components: Arduino UNO, DYPA02YYUM v1.0
*
* Arduino UNO +5V --> DYPA02YYUM Pin 1 Red
* Arduino UNO GND --> DYPA02YYUM Pin 2 Black
* Arduino UNO Pin 11 --> DYPA02YYUM Pin 3 or Floating
* Arduino UNO Pin 10 --> DYPA02YYUM Pin 4
*
* Since Arduino UNO does not have 2 hardware serial ports.
* We are using 1 software serial port connected to the sensor.
* All data from software serial port is copied onto hardware serial port to view in "Arduino IDE Serial Monitor".
*/
#include <SoftwareSerial.h>
SoftwareSerial ss (10, 11); // RX, TX
byte hdr, data_h, data_l, chksum;
unsigned int distance;
void setup()
{
Serial.begin(9600);
while (!Serial);
ss.begin(9600);
}
void loop()
{
ss.write("s");
if (ss.available())
{
hdr = (byte)ss.read();
if (hdr == 255)
{
data_h = (byte)ss.read();
data_l = (byte)ss.read();
chksum = (byte)ss.read();
if (chksum == ((hdr + data_h + data_l)&0x00FF))
{
Serial.print(hdr);
Serial.print(",");
Serial.print(data_h);
Serial.print(",");
Serial.print(data_l);
Serial.print(",");
Serial.print(chksum);
Serial.print("=");
Serial.print(hdr, HEX);
Serial.print(",");
Serial.print(data_h, HEX);
Serial.print(",");
Serial.print(data_l, HEX);
Serial.print(",");
Serial.print(chksum, HEX);
Serial.print(" => ");
distance = data_h * 256 + data_l;
Serial.print(distance, HEX);
Serial.print("=");
Serial.print(distance, DEC);
Serial.println(" mm");
}
}
}
delay(100);
}
写真が動かしたときの距離の様子です。結構正確に測定できてるようです。
久しぶりに UNO 引っ張りだしてきましたが,無事うごきました。
次は,esp32への移植ですが,レベルシフターをかまさないとでめでしょうかね。
「らくらく液体肥料素プレイヤーAQUA+」の改造
過日,「らくらく液体肥料素プレイヤーAQUA+」を〇zonより購入。
早速,肥料をまくべく,調合していざ使用となりましたが,テスト段階で,水漏れがひどくて,一時断念。
初回の使用でこれでから,欠陥かなと思いました。返品もかんがえましたが,パッケージ等,処分してあり
ますので,断念。
早速,分解してみて,原因を確認。すぐに判明しました。調合ユニットとON/OFFユニットは,Oリング二つで
接合してあり,ON/OFFユニットで,OFFにすると,ON/OFFユニットが調合ユニットの流入口に栓をする形で
流量をストップしますんが,このとき,調合ユニットが押されて,Oリングが見えるようになってしまい,
ここから水漏れするようです。動かないようにすればいいのですが,接合部分をホットボンドでつけたり,
接着剤で付けたりして使用してみましたが,だめでした。
写真のように,黄色矢印二つのユニットが,赤矢印の部分で,差し込んである構造です。
あれこれ考えましたが,手元にあった太めの熱収縮チューブで覆ってみました。ビンゴでした。
うまく,接合したようで,これで,一時的には水漏れがなくなりました。もちろん,欠陥品ですので,メーカ
ーには即クレームの書き込みをしました。便利なだけに残念ですON/OFFを使うと水漏れ再開します。
===その後===
何度かメーカーとやりとりをしました。
結局,代替え品を送ってもらえるということで,
本日,代替え品がとどきました。
メーカーの対応はすこぶるいいかと思います。
結局はメーカーというより担当者でしょうか。
IOT再びーーーESP32編(5)ーーー部品調達
IOT再びーーーESP32編(4)
苦労しましたが,思った動作をさせることができました。
ESP32編(3)の諸兄の,超音波センサーで距離を測る関数を,書き換えました。
// 距離測定関数
float measureDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
float distance = (duration * 0.0343) / 2;*/
return distance;
}
この関数を
float measureDistance() {
while (Serial.available()) {
char inChar = (char)Serial.read();
inputString += inChar;
if (inChar == '\n') {
distance=inputString.toFloat();
inputString="";
return distance;
}
}
return distance;
}
のように変更して,動かしてみました。本来,センサーが受け持つ部分を,シリアルコンソールからの手動入
力に変えての動作確認です。
動画の右側のシリアルコンソールから,2→→4→→6→→8→→10 と入力を繰り返してます。入力に応じて,
iphoneのドーナツグラフが変化してくれます。
これで,第一段階の難関がクリアーです。
投稿日: 2024年7月3日 IOT再びーーーESP32編(3)ーSPIFFS不可
前掲の諸兄のスケッチ眺めてみましたが,ハンドラーの部分の記述と,html の javascript の部分がいま
いちわかりません。youtbe をあれこれ検索していましたら,別の諸兄の記事がめにとまりました。この諸兄の
スケッチなら,私用に改変できそうです。諸兄は,超音波を使ってますが,超音波だと,タンクに穴を開ける
必要がある気がしますので,超音波は使わないで当初の予定のように水位センサーを使ってやります。
ひとまず,諸兄のプログラムのオリジナルをインストールしてみます。
ところが,ところが,インストールに必要な,プラグインをIDEに取り込めません。一日,あれこれやりまし
たがやっとできました。
原因は,arduino IDE のバージョンで,使っていたV2.**ではだめで,v1.**で,やっとできました。
これが,分かるのに丸一日,インストールしていたarduino IDE 関係のフォルダーも全削除して,何回か
インストール,つかれました。
おかげで,やっと,下記の諸兄のスケッチをesp32に書き込み,テストできました。
// 必要なライブラリのインクルード
#include <WiFi.h>
#include <WebServer.h>
#include <SPIFFS.h>
// ピンの定義
#define trigPin 5 // 超音波センサのトリガーピン
#define echoPin 18 // 超音波センサのエコーピン
// WiFi接続情報
const char* ssid = "Your SSID";
const char* password = "Your Password";
// WebServerオブジェクトの初期化
WebServer server(80);
// セットアップ関数
void setup() {
Serial.begin(115200); // シリアル通信の開始
pinMode(trigPin, OUTPUT); // トリガーピンを出力として設定
pinMode(echoPin, INPUT); // エコーピンを入力として設定
// SPIFFSの初期化
if(!SPIFFS.begin(true)){
Serial.println("SPIFFSのマウントに失敗しました");
return;
}
// WiFi接続
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
Serial.print(".");
}
Serial.println("\nWiFi connected");
Serial.print("IP Address: ");
Serial.println(WiFi.localIP());
// Webサーバーのルート設定
server.on("/", HTTP_GET, []() {
server.send(200, "text/html", SPIFFS.open("/index.html", "r").readString());
});
// '/distance'で距離を返す設定
server.on("/distance", HTTP_GET, []() {
server.send(200, "text/plain", String(measureDistance()));
});
server.begin(); // サーバーの開始
}
// メインループ
void loop() {
server.handleClient(); // クライアントのリクエストを処理
}
// 距離測定関数
float measureDistance() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
long duration = pulseIn(echoPin, HIGH);
float distance = (duration * 0.0343) / 2;
return distance;
}
スケッチは簡単ですが,HP掲載用のhtmlとjavascritpがやっかいのようですが,これもあまり手を加えずに済みそうです。
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>水位計</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<script src="https://code.highcharts.com/highcharts.js"></script>
<script src="https://code.highcharts.com/highcharts-more.js"></script>
<script src="https://code.highcharts.com/modules/solid-gauge.js"></script>
<style>
body, html {
margin: 0;
padding: 0;
width: 100%;
height: 100%;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
font-family: Arial, sans-serif;
font-size: 20px;
}
#container {
width: 90%;
height: 50%;
}
.settings {
display: flex;
justify-content: center;
align-items: center;
margin-bottom: 20px;
}
.settings > div {
margin: 0 10px;
}
.alert {
display: none;
color: red;
text-align: center;
position: absolute;
width: 100%;
bottom: 10%;
}
#title {
display: flex;
justify-content: center;
align-items: center;
font-size: 50px;
}
</style>
</head>
<body>
<div id="title">Water Level monitoring</div>
<div class="settings">
<div>
<label for="minDistance">0% Distance (cm): </label>
<input type="number" id="minDistance" value="2">
</div>
<div>
<label for="maxDistance">100% Distance (cm): </label>
<input type="number" id="maxDistance" value="15">
</div>
</div>
<div id="container"></div>
<div id="alert" class="alert">Alert: The value is below 20%</div>
<script>
var minDistance = parseFloat(document.getElementById('minDistance').value);
var maxDistance = parseFloat(document.getElementById('maxDistance').value);
document.getElementById('minDistance').addEventListener('change', function() {
minDistance = parseFloat(this.value);
updateChart();
});
document.getElementById('maxDistance').addEventListener('change', function() {
maxDistance = parseFloat(this.value);
updateChart();
});
// Highchartsのゲージオプション設定
var gaugeOptions = {
chart: {
type: 'solidgauge',
},
title: null,
pane: {
startAngle: -120,
endAngle: 120,
background: {
backgroundColor: '#EEE',
innerRadius: '60%',
outerRadius: '100%',
shape: 'arc'
}
},
tooltip: {
enabled: false
},
yAxis: {
stops: [
[0.1, '#DF5353'], // 高い値で青系
[0.5, '#DDDF0D'], // 中間値で黄色
[0.9, '#55BF3B'] // 低い値で赤系
],
lineWidth: 0,
minorTickInterval: null,
tickAmount: 2,
min: 0,
max: 100,
title: null,
labels: {
y: 16
}
},
credits: {
enabled: false
},
series: [{
name: 'Distance',
data: [100], // 初期値
dataLabels: {
format: '<div style="text-align:center"><span style="font-size:30px">{y}%</span></div>'
}
}]
};
// Highchartsのゲージを作成
var chart = Highcharts.chart('container', Highcharts.merge(gaugeOptions, {
series: [{
data: [100] // シリーズにも初期値をセット
}]
}));
// ゲージの値を更新する関数
function updateGauge(value) {
// minDistanceとmaxDistanceを使用して値を計算
var newVal = ((maxDistance - value) / (maxDistance - minDistance)) * 100;
// newValが0未満の場合は0に、100を超える場合は100に制限する
newVal = Math.max(0, Math.min(newVal, 100));
newVal = Math.round(newVal); // 小数点以下を四捨五入して整数に
chart.series[0].points[0].update(newVal);
// 値が20以下の場合、アラートを表示
if (newVal <= 20) {
document.getElementById('alert').style.display = 'block';
} else {
document.getElementById('alert').style.display = 'none';
}
}
// ESP32からデータを取得してゲージを更新する
// HTML内のJavaScriptの一部
// HTML内のJavaScriptの一部
setInterval(function () {
fetch('/distance')
.then(response => response.text())
.then(distance => {
var dist = parseFloat(distance);
updateGauge(dist); // ゲージを更新する関数に距離データを渡す
})
.catch(function (error) {
console.error('Error fetching distance:', error);
});
}, 1000); // 1秒ごとに更新
</script>
</body>
</html>
この諸兄のいいところは,スケッチにhtmlの部分を含めるのではなく,htmlは別途esp32にアップロードでき
るところでしょうか。そのため,デバックのために,htmlを抜き出す必要もなく,htmlをそのままデバックで
きます。